coda_vnops.c revision 167497
1193326Sed/*- 2193326Sed * Coda: an Experimental Distributed File System 3193326Sed * Release 3.1 4193326Sed * 5193326Sed * Copyright (c) 1987-1998 Carnegie Mellon University 6193326Sed * All Rights Reserved 7193326Sed * 8193326Sed * Permission to use, copy, modify and distribute this software and its 9193326Sed * documentation is hereby granted, provided that both the copyright 10193326Sed * notice and this permission notice appear in all copies of the 11193326Sed * software, derivative works or modified versions, and any portions 12193326Sed * thereof, and that both notices appear in supporting documentation, and 13193326Sed * that credit is given to Carnegie Mellon University in all documents 14212904Sdim * and publicity pertaining to direct or indirect use of this code or its 15212904Sdim * derivatives. 16193326Sed * 17193326Sed * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, 18198092Srdivacky * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS 19193326Sed * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON 20198092Srdivacky * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 21212904Sdim * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF 22219077Sdim * ANY DERIVATIVE WORK. 23193326Sed * 24198092Srdivacky * Carnegie Mellon encourages users of this software to return any 25193326Sed * improvements or extensions that they make, and to grant Carnegie 26193326Sed * Mellon the rights to redistribute these changes without encumbrance. 27198954Srdivacky * 28218893Sdim * @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ 29218893Sdim */ 30198954Srdivacky/* 31198954Srdivacky * Mach Operating System 32207619Srdivacky * Copyright (c) 1990 Carnegie-Mellon University 33207619Srdivacky * Copyright (c) 1989 Carnegie-Mellon University 34218893Sdim * All rights reserved. The CMU software License Agreement specifies 35218893Sdim * the terms and conditions for use and redistribution. 36218893Sdim */ 37218893Sdim 38218893Sdim/* 39218893Sdim * This code was written for the Coda filesystem at Carnegie Mellon 40218893Sdim * University. Contributers include David Steere, James Kistler, and 41218893Sdim * M. Satyanarayanan. 42218893Sdim */ 43218893Sdim 44218893Sdim#include <sys/cdefs.h> 45218893Sdim__FBSDID("$FreeBSD: head/sys/fs/coda/coda_vnops.c 167497 2007-03-13 01:50:27Z tegge $"); 46218893Sdim 47218893Sdim#include <sys/param.h> 48207619Srdivacky#include <sys/systm.h> 49207619Srdivacky#include <sys/acct.h> 50207619Srdivacky#include <sys/errno.h> 51198954Srdivacky#include <sys/fcntl.h> 52198954Srdivacky#include <sys/kernel.h> 53198092Srdivacky#include <sys/lock.h> 54198092Srdivacky#include <sys/malloc.h> 55198092Srdivacky#include <sys/file.h> /* Must come after sys/malloc.h */ 56198092Srdivacky#include <sys/mount.h> 57198092Srdivacky#include <sys/mutex.h> 58198092Srdivacky#include <sys/namei.h> 59198092Srdivacky#include <sys/proc.h> 60198092Srdivacky#include <sys/uio.h> 61218893Sdim#include <sys/unistd.h> 62218893Sdim 63218893Sdim#include <vm/vm.h> 64198092Srdivacky#include <vm/vm_object.h> 65218893Sdim#include <vm/vm_extern.h> 66198092Srdivacky 67198092Srdivacky#include <coda/coda.h> 68193326Sed#include <coda/cnode.h> 69193326Sed#include <coda/coda_vnops.h> 70198092Srdivacky#include <coda/coda_venus.h> 71198092Srdivacky#include <coda/coda_opstats.h> 72198092Srdivacky#include <coda/coda_subr.h> 73198092Srdivacky#include <coda/coda_namecache.h> 74198092Srdivacky#include <coda/coda_pioctl.h> 75198092Srdivacky 76198092Srdivacky/* 77198092Srdivacky * These flags select various performance enhancements. 78198092Srdivacky */ 79198092Srdivackyint coda_attr_cache = 1; /* Set to cache attributes in the kernel */ 80198092Srdivackyint coda_symlink_cache = 1; /* Set to cache symbolic link information */ 81198092Srdivackyint coda_access_cache = 1; /* Set to handle some access checks directly */ 82198092Srdivacky 83193326Sed/* structure to keep track of vfs calls */ 84193326Sed 85193326Sedstruct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE]; 86198092Srdivacky 87193326Sed#define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++) 88193326Sed#define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++) 89193326Sed#define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++) 90193326Sed#define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++) 91193326Sed 92193326Sed/* What we are delaying for in printf */ 93198092Srdivackyint coda_printf_delay = 0; /* in microseconds */ 94198092Srdivackyint coda_vnop_print_entry = 0; 95204962Srdivackystatic int coda_lockdebug = 0; 96204962Srdivacky 97223017Sdim/* 98223017Sdim * Some NetBSD details: 99223017Sdim * 100223017Sdim * coda_start is called at the end of the mount syscall. 101223017Sdim * coda_init is called at boot time. 102223017Sdim */ 103223017Sdim 104198092Srdivacky#define ENTRY if(coda_vnop_print_entry) myprintf(("Entered %s\n",__func__)) 105198092Srdivacky 106198092Srdivacky/* Definition of the vnode operation vector */ 107198092Srdivacky 108198092Srdivackystruct vop_vector coda_vnodeops = { 109198092Srdivacky .vop_default = VOP_PANIC, 110198092Srdivacky .vop_lookup = coda_lookup, /* lookup */ 111198092Srdivacky .vop_create = coda_create, /* create */ 112198092Srdivacky .vop_mknod = VOP_PANIC, /* mknod */ 113198092Srdivacky .vop_open = coda_open, /* open */ 114198092Srdivacky .vop_close = coda_close, /* close */ 115198092Srdivacky .vop_access = coda_access, /* access */ 116204962Srdivacky .vop_getattr = coda_getattr, /* getattr */ 117210299Sed .vop_setattr = coda_setattr, /* setattr */ 118198092Srdivacky .vop_read = coda_read, /* read */ 119198092Srdivacky .vop_write = coda_write, /* write */ 120198092Srdivacky .vop_ioctl = coda_ioctl, /* ioctl */ 121198092Srdivacky .vop_fsync = coda_fsync, /* fsync */ 122198092Srdivacky .vop_remove = coda_remove, /* remove */ 123198092Srdivacky .vop_link = coda_link, /* link */ 124198092Srdivacky .vop_rename = coda_rename, /* rename */ 125198092Srdivacky .vop_mkdir = coda_mkdir, /* mkdir */ 126198092Srdivacky .vop_rmdir = coda_rmdir, /* rmdir */ 127198092Srdivacky .vop_symlink = coda_symlink, /* symlink */ 128198092Srdivacky .vop_readdir = coda_readdir, /* readdir */ 129204962Srdivacky .vop_readlink = coda_readlink, /* readlink */ 130198092Srdivacky .vop_inactive = coda_inactive, /* inactive */ 131198092Srdivacky .vop_reclaim = coda_reclaim, /* reclaim */ 132198092Srdivacky ._vop_lock = coda_lock, /* lock */ 133198092Srdivacky .vop_unlock = coda_unlock, /* unlock */ 134198092Srdivacky .vop_bmap = coda_bmap, /* bmap */ 135198092Srdivacky .vop_print = VOP_PANIC, /* print */ 136193326Sed .vop_islocked = coda_islocked, /* islocked */ 137193326Sed .vop_pathconf = coda_pathconf, /* pathconf */ 138193326Sed .vop_advlock = VOP_NULL, /* advlock */ 139193326Sed .vop_lease = VOP_NULL, /* lease */ 140193326Sed .vop_poll = vop_stdpoll, 141193326Sed .vop_getpages = vop_stdgetpages, /* pager intf.*/ 142193326Sed .vop_putpages = vop_stdputpages, /* pager intf.*/ 143193326Sed .vop_getwritemount = vop_stdgetwritemount, 144193326Sed 145193326Sed#if 0 146219077Sdim missing 147219077Sdim .vop_cachedlookup = ufs_lookup, 148219077Sdim .vop_whiteout = ufs_whiteout, 149193326Sed#endif 150193326Sed 151198092Srdivacky}; 152193326Sed 153193326Sed/* A generic do-nothing. For lease_check, advlock */ 154193326Sedint 155193326Sedcoda_vop_nop(void *anon) { 156193326Sed struct vnodeop_desc **desc = (struct vnodeop_desc **)anon; 157193326Sed 158193326Sed if (codadebug) { 159193326Sed myprintf(("Vnode operation %s called, but unsupported\n", 160193326Sed (*desc)->vdesc_name)); 161193326Sed } 162193326Sed return (0); 163193326Sed} 164193326Sed 165193326Sedint 166193326Sedcoda_vnodeopstats_init(void) 167193326Sed{ 168198092Srdivacky register int i; 169193326Sed 170193326Sed for(i=0;i<CODA_VNODEOPS_SIZE;i++) { 171193326Sed coda_vnodeopstats[i].opcode = i; 172193326Sed coda_vnodeopstats[i].entries = 0; 173193326Sed coda_vnodeopstats[i].sat_intrn = 0; 174193326Sed coda_vnodeopstats[i].unsat_intrn = 0; 175193326Sed coda_vnodeopstats[i].gen_intrn = 0; 176193326Sed } 177193326Sed return 0; 178193326Sed} 179193326Sed 180198092Srdivacky/* 181193326Sed * coda_open calls Venus to return the device, inode pair of the cache 182193326Sed * file holding the data. Using iget, coda_open finds the vnode of the 183193326Sed * cache file, and then opens it. 184193326Sed */ 185193326Sedint 186193326Sedcoda_open(struct vop_open_args *ap) 187193326Sed{ 188193326Sed /* 189193326Sed * NetBSD can pass the O_EXCL flag in mode, even though the check 190193326Sed * has already happened. Venus defensively assumes that if open 191193326Sed * is passed the EXCL, it must be a bug. We strip the flag here. 192193326Sed */ 193193326Sed/* true args */ 194198092Srdivacky register struct vnode **vpp = &(ap->a_vp); 195198092Srdivacky struct cnode *cp = VTOC(*vpp); 196198092Srdivacky int flag = ap->a_mode & (~O_EXCL); 197193326Sed struct ucred *cred = ap->a_cred; 198218893Sdim struct thread *td = ap->a_td; 199193326Sed/* locals */ 200193326Sed int error; 201193326Sed struct vnode *vp; 202193326Sed struct cdev *dev; 203193326Sed ino_t inode; 204193326Sed 205193326Sed MARK_ENTRY(CODA_OPEN_STATS); 206193326Sed 207193326Sed /* Check for open of control file. */ 208193326Sed if (IS_CTL_VP(*vpp)) { 209193326Sed /* XXX */ 210207619Srdivacky /* if (WRITEABLE(flag)) */ 211207619Srdivacky if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) { 212207619Srdivacky MARK_INT_FAIL(CODA_OPEN_STATS); 213198092Srdivacky return(EACCES); 214193326Sed } 215203955Srdivacky MARK_INT_SAT(CODA_OPEN_STATS); 216203955Srdivacky return(0); 217203955Srdivacky } 218203955Srdivacky 219193326Sed error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, td->td_proc, &dev, &inode); 220193326Sed if (error) 221198092Srdivacky return (error); 222204962Srdivacky if (!error) { 223193326Sed CODADEBUG( CODA_OPEN,myprintf(("open: dev %#lx inode %lu result %d\n", 224193326Sed (u_long)dev2udev(dev), (u_long)inode, 225193326Sed error)); ) 226207619Srdivacky } 227207619Srdivacky 228207619Srdivacky /* Translate the <device, inode> pair for the cache file into 229207619Srdivacky an inode pointer. */ 230219077Sdim error = coda_grab_vnode(dev, inode, &vp); 231207619Srdivacky if (error) 232207619Srdivacky return (error); 233193326Sed 234193326Sed /* We get the vnode back locked. Needs unlocked */ 235193326Sed VOP_UNLOCK(vp, 0, td); 236193326Sed /* Keep a reference until the close comes in. */ 237193326Sed vref(*vpp); 238219077Sdim 239219077Sdim /* Save the vnode pointer for the cache file. */ 240219077Sdim if (cp->c_ovp == NULL) { 241219077Sdim cp->c_ovp = vp; 242193326Sed } else { 243193326Sed if (cp->c_ovp != vp) 244198092Srdivacky panic("coda_open: cp->c_ovp != ITOV(ip)"); 245198092Srdivacky } 246198092Srdivacky cp->c_ocount++; 247198092Srdivacky 248198092Srdivacky /* Flush the attribute cached if writing the file. */ 249198092Srdivacky if (flag & FWRITE) { 250198092Srdivacky cp->c_owrite++; 251198092Srdivacky cp->c_flags &= ~C_VATTR; 252198092Srdivacky } 253198092Srdivacky 254198092Srdivacky /* Save the <device, inode> pair for the cache file to speed 255198092Srdivacky up subsequent page_read's. */ 256198092Srdivacky cp->c_device = dev; 257198092Srdivacky cp->c_inode = inode; 258198092Srdivacky 259198092Srdivacky /* Open the cache file. */ 260198092Srdivacky error = VOP_OPEN(vp, flag, cred, td, -1); 261198092Srdivacky if (error) { 262221345Sdim printf("coda_open: VOP_OPEN on container failed %d\n", error); 263198092Srdivacky return (error); 264198092Srdivacky } 265198092Srdivacky/* grab (above) does this when it calls newvnode unless it's in the cache*/ 266198092Srdivacky 267198092Srdivacky return(error); 268198092Srdivacky} 269198092Srdivacky 270198092Srdivacky/* 271198092Srdivacky * Close the cache file used for I/O and notify Venus. 272198092Srdivacky */ 273198092Srdivackyint 274198092Srdivackycoda_close(struct vop_close_args *ap) 275198092Srdivacky{ 276198092Srdivacky/* true args */ 277198092Srdivacky struct vnode *vp = ap->a_vp; 278198092Srdivacky struct cnode *cp = VTOC(vp); 279198092Srdivacky int flag = ap->a_fflag; 280198092Srdivacky struct ucred *cred = ap->a_cred; 281198092Srdivacky struct thread *td = ap->a_td; 282198092Srdivacky/* locals */ 283198092Srdivacky int error; 284198092Srdivacky 285198092Srdivacky MARK_ENTRY(CODA_CLOSE_STATS); 286198092Srdivacky 287198092Srdivacky /* Check for close of control file. */ 288199482Srdivacky if (IS_CTL_VP(vp)) { 289199482Srdivacky MARK_INT_SAT(CODA_CLOSE_STATS); 290199482Srdivacky return(0); 291198092Srdivacky } 292198092Srdivacky 293200583Srdivacky if (IS_UNMOUNTING(cp)) { 294200583Srdivacky if (cp->c_ovp) { 295200583Srdivacky#ifdef CODA_VERBOSE 296200583Srdivacky printf("coda_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n", 297198092Srdivacky vrefcnt(vp), cp->c_ovp, vp, cp); 298198092Srdivacky#endif 299198092Srdivacky#ifdef hmm 300198092Srdivacky vgone(cp->c_ovp); 301198092Srdivacky#else 302198092Srdivacky VOP_CLOSE(cp->c_ovp, flag, cred, td); /* Do errors matter here? */ 303207619Srdivacky vrele(cp->c_ovp); 304204643Srdivacky#endif 305204643Srdivacky } else { 306212904Sdim#ifdef CODA_VERBOSE 307204643Srdivacky printf("coda_close: NO container vp %p/cp %p\n", vp, cp); 308204643Srdivacky#endif 309204643Srdivacky } 310204643Srdivacky return ENODEV; 311204643Srdivacky } else { 312204643Srdivacky VOP_CLOSE(cp->c_ovp, flag, cred, td); /* Do errors matter here? */ 313204643Srdivacky vrele(cp->c_ovp); 314204643Srdivacky } 315204643Srdivacky 316204643Srdivacky if (--cp->c_ocount == 0) 317204643Srdivacky cp->c_ovp = NULL; 318204643Srdivacky 319204643Srdivacky if (flag & FWRITE) /* file was opened for write */ 320204643Srdivacky --cp->c_owrite; 321204643Srdivacky 322204643Srdivacky error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, td->td_proc); 323204643Srdivacky vrele(CTOV(cp)); 324204643Srdivacky 325204643Srdivacky CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); ) 326204643Srdivacky return(error); 327204643Srdivacky} 328204643Srdivacky 329204643Srdivackyint 330204643Srdivackycoda_read(struct vop_read_args *ap) 331204643Srdivacky{ 332204643Srdivacky 333204643Srdivacky ENTRY; 334207619Srdivacky return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ, 335207619Srdivacky ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td)); 336204643Srdivacky} 337204643Srdivacky 338204643Srdivackyint 339204643Srdivackycoda_write(struct vop_write_args *ap) 340204643Srdivacky{ 341204643Srdivacky 342204643Srdivacky ENTRY; 343204643Srdivacky return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE, 344204643Srdivacky ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td)); 345204643Srdivacky} 346204643Srdivacky 347204643Srdivackyint 348204643Srdivackycoda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag, 349204643Srdivacky struct ucred *cred, struct thread *td) 350204643Srdivacky{ 351204643Srdivacky/* upcall decl */ 352198092Srdivacky /* NOTE: container file operation!!! */ 353198092Srdivacky/* locals */ 354198092Srdivacky struct cnode *cp = VTOC(vp); 355198092Srdivacky struct vnode *cfvp = cp->c_ovp; 356198092Srdivacky struct proc *p = td->td_proc; 357198092Srdivacky struct thread *ltd = td; 358201361Srdivacky int igot_internally = 0; 359200583Srdivacky int opened_internally = 0; 360200583Srdivacky int error = 0; 361200583Srdivacky int iscore = 0; 362219077Sdim 363200583Srdivacky MARK_ENTRY(CODA_RDWR_STATS); 364219077Sdim 365219077Sdim CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %d, %lld, %d)\n", rw, 366219077Sdim (void *)uiop->uio_iov->iov_base, uiop->uio_resid, 367219077Sdim (long long)uiop->uio_offset, uiop->uio_segflg)); ) 368219077Sdim 369219077Sdim /* Check for rdwr of control object. */ 370219077Sdim if (IS_CTL_VP(vp)) { 371219077Sdim MARK_INT_FAIL(CODA_RDWR_STATS); 372219077Sdim return(EINVAL); 373219077Sdim } 374219077Sdim 375219077Sdim /* 376219077Sdim * If file is not already open this must be a page 377193326Sed * {read,write} request. Iget the cache file's inode 378198092Srdivacky * pointer if we still have its <device, inode> pair. 379198092Srdivacky * Otherwise, we must do an internal open to derive the 380198092Srdivacky * pair. 381198092Srdivacky */ 382198092Srdivacky if (cfvp == NULL) { 383198092Srdivacky /* 384198092Srdivacky * If we're dumping core, do the internal open. Otherwise 385198092Srdivacky * venus won't have the correct size of the core when 386198092Srdivacky * it's completely written. 387198092Srdivacky */ 388198092Srdivacky if (p) { 389223017Sdim PROC_LOCK(p); 390198092Srdivacky iscore = (p->p_acflag & ACORE); 391198092Srdivacky PROC_UNLOCK(p); 392199482Srdivacky } 393198092Srdivacky else 394198092Srdivacky ltd = curthread; 395199482Srdivacky 396198092Srdivacky if (cp->c_inode != 0 && !iscore) { 397198092Srdivacky igot_internally = 1; 398198092Srdivacky error = coda_grab_vnode(cp->c_device, cp->c_inode, &cfvp); 399198092Srdivacky if (error) { 400198092Srdivacky MARK_INT_FAIL(CODA_RDWR_STATS); 401198092Srdivacky return(error); 402198092Srdivacky } 403198092Srdivacky /* 404207619Srdivacky * We get the vnode back locked by curthread in both Mach and 405207619Srdivacky * NetBSD. Needs unlocked 406219077Sdim */ 407198092Srdivacky VOP_UNLOCK(cfvp, 0, ltd); 408199482Srdivacky } 409198092Srdivacky else { 410199482Srdivacky opened_internally = 1; 411198092Srdivacky MARK_INT_GEN(CODA_OPEN_STATS); 412198092Srdivacky error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), 413198092Srdivacky cred, td, -1); 414198092Srdivackyprintf("coda_rdwr: Internally Opening %p\n", vp); 415198092Srdivacky if (error) { 416198092Srdivacky printf("coda_rdwr: VOP_OPEN on container failed %d\n", error); 417198092Srdivacky return (error); 418198092Srdivacky } 419198092Srdivacky cfvp = cp->c_ovp; 420198092Srdivacky } 421198092Srdivacky } 422198092Srdivacky 423198092Srdivacky /* Have UFS handle the call. */ 424198092Srdivacky CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = %s, refcnt = %d\n", 425198092Srdivacky coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); ) 426223017Sdim if (rw == UIO_READ) { 427198092Srdivacky error = VOP_READ(cfvp, uiop, ioflag, cred); 428198092Srdivacky } else { 429198092Srdivacky error = VOP_WRITE(cfvp, uiop, ioflag, cred); 430198092Srdivacky /* ufs_write updates the vnode_pager_setsize for the vnode/object */ 431198092Srdivacky 432199482Srdivacky { struct vattr attr; 433198092Srdivacky 434198092Srdivacky if (VOP_GETATTR(cfvp, &attr, cred, td) == 0) { 435198092Srdivacky vnode_pager_setsize(vp, attr.va_size); 436198092Srdivacky } 437198092Srdivacky } 438212904Sdim } 439212904Sdim 440212904Sdim if (error) 441212904Sdim MARK_INT_FAIL(CODA_RDWR_STATS); 442212904Sdim else 443212904Sdim MARK_INT_SAT(CODA_RDWR_STATS); 444212904Sdim 445212904Sdim /* Do an internal close if necessary. */ 446212904Sdim if (opened_internally) { 447212904Sdim MARK_INT_GEN(CODA_CLOSE_STATS); 448212904Sdim (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, td); 449200583Srdivacky } 450200583Srdivacky 451219077Sdim /* Invalidate cached attributes if writing. */ 452200583Srdivacky if (rw == UIO_WRITE) 453198092Srdivacky cp->c_flags &= ~C_VATTR; 454198092Srdivacky return(error); 455198092Srdivacky} 456198092Srdivacky 457219077Sdim 458219077Sdim 459212904Sdimint 460212904Sdimcoda_ioctl(struct vop_ioctl_args *ap) 461198092Srdivacky{ 462201361Srdivacky/* true args */ 463201361Srdivacky struct vnode *vp = ap->a_vp; 464201361Srdivacky int com = ap->a_command; 465201361Srdivacky caddr_t data = ap->a_data; 466201361Srdivacky int flag = ap->a_fflag; 467207619Srdivacky struct ucred *cred = ap->a_cred; 468207619Srdivacky struct thread *td = ap->a_td; 469201361Srdivacky/* locals */ 470201361Srdivacky int error; 471201361Srdivacky struct vnode *tvp; 472201361Srdivacky struct nameidata ndp; 473201361Srdivacky struct PioctlData *iap = (struct PioctlData *)data; 474206084Srdivacky 475206084Srdivacky MARK_ENTRY(CODA_IOCTL_STATS); 476201361Srdivacky 477201361Srdivacky CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));) 478201361Srdivacky 479206084Srdivacky /* Don't check for operation on a dying object, for ctlvp it 480206084Srdivacky shouldn't matter */ 481202379Srdivacky 482202379Srdivacky /* Must be control object to succeed. */ 483202379Srdivacky if (!IS_CTL_VP(vp)) { 484202379Srdivacky MARK_INT_FAIL(CODA_IOCTL_STATS); 485210299Sed CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));) 486201361Srdivacky return (EOPNOTSUPP); 487219077Sdim } 488210299Sed /* Look up the pathname. */ 489201361Srdivacky 490201361Srdivacky /* Should we use the name cache here? It would get it from 491200583Srdivacky lookupname sooner or later anyway, right? */ 492198092Srdivacky 493198092Srdivacky NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, iap->path, td); 494198092Srdivacky error = namei(&ndp); 495198092Srdivacky tvp = ndp.ni_vp; 496198092Srdivacky 497198092Srdivacky if (error) { 498198092Srdivacky MARK_INT_FAIL(CODA_IOCTL_STATS); 499198092Srdivacky CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n", 500198092Srdivacky error));) 501198092Srdivacky return(error); 502198092Srdivacky } 503198092Srdivacky 504219077Sdim /* 505219077Sdim * Make sure this is a coda style cnode, but it may be a 506199482Srdivacky * different vfsp 507200583Srdivacky */ 508198092Srdivacky if (tvp->v_op != &coda_vnodeops) { 509198092Srdivacky vrele(tvp); 510193326Sed NDFREE(&ndp, NDF_ONLY_PNBUF); 511198092Srdivacky MARK_INT_FAIL(CODA_IOCTL_STATS); 512198092Srdivacky CODADEBUG(CODA_IOCTL, 513198092Srdivacky myprintf(("coda_ioctl error: %s not a coda object\n", 514198092Srdivacky iap->path));) 515198092Srdivacky return(EINVAL); 516198092Srdivacky } 517219077Sdim 518219077Sdim if (iap->vi.in_size > VC_MAXDATASIZE) { 519198092Srdivacky NDFREE(&ndp, 0); 520219077Sdim return(EINVAL); 521219077Sdim } 522219077Sdim error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, td->td_proc); 523219077Sdim 524219077Sdim if (error) 525219077Sdim MARK_INT_FAIL(CODA_IOCTL_STATS); 526219077Sdim else 527219077Sdim CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); ) 528219077Sdim 529219077Sdim vrele(tvp); 530198092Srdivacky NDFREE(&ndp, NDF_ONLY_PNBUF); 531198092Srdivacky return(error); 532219077Sdim} 533219077Sdim 534219077Sdim/* 535219077Sdim * To reduce the cost of a user-level venus;we cache attributes in 536219077Sdim * the kernel. Each cnode has storage allocated for an attribute. If 537219077Sdim * c_vattr is valid, return a reference to it. Otherwise, get the 538219077Sdim * attributes from venus and store them in the cnode. There is some 539219077Sdim * question if this method is a security leak. But I think that in 540219077Sdim * order to make this call, the user must have done a lookup and 541193326Sed * opened the file, and therefore should already have access. 542219077Sdim */ 543219077Sdimint 544219077Sdimcoda_getattr(struct vop_getattr_args *ap) 545219077Sdim{ 546193326Sed/* true args */ 547198092Srdivacky struct vnode *vp = ap->a_vp; 548219077Sdim struct cnode *cp = VTOC(vp); 549219077Sdim struct vattr *vap = ap->a_vap; 550219077Sdim struct ucred *cred = ap->a_cred; 551219077Sdim struct thread *td = ap->a_td; 552219077Sdim/* locals */ 553223017Sdim int error; 554219077Sdim 555219077Sdim MARK_ENTRY(CODA_GETATTR_STATS); 556223017Sdim 557219077Sdim if (IS_UNMOUNTING(cp)) 558219077Sdim return ENODEV; 559223017Sdim 560219077Sdim /* Check for getattr of control object. */ 561219077Sdim if (IS_CTL_VP(vp)) { 562223017Sdim MARK_INT_FAIL(CODA_GETATTR_STATS); 563219077Sdim return(ENOENT); 564219077Sdim } 565219077Sdim 566223017Sdim /* Check to see if the attributes have already been cached */ 567219077Sdim if (VALID_VATTR(cp)) { 568219077Sdim CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: %s\n", 569219077Sdim coda_f2s(&cp->c_fid)));}); 570223017Sdim CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR)) 571223017Sdim print_vattr(&cp->c_vattr); ); 572223017Sdim 573223017Sdim *vap = cp->c_vattr; 574223017Sdim MARK_INT_SAT(CODA_GETATTR_STATS); 575223017Sdim return(0); 576223017Sdim } 577223017Sdim 578223017Sdim error = venus_getattr(vtomi(vp), &cp->c_fid, cred, td->td_proc, vap); 579223017Sdim 580219077Sdim if (!error) { 581219077Sdim CODADEBUG(CODA_GETATTR, myprintf(("getattr miss %s: result %d\n", 582219077Sdim coda_f2s(&cp->c_fid), error)); ) 583219077Sdim 584219077Sdim CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR)) 585193326Sed print_vattr(vap); ); 586193326Sed 587200583Srdivacky { int size = vap->va_size; 588200583Srdivacky struct vnode *convp = cp->c_ovp; 589200583Srdivacky if (convp != (struct vnode *)0) { 590219077Sdim vnode_pager_setsize(convp, size); 591200583Srdivacky } 592193326Sed } 593193326Sed /* If not open for write, store attributes in cnode */ 594193326Sed if ((cp->c_owrite == 0) && (coda_attr_cache)) { 595200583Srdivacky cp->c_vattr = *vap; 596199482Srdivacky cp->c_flags |= C_VATTR; 597199482Srdivacky } 598198092Srdivacky 599198092Srdivacky } 600193326Sed return(error); 601200583Srdivacky} 602193326Sed 603198092Srdivackyint 604219077Sdimcoda_setattr(struct vop_setattr_args *ap) 605219077Sdim{ 606219077Sdim/* true args */ 607198092Srdivacky register struct vnode *vp = ap->a_vp; 608193326Sed struct cnode *cp = VTOC(vp); 609193326Sed register struct vattr *vap = ap->a_vap; 610193326Sed struct ucred *cred = ap->a_cred; 611219077Sdim struct thread *td = ap->a_td; 612193326Sed/* locals */ 613219077Sdim int error; 614193326Sed 615219077Sdim MARK_ENTRY(CODA_SETATTR_STATS); 616193326Sed 617193326Sed /* Check for setattr of control object. */ 618219077Sdim if (IS_CTL_VP(vp)) { 619219077Sdim MARK_INT_FAIL(CODA_SETATTR_STATS); 620219077Sdim return(ENOENT); 621219077Sdim } 622219077Sdim 623219077Sdim if (codadebug & CODADBGMSK(CODA_SETATTR)) { 624219077Sdim print_vattr(vap); 625219077Sdim } 626219077Sdim error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, td->td_proc); 627219077Sdim 628219077Sdim if (!error) 629219077Sdim cp->c_flags &= ~C_VATTR; 630219077Sdim 631219077Sdim { int size = vap->va_size; 632198092Srdivacky struct vnode *convp = cp->c_ovp; 633198092Srdivacky if (size != VNOVAL && convp != (struct vnode *)0) { 634200583Srdivacky vnode_pager_setsize(convp, size); 635200583Srdivacky } 636200583Srdivacky } 637200583Srdivacky CODADEBUG(CODA_SETATTR, myprintf(("setattr %d\n", error)); ) 638200583Srdivacky return(error); 639200583Srdivacky} 640207619Srdivacky 641219077Sdimint 642219077Sdimcoda_access(struct vop_access_args *ap) 643219077Sdim{ 644219077Sdim/* true args */ 645200583Srdivacky struct vnode *vp = ap->a_vp; 646219077Sdim struct cnode *cp = VTOC(vp); 647219077Sdim int mode = ap->a_mode; 648219077Sdim struct ucred *cred = ap->a_cred; 649219077Sdim struct thread *td = ap->a_td; 650219077Sdim/* locals */ 651219077Sdim int error; 652219077Sdim 653200583Srdivacky MARK_ENTRY(CODA_ACCESS_STATS); 654200583Srdivacky 655219077Sdim /* Check for access of control object. Only read access is 656221345Sdim allowed on it. */ 657221345Sdim if (IS_CTL_VP(vp)) { 658221345Sdim /* bogus hack - all will be marked as successes */ 659221345Sdim MARK_INT_SAT(CODA_ACCESS_STATS); 660221345Sdim return(((mode & VREAD) && !(mode & (VWRITE | VEXEC))) 661221345Sdim ? 0 : EACCES); 662221345Sdim } 663219077Sdim 664221345Sdim /* 665219077Sdim * if the file is a directory, and we are checking exec (eg lookup) 666219077Sdim * access, and the file is in the namecache, then the user must have 667219077Sdim * lookup access to it. 668221345Sdim */ 669221345Sdim if (coda_access_cache) { 670221345Sdim if ((vp->v_type == VDIR) && (mode & VEXEC)) { 671221345Sdim if (coda_nc_lookup(cp, ".", 1, cred)) { 672221345Sdim MARK_INT_SAT(CODA_ACCESS_STATS); 673221345Sdim return(0); /* it was in the cache */ 674221345Sdim } 675221345Sdim } 676221345Sdim } 677221345Sdim 678221345Sdim error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, td->td_proc); 679221345Sdim 680221345Sdim return(error); 681221345Sdim} 682221345Sdim 683221345Sdimint 684221345Sdimcoda_readlink(struct vop_readlink_args *ap) 685221345Sdim{ 686221345Sdim/* true args */ 687221345Sdim struct vnode *vp = ap->a_vp; 688221345Sdim struct cnode *cp = VTOC(vp); 689221345Sdim struct uio *uiop = ap->a_uio; 690221345Sdim struct ucred *cred = ap->a_cred; 691221345Sdim struct thread *td = ap->a_uio->uio_td; 692221345Sdim/* locals */ 693221345Sdim int error; 694221345Sdim char *str; 695221345Sdim int len; 696221345Sdim 697221345Sdim MARK_ENTRY(CODA_READLINK_STATS); 698221345Sdim 699221345Sdim /* Check for readlink of control object. */ 700221345Sdim if (IS_CTL_VP(vp)) { 701221345Sdim MARK_INT_FAIL(CODA_READLINK_STATS); 702221345Sdim return(ENOENT); 703221345Sdim } 704221345Sdim 705221345Sdim if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */ 706221345Sdim uiop->uio_rw = UIO_READ; 707221345Sdim error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop); 708221345Sdim if (error) 709221345Sdim MARK_INT_FAIL(CODA_READLINK_STATS); 710221345Sdim else 711221345Sdim MARK_INT_SAT(CODA_READLINK_STATS); 712221345Sdim return(error); 713221345Sdim } 714221345Sdim 715221345Sdim error = venus_readlink(vtomi(vp), &cp->c_fid, cred, 716219077Sdim td != NULL ? td->td_proc : NULL, &str, &len); 717219077Sdim 718219077Sdim if (!error) { 719223017Sdim uiop->uio_rw = UIO_READ; 720223017Sdim error = uiomove(str, len, uiop); 721223017Sdim 722223017Sdim if (coda_symlink_cache) { 723223017Sdim cp->c_symlink = str; 724223017Sdim cp->c_symlen = len; 725223017Sdim cp->c_flags |= C_SYMLINK; 726221345Sdim } else 727221345Sdim CODA_FREE(str, len); 728221345Sdim } 729221345Sdim 730221345Sdim CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));) 731221345Sdim return(error); 732221345Sdim} 733221345Sdim 734221345Sdimint 735221345Sdimcoda_fsync(struct vop_fsync_args *ap) 736221345Sdim{ 737221345Sdim/* true args */ 738221345Sdim struct vnode *vp = ap->a_vp; 739221345Sdim struct cnode *cp = VTOC(vp); 740221345Sdim struct thread *td = ap->a_td; 741221345Sdim/* locals */ 742219077Sdim struct vnode *convp = cp->c_ovp; 743193326Sed int error; 744193326Sed 745219077Sdim MARK_ENTRY(CODA_FSYNC_STATS); 746219077Sdim 747219077Sdim /* Check for fsync on an unmounting object */ 748219077Sdim /* The NetBSD kernel, in it's infinite wisdom, can try to fsync 749219077Sdim * after an unmount has been initiated. This is a Bad Thing, 750219077Sdim * which we have to avoid. Not a legitimate failure for stats. 751219077Sdim */ 752219077Sdim if (IS_UNMOUNTING(cp)) { 753219077Sdim return(ENODEV); 754219077Sdim } 755219077Sdim 756219077Sdim /* Check for fsync of control object. */ 757219077Sdim if (IS_CTL_VP(vp)) { 758219077Sdim MARK_INT_SAT(CODA_FSYNC_STATS); 759219077Sdim return(0); 760219077Sdim } 761219077Sdim 762219077Sdim if (convp) 763219077Sdim VOP_FSYNC(convp, MNT_WAIT, td); 764219077Sdim 765219077Sdim /* 766219077Sdim * We see fsyncs with usecount == 1 then usecount == 0. 767219077Sdim * For now we ignore them. 768219077Sdim */ 769219077Sdim /* 770219077Sdim VI_LOCK(vp); 771219077Sdim if (!vp->v_usecount) { 772219077Sdim printf("coda_fsync on vnode %p with %d usecount. c_flags = %x (%x)\n", 773219077Sdim vp, vp->v_usecount, cp->c_flags, cp->c_flags&C_PURGING); 774219077Sdim } 775219077Sdim VI_UNLOCK(vp); 776219077Sdim */ 777219077Sdim 778219077Sdim /* 779219077Sdim * We can expect fsync on any vnode at all if venus is pruging it. 780200583Srdivacky * Venus can't very well answer the fsync request, now can it? 781200583Srdivacky * Hopefully, it won't have to, because hopefully, venus preserves 782200583Srdivacky * the (possibly untrue) invariant that it never purges an open 783200583Srdivacky * vnode. Hopefully. 784200583Srdivacky */ 785200583Srdivacky if (cp->c_flags & C_PURGING) { 786200583Srdivacky return(0); 787200583Srdivacky } 788200583Srdivacky 789200583Srdivacky /* needs research */ 790200583Srdivacky return 0; 791200583Srdivacky error = venus_fsync(vtomi(vp), &cp->c_fid, td->td_proc); 792200583Srdivacky 793200583Srdivacky CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); ); 794200583Srdivacky return(error); 795200583Srdivacky} 796200583Srdivacky 797200583Srdivackyint 798200583Srdivackycoda_inactive(struct vop_inactive_args *ap) 799200583Srdivacky{ 800200583Srdivacky /* XXX - at the moment, inactive doesn't look at cred, and doesn't 801200583Srdivacky have a proc pointer. Oops. */ 802200583Srdivacky/* true args */ 803219077Sdim struct vnode *vp = ap->a_vp; 804200583Srdivacky struct cnode *cp = VTOC(vp); 805200583Srdivacky struct ucred *cred __attribute__((unused)) = NULL; 806212904Sdim struct thread *td __attribute__((unused)) = curthread; 807200583Srdivacky/* upcall decl */ 808200583Srdivacky/* locals */ 809200583Srdivacky 810200583Srdivacky /* We don't need to send inactive to venus - DCS */ 811200583Srdivacky MARK_ENTRY(CODA_INACTIVE_STATS); 812200583Srdivacky 813200583Srdivacky if (IS_CTL_VP(vp)) { 814200583Srdivacky MARK_INT_SAT(CODA_INACTIVE_STATS); 815200583Srdivacky return 0; 816200583Srdivacky } 817200583Srdivacky 818200583Srdivacky CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n", 819193326Sed coda_f2s(&cp->c_fid), vp->v_mount));) 820193326Sed 821193326Sed /* If an array has been allocated to hold the symlink, deallocate it */ 822193326Sed if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { 823193326Sed if (cp->c_symlink == NULL) 824193326Sed panic("coda_inactive: null symlink pointer in cnode"); 825207619Srdivacky 826193326Sed CODA_FREE(cp->c_symlink, cp->c_symlen); 827201361Srdivacky cp->c_flags &= ~C_SYMLINK; 828201361Srdivacky cp->c_symlen = 0; 829201361Srdivacky } 830201361Srdivacky 831201361Srdivacky /* Remove it from the table so it can't be found. */ 832201361Srdivacky coda_unsave(cp); 833201361Srdivacky if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) { 834201361Srdivacky myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp)); 835207619Srdivacky panic("badness in coda_inactive\n"); 836201361Srdivacky } 837201361Srdivacky 838201361Srdivacky if (IS_UNMOUNTING(cp)) { 839207619Srdivacky#ifdef DEBUG 840207619Srdivacky printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vrefcnt(vp), vp, cp); 841207619Srdivacky if (cp->c_ovp != NULL) 842207619Srdivacky printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n", 843207619Srdivacky vrefcnt(vp), vp, cp); 844198092Srdivacky#endif 845193326Sed } else { 846193326Sed#ifdef OLD_DIAGNOSTIC 847193326Sed if (vrefcnt(CTOV(cp))) { 848193326Sed panic("coda_inactive: nonzero reference count"); 849193326Sed } 850193326Sed if (cp->c_ovp != NULL) { 851193326Sed panic("coda_inactive: cp->ovp != NULL"); 852193326Sed } 853193326Sed#endif 854198092Srdivacky vgone(vp); 855198092Srdivacky } 856201361Srdivacky 857201361Srdivacky MARK_INT_SAT(CODA_INACTIVE_STATS); 858201361Srdivacky return(0); 859193326Sed} 860 861/* 862 * Remote filesystem operations having to do with directory manipulation. 863 */ 864 865/* 866 * It appears that in NetBSD, lookup is supposed to return the vnode locked 867 */ 868int 869coda_lookup(struct vop_lookup_args *ap) 870{ 871/* true args */ 872 struct vnode *dvp = ap->a_dvp; 873 struct cnode *dcp = VTOC(dvp); 874 struct vnode **vpp = ap->a_vpp; 875 /* 876 * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest 877 * of the string to xlate, and that we must try to get at least 878 * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth. I 879 * could be wrong. 880 */ 881 struct componentname *cnp = ap->a_cnp; 882 struct ucred *cred = cnp->cn_cred; 883 struct thread *td = cnp->cn_thread; 884/* locals */ 885 struct cnode *cp; 886 const char *nm = cnp->cn_nameptr; 887 int len = cnp->cn_namelen; 888 CodaFid VFid; 889 int vtype; 890 int error = 0; 891 892 MARK_ENTRY(CODA_LOOKUP_STATS); 893 894 CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n", 895 nm, coda_f2s(&dcp->c_fid)));); 896 897 /* Check for lookup of control object. */ 898 if (IS_CTL_NAME(dvp, nm, len)) { 899 *vpp = coda_ctlvp; 900 vref(*vpp); 901 MARK_INT_SAT(CODA_LOOKUP_STATS); 902 goto exit; 903 } 904 905 if (len+1 > CODA_MAXNAMLEN) { 906 MARK_INT_FAIL(CODA_LOOKUP_STATS); 907 908 CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %s (%s)\n", 909 coda_f2s(&dcp->c_fid), nm));); 910 *vpp = (struct vnode *)0; 911 error = EINVAL; 912 goto exit; 913 } 914 /* First try to look the file up in the cfs name cache */ 915 /* lock the parent vnode? */ 916 cp = coda_nc_lookup(dcp, nm, len, cred); 917 if (cp) { 918 *vpp = CTOV(cp); 919 vref(*vpp); 920 CODADEBUG(CODA_LOOKUP, 921 myprintf(("lookup result %d vpp %p\n",error,*vpp));) 922 } else { 923 924 /* The name wasn't cached, so we need to contact Venus */ 925 error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc, &VFid, &vtype); 926 927 if (error) { 928 MARK_INT_FAIL(CODA_LOOKUP_STATS); 929 930 CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %s (%s)%d\n", 931 coda_f2s(&dcp->c_fid), nm, error));) 932 *vpp = (struct vnode *)0; 933 } else { 934 MARK_INT_SAT(CODA_LOOKUP_STATS); 935 CODADEBUG(CODA_LOOKUP, 936 myprintf(("lookup: %s type %o result %d\n", 937 coda_f2s(&VFid), vtype, error)); ) 938 cp = make_coda_node(&VFid, dvp->v_mount, vtype); 939 *vpp = CTOV(cp); 940 941 /* enter the new vnode in the Name Cache only if the top bit isn't set */ 942 /* And don't enter a new vnode for an invalid one! */ 943 if (!(vtype & CODA_NOCACHE)) 944 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 945 } 946 } 947 948 exit: 949 /* 950 * If we are creating, and this was the last name to be looked up, 951 * and the error was ENOENT, then there really shouldn't be an 952 * error and we can make the leaf NULL and return success. Since 953 * this is supposed to work under Mach as well as NetBSD, we're 954 * leaving this fn wrapped. We also must tell lookup/namei that 955 * we need to save the last component of the name. (Create will 956 * have to free the name buffer later...lucky us...) 957 */ 958 if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME)) 959 && (cnp->cn_flags & ISLASTCN) 960 && (error == ENOENT)) 961 { 962 error = EJUSTRETURN; 963 cnp->cn_flags |= SAVENAME; 964 *ap->a_vpp = NULL; 965 } 966 967 /* 968 * If we are removing, and we are at the last element, and we 969 * found it, then we need to keep the name around so that the 970 * removal will go ahead as planned. Unfortunately, this will 971 * probably also lock the to-be-removed vnode, which may or may 972 * not be a good idea. I'll have to look at the bits of 973 * coda_remove to make sure. We'll only save the name if we did in 974 * fact find the name, otherwise coda_remove won't have a chance 975 * to free the pathname. 976 */ 977 if ((cnp->cn_nameiop == DELETE) 978 && (cnp->cn_flags & ISLASTCN) 979 && !error) 980 { 981 cnp->cn_flags |= SAVENAME; 982 } 983 984 /* 985 * If the lookup went well, we need to (potentially?) unlock the 986 * parent, and lock the child. We are only responsible for 987 * checking to see if the parent is supposed to be unlocked before 988 * we return. We must always lock the child (provided there is 989 * one, and (the parent isn't locked or it isn't the same as the 990 * parent.) Simple, huh? We can never leave the parent locked unless 991 * we are ISLASTCN 992 */ 993 if (!error || (error == EJUSTRETURN)) { 994 if (cnp->cn_flags & ISDOTDOT) { 995 if ((error = VOP_UNLOCK(dvp, 0, td))) { 996 return error; 997 } 998 /* 999 * The parent is unlocked. As long as there is a child, 1000 * lock it without bothering to check anything else. 1001 */ 1002 if (*ap->a_vpp) { 1003 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 1004 vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE, td); 1005 return (error); 1006 } 1007 } 1008 vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE, td); 1009 } else { 1010 /* The parent is locked, and may be the same as the child */ 1011 if (*ap->a_vpp && (*ap->a_vpp != dvp)) { 1012 /* Different, go ahead and lock it. */ 1013 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 1014 return (error); 1015 } 1016 } 1017 } 1018 } else { 1019 /* If the lookup failed, we need to ensure that the leaf is NULL */ 1020 /* Don't change any locking? */ 1021 *ap->a_vpp = NULL; 1022 } 1023 return(error); 1024} 1025 1026/*ARGSUSED*/ 1027int 1028coda_create(struct vop_create_args *ap) 1029{ 1030/* true args */ 1031 struct vnode *dvp = ap->a_dvp; 1032 struct cnode *dcp = VTOC(dvp); 1033 struct vattr *va = ap->a_vap; 1034 int exclusive = 1; 1035 int mode = ap->a_vap->va_mode; 1036 struct vnode **vpp = ap->a_vpp; 1037 struct componentname *cnp = ap->a_cnp; 1038 struct ucred *cred = cnp->cn_cred; 1039 struct thread *td = cnp->cn_thread; 1040/* locals */ 1041 int error; 1042 struct cnode *cp; 1043 const char *nm = cnp->cn_nameptr; 1044 int len = cnp->cn_namelen; 1045 CodaFid VFid; 1046 struct vattr attr; 1047 1048 MARK_ENTRY(CODA_CREATE_STATS); 1049 1050 /* All creates are exclusive XXX */ 1051 /* I'm assuming the 'mode' argument is the file mode bits XXX */ 1052 1053 /* Check for create of control object. */ 1054 if (IS_CTL_NAME(dvp, nm, len)) { 1055 *vpp = (struct vnode *)0; 1056 MARK_INT_FAIL(CODA_CREATE_STATS); 1057 return(EACCES); 1058 } 1059 1060 error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, td->td_proc, &VFid, &attr); 1061 1062 if (!error) { 1063 1064 /* If this is an exclusive create, panic if the file already exists. */ 1065 /* Venus should have detected the file and reported EEXIST. */ 1066 1067 if ((exclusive == 1) && 1068 (coda_find(&VFid) != NULL)) 1069 panic("cnode existed for newly created file!"); 1070 1071 cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type); 1072 *vpp = CTOV(cp); 1073 1074 /* Update va to reflect the new attributes. */ 1075 (*va) = attr; 1076 1077 /* Update the attribute cache and mark it as valid */ 1078 if (coda_attr_cache) { 1079 VTOC(*vpp)->c_vattr = attr; 1080 VTOC(*vpp)->c_flags |= C_VATTR; 1081 } 1082 1083 /* Invalidate the parent's attr cache, the modification time has changed */ 1084 VTOC(dvp)->c_flags &= ~C_VATTR; 1085 1086 /* enter the new vnode in the Name Cache */ 1087 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 1088 1089 CODADEBUG(CODA_CREATE, 1090 myprintf(("create: %s, result %d\n", 1091 coda_f2s(&VFid), error)); ) 1092 } else { 1093 *vpp = (struct vnode *)0; 1094 CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));) 1095 } 1096 1097 if (!error) { 1098 if (cnp->cn_flags & LOCKLEAF) { 1099 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 1100 printf("coda_create: "); 1101 panic("unlocked parent but couldn't lock child"); 1102 } 1103 } 1104#ifdef OLD_DIAGNOSTIC 1105 else { 1106 printf("coda_create: LOCKLEAF not set!\n"); 1107 } 1108#endif 1109 } 1110 return(error); 1111} 1112 1113int 1114coda_remove(struct vop_remove_args *ap) 1115{ 1116/* true args */ 1117 struct vnode *dvp = ap->a_dvp; 1118 struct cnode *cp = VTOC(dvp); 1119 struct componentname *cnp = ap->a_cnp; 1120 struct ucred *cred = cnp->cn_cred; 1121 struct thread *td = cnp->cn_thread; 1122/* locals */ 1123 int error; 1124 const char *nm = cnp->cn_nameptr; 1125 int len = cnp->cn_namelen; 1126 struct cnode *tp; 1127 1128 MARK_ENTRY(CODA_REMOVE_STATS); 1129 1130 CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n", 1131 nm, coda_f2s(&cp->c_fid)));); 1132 /* Remove the file's entry from the CODA Name Cache */ 1133 /* We're being conservative here, it might be that this person 1134 * doesn't really have sufficient access to delete the file 1135 * but we feel zapping the entry won't really hurt anyone -- dcs 1136 */ 1137 /* I'm gonna go out on a limb here. If a file and a hardlink to it 1138 * exist, and one is removed, the link count on the other will be 1139 * off by 1. We could either invalidate the attrs if cached, or 1140 * fix them. I'll try to fix them. DCS 11/8/94 1141 */ 1142 tp = coda_nc_lookup(VTOC(dvp), nm, len, cred); 1143 if (tp) { 1144 if (VALID_VATTR(tp)) { /* If attrs are cached */ 1145 if (tp->c_vattr.va_nlink > 1) { /* If it's a hard link */ 1146 tp->c_vattr.va_nlink--; 1147 } 1148 } 1149 1150 coda_nc_zapfile(VTOC(dvp), nm, len); 1151 /* No need to flush it if it doesn't exist! */ 1152 } 1153 /* Invalidate the parent's attr cache, the modification time has changed */ 1154 VTOC(dvp)->c_flags &= ~C_VATTR; 1155 1156 /* Check for remove of control object. */ 1157 if (IS_CTL_NAME(dvp, nm, len)) { 1158 MARK_INT_FAIL(CODA_REMOVE_STATS); 1159 return(ENOENT); 1160 } 1161 1162 error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, td->td_proc); 1163 1164 CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); ) 1165 1166 return(error); 1167} 1168 1169int 1170coda_link(struct vop_link_args *ap) 1171{ 1172/* true args */ 1173 struct vnode *vp = ap->a_vp; 1174 struct cnode *cp = VTOC(vp); 1175 struct vnode *tdvp = ap->a_tdvp; 1176 struct cnode *tdcp = VTOC(tdvp); 1177 struct componentname *cnp = ap->a_cnp; 1178 struct ucred *cred = cnp->cn_cred; 1179 struct thread *td = cnp->cn_thread; 1180/* locals */ 1181 int error; 1182 const char *nm = cnp->cn_nameptr; 1183 int len = cnp->cn_namelen; 1184 1185 MARK_ENTRY(CODA_LINK_STATS); 1186 1187 if (codadebug & CODADBGMSK(CODA_LINK)) { 1188 myprintf(("nb_link: vp fid: %s\n", 1189 coda_f2s(&cp->c_fid))); 1190 myprintf(("nb_link: tdvp fid: %s)\n", 1191 coda_f2s(&tdcp->c_fid))); 1192 } 1193 if (codadebug & CODADBGMSK(CODA_LINK)) { 1194 myprintf(("link: vp fid: %s\n", 1195 coda_f2s(&cp->c_fid))); 1196 myprintf(("link: tdvp fid: %s\n", 1197 coda_f2s(&tdcp->c_fid))); 1198 } 1199 1200 /* Check for link to/from control object. */ 1201 if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) { 1202 MARK_INT_FAIL(CODA_LINK_STATS); 1203 return(EACCES); 1204 } 1205 1206 error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, td->td_proc); 1207 1208 /* Invalidate the parent's attr cache, the modification time has changed */ 1209 VTOC(tdvp)->c_flags &= ~C_VATTR; 1210 VTOC(vp)->c_flags &= ~C_VATTR; 1211 1212 CODADEBUG(CODA_LINK, myprintf(("in link result %d\n",error)); ) 1213 1214 return(error); 1215} 1216 1217int 1218coda_rename(struct vop_rename_args *ap) 1219{ 1220/* true args */ 1221 struct vnode *odvp = ap->a_fdvp; 1222 struct cnode *odcp = VTOC(odvp); 1223 struct componentname *fcnp = ap->a_fcnp; 1224 struct vnode *ndvp = ap->a_tdvp; 1225 struct cnode *ndcp = VTOC(ndvp); 1226 struct componentname *tcnp = ap->a_tcnp; 1227 struct ucred *cred = fcnp->cn_cred; 1228 struct thread *td = fcnp->cn_thread; 1229/* true args */ 1230 int error; 1231 const char *fnm = fcnp->cn_nameptr; 1232 int flen = fcnp->cn_namelen; 1233 const char *tnm = tcnp->cn_nameptr; 1234 int tlen = tcnp->cn_namelen; 1235 1236 MARK_ENTRY(CODA_RENAME_STATS); 1237 1238 /* Hmmm. The vnodes are already looked up. Perhaps they are locked? 1239 This could be Bad. XXX */ 1240#ifdef OLD_DIAGNOSTIC 1241 if ((fcnp->cn_cred != tcnp->cn_cred) 1242 || (fcnp->cn_thread != tcnp->cn_thread)) 1243 { 1244 panic("coda_rename: component names don't agree"); 1245 } 1246#endif 1247 1248 /* Check for rename involving control object. */ 1249 if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) { 1250 MARK_INT_FAIL(CODA_RENAME_STATS); 1251 return(EACCES); 1252 } 1253 1254 /* Problem with moving directories -- need to flush entry for .. */ 1255 if (odvp != ndvp) { 1256 struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred); 1257 if (ovcp) { 1258 struct vnode *ovp = CTOV(ovcp); 1259 if ((ovp) && 1260 (ovp->v_type == VDIR)) /* If it's a directory */ 1261 coda_nc_zapfile(VTOC(ovp),"..", 2); 1262 } 1263 } 1264 1265 /* Remove the entries for both source and target files */ 1266 coda_nc_zapfile(VTOC(odvp), fnm, flen); 1267 coda_nc_zapfile(VTOC(ndvp), tnm, tlen); 1268 1269 /* Invalidate the parent's attr cache, the modification time has changed */ 1270 VTOC(odvp)->c_flags &= ~C_VATTR; 1271 VTOC(ndvp)->c_flags &= ~C_VATTR; 1272 1273 if (flen+1 > CODA_MAXNAMLEN) { 1274 MARK_INT_FAIL(CODA_RENAME_STATS); 1275 error = EINVAL; 1276 goto exit; 1277 } 1278 1279 if (tlen+1 > CODA_MAXNAMLEN) { 1280 MARK_INT_FAIL(CODA_RENAME_STATS); 1281 error = EINVAL; 1282 goto exit; 1283 } 1284 1285 error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, td->td_proc); 1286 1287 exit: 1288 CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));) 1289 /* XXX - do we need to call cache pureg on the moved vnode? */ 1290 cache_purge(ap->a_fvp); 1291 1292 /* Release parents first, then children. */ 1293 vrele(odvp); 1294 if (ap->a_tvp) { 1295 if (ap->a_tvp == ndvp) 1296 vrele(ndvp); 1297 else 1298 vput(ndvp); 1299 vput(ap->a_tvp); 1300 } else 1301 vput(ndvp); 1302 vrele(ap->a_fvp); 1303 1304 return(error); 1305} 1306 1307int 1308coda_mkdir(struct vop_mkdir_args *ap) 1309{ 1310/* true args */ 1311 struct vnode *dvp = ap->a_dvp; 1312 struct cnode *dcp = VTOC(dvp); 1313 struct componentname *cnp = ap->a_cnp; 1314 register struct vattr *va = ap->a_vap; 1315 struct vnode **vpp = ap->a_vpp; 1316 struct ucred *cred = cnp->cn_cred; 1317 struct thread *td = cnp->cn_thread; 1318/* locals */ 1319 int error; 1320 const char *nm = cnp->cn_nameptr; 1321 int len = cnp->cn_namelen; 1322 struct cnode *cp; 1323 CodaFid VFid; 1324 struct vattr ova; 1325 1326 MARK_ENTRY(CODA_MKDIR_STATS); 1327 1328 /* Check for mkdir of target object. */ 1329 if (IS_CTL_NAME(dvp, nm, len)) { 1330 *vpp = (struct vnode *)0; 1331 MARK_INT_FAIL(CODA_MKDIR_STATS); 1332 return(EACCES); 1333 } 1334 1335 if (len+1 > CODA_MAXNAMLEN) { 1336 *vpp = (struct vnode *)0; 1337 MARK_INT_FAIL(CODA_MKDIR_STATS); 1338 return(EACCES); 1339 } 1340 1341 error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, td->td_proc, &VFid, &ova); 1342 1343 if (!error) { 1344 if (coda_find(&VFid) != NULL) 1345 panic("cnode existed for newly created directory!"); 1346 1347 1348 cp = make_coda_node(&VFid, dvp->v_mount, va->va_type); 1349 *vpp = CTOV(cp); 1350 1351 /* enter the new vnode in the Name Cache */ 1352 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 1353 1354 /* as a side effect, enter "." and ".." for the directory */ 1355 coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp)); 1356 coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp)); 1357 1358 if (coda_attr_cache) { 1359 VTOC(*vpp)->c_vattr = ova; /* update the attr cache */ 1360 VTOC(*vpp)->c_flags |= C_VATTR; /* Valid attributes in cnode */ 1361 } 1362 1363 /* Invalidate the parent's attr cache, the modification time has changed */ 1364 VTOC(dvp)->c_flags &= ~C_VATTR; 1365 1366 CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n", 1367 coda_f2s(&VFid), error)); ) 1368 } else { 1369 *vpp = (struct vnode *)0; 1370 CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));) 1371 } 1372 1373 return(error); 1374} 1375 1376int 1377coda_rmdir(struct vop_rmdir_args *ap) 1378{ 1379/* true args */ 1380 struct vnode *dvp = ap->a_dvp; 1381 struct cnode *dcp = VTOC(dvp); 1382 struct componentname *cnp = ap->a_cnp; 1383 struct ucred *cred = cnp->cn_cred; 1384 struct thread *td = cnp->cn_thread; 1385/* true args */ 1386 int error; 1387 const char *nm = cnp->cn_nameptr; 1388 int len = cnp->cn_namelen; 1389 struct cnode *cp; 1390 1391 MARK_ENTRY(CODA_RMDIR_STATS); 1392 1393 /* Check for rmdir of control object. */ 1394 if (IS_CTL_NAME(dvp, nm, len)) { 1395 MARK_INT_FAIL(CODA_RMDIR_STATS); 1396 return(ENOENT); 1397 } 1398 1399 /* We're being conservative here, it might be that this person 1400 * doesn't really have sufficient access to delete the file 1401 * but we feel zapping the entry won't really hurt anyone -- dcs 1402 */ 1403 /* 1404 * As a side effect of the rmdir, remove any entries for children of 1405 * the directory, especially "." and "..". 1406 */ 1407 cp = coda_nc_lookup(dcp, nm, len, cred); 1408 if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL); 1409 1410 /* Remove the file's entry from the CODA Name Cache */ 1411 coda_nc_zapfile(dcp, nm, len); 1412 1413 /* Invalidate the parent's attr cache, the modification time has changed */ 1414 dcp->c_flags &= ~C_VATTR; 1415 1416 error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc); 1417 1418 CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); ) 1419 1420 return(error); 1421} 1422 1423int 1424coda_symlink(struct vop_symlink_args *ap) 1425{ 1426/* true args */ 1427 struct vnode *tdvp = ap->a_dvp; 1428 struct cnode *tdcp = VTOC(tdvp); 1429 struct componentname *cnp = ap->a_cnp; 1430 struct vattr *tva = ap->a_vap; 1431 char *path = ap->a_target; 1432 struct ucred *cred = cnp->cn_cred; 1433 struct thread *td = cnp->cn_thread; 1434 struct vnode **vpp = ap->a_vpp; 1435/* locals */ 1436 int error; 1437 /* 1438 * XXX I'm assuming the following things about coda_symlink's 1439 * arguments: 1440 * t(foo) is the new name/parent/etc being created. 1441 * lname is the contents of the new symlink. 1442 */ 1443 char *nm = cnp->cn_nameptr; 1444 int len = cnp->cn_namelen; 1445 int plen = strlen(path); 1446 1447 /* 1448 * Here's the strategy for the moment: perform the symlink, then 1449 * do a lookup to grab the resulting vnode. I know this requires 1450 * two communications with Venus for a new sybolic link, but 1451 * that's the way the ball bounces. I don't yet want to change 1452 * the way the Mach symlink works. When Mach support is 1453 * deprecated, we should change symlink so that the common case 1454 * returns the resultant vnode in a vpp argument. 1455 */ 1456 1457 MARK_ENTRY(CODA_SYMLINK_STATS); 1458 1459 /* Check for symlink of control object. */ 1460 if (IS_CTL_NAME(tdvp, nm, len)) { 1461 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1462 return(EACCES); 1463 } 1464 1465 if (plen+1 > CODA_MAXPATHLEN) { 1466 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1467 return(EINVAL); 1468 } 1469 1470 if (len+1 > CODA_MAXNAMLEN) { 1471 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1472 error = EINVAL; 1473 goto exit; 1474 } 1475 1476 error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, td->td_proc); 1477 1478 /* Invalidate the parent's attr cache, the modification time has changed */ 1479 tdcp->c_flags &= ~C_VATTR; 1480 1481 if (error == 0) 1482 error = VOP_LOOKUP(tdvp, vpp, cnp); 1483 1484 exit: 1485 CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); ) 1486 return(error); 1487} 1488 1489/* 1490 * Read directory entries. 1491 */ 1492int 1493coda_readdir(struct vop_readdir_args *ap) 1494{ 1495/* true args */ 1496 struct vnode *vp = ap->a_vp; 1497 struct cnode *cp = VTOC(vp); 1498 register struct uio *uiop = ap->a_uio; 1499 struct ucred *cred = ap->a_cred; 1500 int *eofflag = ap->a_eofflag; 1501 u_long **cookies = ap->a_cookies; 1502 int *ncookies = ap->a_ncookies; 1503 struct thread *td = ap->a_uio->uio_td; 1504/* upcall decl */ 1505/* locals */ 1506 int error = 0; 1507 1508 MARK_ENTRY(CODA_READDIR_STATS); 1509 1510 CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %lld, %d)\n", 1511 (void *)uiop->uio_iov->iov_base, 1512 uiop->uio_resid, 1513 (long long)uiop->uio_offset, 1514 uiop->uio_segflg)); ) 1515 1516 /* Check for readdir of control object. */ 1517 if (IS_CTL_VP(vp)) { 1518 MARK_INT_FAIL(CODA_READDIR_STATS); 1519 return(ENOENT); 1520 } 1521 1522 { 1523 /* If directory is not already open do an "internal open" on it. */ 1524 int opened_internally = 0; 1525 if (cp->c_ovp == NULL) { 1526 opened_internally = 1; 1527 MARK_INT_GEN(CODA_OPEN_STATS); 1528 error = VOP_OPEN(vp, FREAD, cred, td, -1); 1529printf("coda_readdir: Internally Opening %p\n", vp); 1530 if (error) { 1531 printf("coda_readdir: VOP_OPEN on container failed %d\n", error); 1532 return (error); 1533 } 1534 } 1535 1536 /* Have UFS handle the call. */ 1537 CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = %s, refcnt = %d\n", coda_f2s(&cp->c_fid), vp->v_usecount)); ) 1538 error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies, 1539 cookies); 1540 1541 if (error) 1542 MARK_INT_FAIL(CODA_READDIR_STATS); 1543 else 1544 MARK_INT_SAT(CODA_READDIR_STATS); 1545 1546 /* Do an "internal close" if necessary. */ 1547 if (opened_internally) { 1548 MARK_INT_GEN(CODA_CLOSE_STATS); 1549 (void)VOP_CLOSE(vp, FREAD, cred, td); 1550 } 1551 } 1552 1553 return(error); 1554} 1555 1556/* 1557 * Convert from filesystem blocks to device blocks 1558 */ 1559int 1560coda_bmap(struct vop_bmap_args *ap) 1561{ 1562 /* XXX on the global proc */ 1563/* true args */ 1564 struct vnode *vp __attribute__((unused)) = ap->a_vp; /* file's vnode */ 1565 daddr_t bn __attribute__((unused)) = ap->a_bn; /* fs block number */ 1566 struct bufobj **bop = ap->a_bop; /* RETURN bufobj of device */ 1567 daddr_t *bnp __attribute__((unused)) = ap->a_bnp; /* RETURN device block number */ 1568 struct thread *td __attribute__((unused)) = curthread; 1569/* upcall decl */ 1570/* locals */ 1571 1572 int ret = 0; 1573 struct cnode *cp; 1574 1575 cp = VTOC(vp); 1576 if (cp->c_ovp) { 1577 return EINVAL; 1578 ret = VOP_BMAP(cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb); 1579#if 0 1580 printf("VOP_BMAP(cp->c_ovp %p, bn %p, bop %p, bnp %lld, ap->a_runp %p, ap->a_runb %p) = %d\n", 1581 cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb, ret); 1582#endif 1583 return ret; 1584 } else { 1585#if 0 1586 printf("coda_bmap: no container\n"); 1587#endif 1588 return(EOPNOTSUPP); 1589 } 1590} 1591 1592int 1593coda_reclaim(struct vop_reclaim_args *ap) 1594{ 1595/* true args */ 1596 struct vnode *vp = ap->a_vp; 1597 struct cnode *cp = VTOC(vp); 1598/* upcall decl */ 1599/* locals */ 1600 1601/* 1602 * Forced unmount/flush will let vnodes with non zero use be destroyed! 1603 */ 1604 ENTRY; 1605 1606 if (IS_UNMOUNTING(cp)) { 1607#ifdef DEBUG 1608 if (VTOC(vp)->c_ovp) { 1609 if (IS_UNMOUNTING(cp)) 1610 printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp); 1611 } 1612#endif 1613 } else { 1614#ifdef OLD_DIAGNOSTIC 1615 if (vrefcnt(vp) != 0) 1616 print("coda_reclaim: pushing active %p\n", vp); 1617 if (VTOC(vp)->c_ovp) { 1618 panic("coda_reclaim: c_ovp not void"); 1619 } 1620#endif 1621 } 1622 cache_purge(vp); 1623 coda_free(VTOC(vp)); 1624 vp->v_data = NULL; 1625 vnode_destroy_vobject(vp); 1626 return (0); 1627} 1628 1629int 1630coda_lock(struct _vop_lock_args *ap) 1631{ 1632/* true args */ 1633 struct vnode *vp = ap->a_vp; 1634 struct cnode *cp = VTOC(vp); 1635/* upcall decl */ 1636/* locals */ 1637 1638 ENTRY; 1639 1640 if ((ap->a_flags & LK_INTERLOCK) == 0) { 1641 VI_LOCK(vp); 1642 ap->a_flags |= LK_INTERLOCK; 1643 } 1644 1645 if (coda_lockdebug) { 1646 myprintf(("Attempting lock on %s\n", 1647 coda_f2s(&cp->c_fid))); 1648 } 1649 1650 return (vop_stdlock(ap)); 1651} 1652 1653int 1654coda_unlock(struct vop_unlock_args *ap) 1655{ 1656/* true args */ 1657 struct vnode *vp = ap->a_vp; 1658 struct cnode *cp = VTOC(vp); 1659/* upcall decl */ 1660/* locals */ 1661 1662 ENTRY; 1663 if (coda_lockdebug) { 1664 myprintf(("Attempting unlock on %s\n", 1665 coda_f2s(&cp->c_fid))); 1666 } 1667 1668 return (vop_stdunlock(ap)); 1669} 1670 1671int 1672coda_islocked(struct vop_islocked_args *ap) 1673{ 1674/* true args */ 1675 ENTRY; 1676 1677 return (vop_stdislocked(ap)); 1678} 1679 1680/* How one looks up a vnode given a device/inode pair: */ 1681int 1682coda_grab_vnode(struct cdev *dev, ino_t ino, struct vnode **vpp) 1683{ 1684 /* This is like VFS_VGET() or igetinode()! */ 1685 int error; 1686 struct mount *mp; 1687 1688 if (!(mp = devtomp(dev))) { 1689 myprintf(("coda_grab_vnode: devtomp(%#lx) returns NULL\n", 1690 (u_long)dev2udev(dev))); 1691 return(ENXIO); 1692 } 1693 1694 /* XXX - ensure that nonzero-return means failure */ 1695 error = VFS_VGET(mp,ino,LK_EXCLUSIVE,vpp); 1696 if (error) { 1697 myprintf(("coda_grab_vnode: iget/vget(%lx, %lu) returns %p, err %d\n", 1698 (u_long)dev2udev(dev), (u_long)ino, (void *)*vpp, error)); 1699 return(ENOENT); 1700 } 1701 return(0); 1702} 1703 1704void 1705print_vattr(struct vattr *attr) 1706{ 1707 char *typestr; 1708 1709 switch (attr->va_type) { 1710 case VNON: 1711 typestr = "VNON"; 1712 break; 1713 case VREG: 1714 typestr = "VREG"; 1715 break; 1716 case VDIR: 1717 typestr = "VDIR"; 1718 break; 1719 case VBLK: 1720 typestr = "VBLK"; 1721 break; 1722 case VCHR: 1723 typestr = "VCHR"; 1724 break; 1725 case VLNK: 1726 typestr = "VLNK"; 1727 break; 1728 case VSOCK: 1729 typestr = "VSCK"; 1730 break; 1731 case VFIFO: 1732 typestr = "VFFO"; 1733 break; 1734 case VBAD: 1735 typestr = "VBAD"; 1736 break; 1737 default: 1738 typestr = "????"; 1739 break; 1740 } 1741 1742 1743 myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n", 1744 typestr, (int)attr->va_mode, (int)attr->va_uid, 1745 (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev)); 1746 1747 myprintf((" fileid %d nlink %d size %d blocksize %d bytes %d\n", 1748 (int)attr->va_fileid, (int)attr->va_nlink, 1749 (int)attr->va_size, 1750 (int)attr->va_blocksize,(int)attr->va_bytes)); 1751 myprintf((" gen %ld flags %ld vaflags %d\n", 1752 attr->va_gen, attr->va_flags, attr->va_vaflags)); 1753 myprintf((" atime sec %d nsec %d\n", 1754 (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec)); 1755 myprintf((" mtime sec %d nsec %d\n", 1756 (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec)); 1757 myprintf((" ctime sec %d nsec %d\n", 1758 (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec)); 1759} 1760 1761/* How to print a ucred */ 1762void 1763print_cred(struct ucred *cred) 1764{ 1765 1766 int i; 1767 1768 myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid)); 1769 1770 for (i=0; i < cred->cr_ngroups; i++) 1771 myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i])); 1772 myprintf(("\n")); 1773 1774} 1775 1776/* 1777 * Return a vnode for the given fid. 1778 * If no cnode exists for this fid create one and put it 1779 * in a table hashed by coda_f2i(). If the cnode for 1780 * this fid is already in the table return it (ref count is 1781 * incremented by coda_find. The cnode will be flushed from the 1782 * table when coda_inactive calls coda_unsave. 1783 */ 1784struct cnode * 1785make_coda_node(CodaFid *fid, struct mount *vfsp, short type) 1786{ 1787 struct cnode *cp; 1788 int err; 1789 1790 if ((cp = coda_find(fid)) == NULL) { 1791 struct vnode *vp; 1792 1793 cp = coda_alloc(); 1794 cp->c_fid = *fid; 1795 1796 err = getnewvnode("coda", vfsp, &coda_vnodeops, &vp); 1797 if (err) { 1798 panic("coda: getnewvnode returned error %d\n", err); 1799 } 1800 err = insmntque1(vp, vfsp, NULL, NULL); /* XXX: Too early for mpsafe fs */ 1801 if (err != 0) 1802 panic("coda: insmntque failed: error %d", err); 1803 vp->v_data = cp; 1804 vp->v_type = type; 1805 cp->c_vnode = vp; 1806 coda_save(cp); 1807 1808 } else { 1809 vref(CTOV(cp)); 1810 } 1811 1812 return cp; 1813} 1814 1815int 1816coda_pathconf(struct vop_pathconf_args *ap) 1817{ 1818 int error; 1819 register_t *retval; 1820 1821 retval = ap->a_retval; 1822 error = 0; 1823 1824 switch (ap->a_name) { 1825 case _PC_NAME_MAX: 1826 *retval = CODA_MAXNAMLEN; 1827 break; 1828 case _PC_PATH_MAX: 1829 *retval = CODA_MAXPATHLEN; 1830 break; 1831 default: 1832 error = vop_stdpathconf(ap); 1833 break; 1834 } 1835 1836 return (error); 1837} 1838