|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1989, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * ! 27: * This code is derived from software contributed to Berkeley by ! 28: * Rick Macklem at The University of Guelph. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 ! 59: * FreeBSD-Id: nfs_node.c,v 1.22 1997/10/28 14:06:20 bde Exp $ ! 60: */ ! 61: ! 62: ! 63: #include <sys/param.h> ! 64: #include <sys/systm.h> ! 65: #include <sys/proc.h> ! 66: #include <sys/mount.h> ! 67: #include <sys/namei.h> ! 68: #include <sys/vnode.h> ! 69: #include <sys/malloc.h> ! 70: ! 71: #include <nfs/rpcv2.h> ! 72: #include <nfs/nfsproto.h> ! 73: #include <nfs/nfs.h> ! 74: #include <nfs/nfsnode.h> ! 75: #include <nfs/nfsmount.h> ! 76: ! 77: #ifdef MALLOC_DEFINE ! 78: static MALLOC_DEFINE(M_NFSNODE, "NFS node", "NFS vnode private part"); ! 79: #endif ! 80: ! 81: LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; ! 82: u_long nfsnodehash; ! 83: ! 84: #define TRUE 1 ! 85: #define FALSE 0 ! 86: ! 87: /* ! 88: * Initialize hash links for nfsnodes ! 89: * and build nfsnode free list. ! 90: */ ! 91: void ! 92: nfs_nhinit() ! 93: { ! 94: ! 95: #ifndef lint ! 96: if ((sizeof(struct nfsnode) - 1) & sizeof(struct nfsnode)) ! 97: printf("nfs_nhinit: bad size %d\n", sizeof(struct nfsnode)); ! 98: #endif /* not lint */ ! 99: nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash); ! 100: } ! 101: ! 102: /* ! 103: * Compute an entry in the NFS hash table structure ! 104: */ ! 105: u_long ! 106: nfs_hash(fhp, fhsize) ! 107: register nfsfh_t *fhp; ! 108: int fhsize; ! 109: { ! 110: register u_char *fhpp; ! 111: register u_long fhsum; ! 112: register int i; ! 113: ! 114: fhpp = &fhp->fh_bytes[0]; ! 115: fhsum = 0; ! 116: for (i = 0; i < fhsize; i++) ! 117: fhsum += *fhpp++; ! 118: return (fhsum); ! 119: } ! 120: ! 121: /* ! 122: * Look up a vnode/nfsnode by file handle. ! 123: * Callers must check for mount points!! ! 124: * In all cases, a pointer to a ! 125: * nfsnode structure is returned. ! 126: */ ! 127: int nfs_node_hash_lock; ! 128: ! 129: int ! 130: nfs_nget(mntp, fhp, fhsize, npp) ! 131: struct mount *mntp; ! 132: register nfsfh_t *fhp; ! 133: int fhsize; ! 134: struct nfsnode **npp; ! 135: { ! 136: struct proc *p = current_proc(); /* XXX */ ! 137: struct nfsnode *np; ! 138: struct nfsnodehashhead *nhpp; ! 139: register struct vnode *vp; ! 140: struct vnode *nvp; ! 141: int error; ! 142: ! 143: nhpp = NFSNOHASH(nfs_hash(fhp, fhsize)); ! 144: loop: ! 145: for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) { ! 146: if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || ! 147: bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) ! 148: continue; ! 149: vp = NFSTOV(np); ! 150: if (vget(vp, LK_EXCLUSIVE, p)) ! 151: goto loop; ! 152: *npp = np; ! 153: return(0); ! 154: } ! 155: /* ! 156: * Obtain a lock to prevent a race condition if the getnewvnode() ! 157: * or MALLOC() below happens to block. ! 158: */ ! 159: if (nfs_node_hash_lock) { ! 160: while (nfs_node_hash_lock) { ! 161: nfs_node_hash_lock = -1; ! 162: tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0); ! 163: } ! 164: goto loop; ! 165: } ! 166: nfs_node_hash_lock = 1; ! 167: ! 168: /* ! 169: * Do the MALLOC before the getnewvnode since doing so afterward ! 170: * might cause a bogus v_data pointer to get dereferenced ! 171: * elsewhere if MALLOC should block. ! 172: */ ! 173: MALLOC_ZONE(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK); ! 174: ! 175: error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); ! 176: if (error) { ! 177: if (nfs_node_hash_lock < 0) ! 178: wakeup(&nfs_node_hash_lock); ! 179: nfs_node_hash_lock = 0; ! 180: *npp = 0; ! 181: FREE_ZONE(np, sizeof *np, M_NFSNODE); ! 182: return (error); ! 183: } ! 184: vp = nvp; ! 185: bzero((caddr_t)np, sizeof *np); ! 186: vp->v_data = np; ! 187: np->n_vnode = vp; ! 188: /* ! 189: * Insert the nfsnode in the hash queue for its new file handle ! 190: */ ! 191: LIST_INSERT_HEAD(nhpp, np, n_hash); ! 192: if (fhsize > NFS_SMALLFH) { ! 193: MALLOC_ZONE(np->n_fhp, nfsfh_t *, ! 194: fhsize, M_NFSBIGFH, M_WAITOK); ! 195: } else ! 196: np->n_fhp = &np->n_fh; ! 197: bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); ! 198: np->n_fhsize = fhsize; ! 199: *npp = np; ! 200: ! 201: if (nfs_node_hash_lock < 0) ! 202: wakeup(&nfs_node_hash_lock); ! 203: nfs_node_hash_lock = 0; ! 204: ! 205: #if 0 ! 206: #if MACH_NBC ! 207: if (vp->v_type == VREG) ! 208: vm_info_init(vp); ! 209: #endif /* MACH_NBC */ ! 210: #endif 0 /* ! 211: * Lock the new nfsnode. ! 212: */ ! 213: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 214: ! 215: return (0); ! 216: } ! 217: ! 218: int ! 219: nfs_inactive(ap) ! 220: struct vop_inactive_args /* { ! 221: struct vnode *a_vp; ! 222: struct proc *a_p; ! 223: } */ *ap; ! 224: { ! 225: register struct nfsnode *np; ! 226: register struct sillyrename *sp; ! 227: struct proc *p = current_proc(); /* XXX */ ! 228: extern int prtactive; ! 229: struct ucred *cred; ! 230: ! 231: np = VTONFS(ap->a_vp); ! 232: if (prtactive && ap->a_vp->v_usecount != 0) ! 233: vprint("nfs_inactive: pushing active", ap->a_vp); ! 234: if (ap->a_vp->v_type != VDIR) { ! 235: sp = np->n_sillyrename; ! 236: np->n_sillyrename = (struct sillyrename *)0; ! 237: } else ! 238: sp = (struct sillyrename *)0; ! 239: ! 240: if (sp) { ! 241: /* ! 242: * Remove the silly file that was rename'd earlier ! 243: */ ! 244: #if DIAGNOSTIC ! 245: kprintf("nfs_inactive removing %s, dvp=%x, a_vp=%x, ap=%x, np=%x, sp=%x\n", &sp->s_name[0], (unsigned)sp->s_dvp, (unsigned)ap->a_vp, (unsigned)ap, (unsigned)np, (unsigned)sp); ! 246: #endif ! 247: /* ! 248: * We get a reference (vget) to ensure getnewvnode() ! 249: * doesn't recycle vp while we're asleep awaiting I/O. ! 250: * Note we don't need the reference unless usecount is ! 251: * already zero. In the case of a forcible unmount it ! 252: * wont be zero and doing a vget would fail because ! 253: * vclean holds VXLOCK. ! 254: */ ! 255: if (ap->a_vp->v_usecount > 0) { ! 256: VREF(ap->a_vp); ! 257: } else if (vget(ap->a_vp, 0, ap->a_p)) ! 258: panic("nfs_inactive: vget failed"); ! 259: (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1); ! 260: nfs_removeit(sp); ! 261: cred = sp->s_cred; ! 262: if (cred != NOCRED) { ! 263: sp->s_cred = NOCRED; ! 264: crfree(cred); ! 265: } ! 266: vrele(sp->s_dvp); ! 267: FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ); ! 268: vrele(ap->a_vp); ! 269: } ! 270: np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | ! 271: NQNFSNONCACHE | NQNFSWRITE); ! 272: VOP_UNLOCK(ap->a_vp, 0, ap->a_p); ! 273: return (0); ! 274: } ! 275: ! 276: /* ! 277: * Reclaim an nfsnode so that it can be used for other purposes. ! 278: */ ! 279: int ! 280: nfs_reclaim(ap) ! 281: struct vop_reclaim_args /* { ! 282: struct vnode *a_vp; ! 283: } */ *ap; ! 284: { ! 285: register struct vnode *vp = ap->a_vp; ! 286: register struct nfsnode *np = VTONFS(vp); ! 287: register struct nfsmount *nmp = VFSTONFS(vp->v_mount); ! 288: register struct nfsdmap *dp, *dp2; ! 289: extern int prtactive; ! 290: ! 291: if (prtactive && vp->v_usecount != 0) ! 292: vprint("nfs_reclaim: pushing active", vp); ! 293: ! 294: LIST_REMOVE(np, n_hash); ! 295: ! 296: /* ! 297: * For nqnfs, take it off the timer queue as required. ! 298: */ ! 299: if ((nmp->nm_flag & NFSMNT_NQNFS) && np->n_timer.cqe_next != 0) { ! 300: CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer); ! 301: } ! 302: ! 303: /* ! 304: * Free up any directory cookie structures and ! 305: * large file handle structures that might be associated with ! 306: * this nfs node. ! 307: */ ! 308: if (vp->v_type == VDIR) { ! 309: dp = np->n_cookies.lh_first; ! 310: while (dp) { ! 311: dp2 = dp; ! 312: dp = dp->ndm_list.le_next; ! 313: FREE_ZONE((caddr_t)dp2, ! 314: sizeof (struct nfsdmap), M_NFSDIROFF); ! 315: } ! 316: } ! 317: if (np->n_fhsize > NFS_SMALLFH) { ! 318: FREE_ZONE((caddr_t)np->n_fhp, np->n_fhsize, M_NFSBIGFH); ! 319: } ! 320: ! 321: cache_purge(vp); ! 322: FREE_ZONE(vp->v_data, sizeof (struct nfsnode), M_NFSNODE); ! 323: vp->v_data = (void *)0; ! 324: return (0); ! 325: } ! 326: ! 327: #if 0 ! 328: /* ! 329: * Lock an nfsnode ! 330: */ ! 331: int ! 332: nfs_lock(ap) ! 333: struct vop_lock_args /* { ! 334: struct vnode *a_vp; ! 335: } */ *ap; ! 336: { ! 337: register struct vnode *vp = ap->a_vp; ! 338: ! 339: /* ! 340: * Ugh, another place where interruptible mounts will get hung. ! 341: * If you make this sleep interruptible, then you have to fix all ! 342: * the VOP_LOCK() calls to expect interruptibility. ! 343: */ ! 344: while (vp->v_flag & VXLOCK) { ! 345: vp->v_flag |= VXWANT; ! 346: (void) tsleep((caddr_t)vp, PINOD, "nfslck", 0); ! 347: } ! 348: if (vp->v_tag == VT_NON) ! 349: return (ENOENT); ! 350: ! 351: #if 0 ! 352: /* ! 353: * Only lock regular files. If a server crashed while we were ! 354: * holding a directory lock, we could easily end up sleeping ! 355: * until the server rebooted while holding a lock on the root. ! 356: * Locks are only needed for protecting critical sections in ! 357: * VMIO at the moment. ! 358: * New vnodes will have type VNON but they should be locked ! 359: * since they may become VREG. This is checked in loadattrcache ! 360: * and unwanted locks are released there. ! 361: */ ! 362: if (vp->v_type == VREG || vp->v_type == VNON) { ! 363: while (np->n_flag & NLOCKED) { ! 364: np->n_flag |= NWANTED; ! 365: (void) tsleep((caddr_t) np, PINOD, "nfslck2", 0); ! 366: /* ! 367: * If the vnode has transmuted into a VDIR while we ! 368: * were asleep, then skip the lock. ! 369: */ ! 370: if (vp->v_type != VREG && vp->v_type != VNON) ! 371: return (0); ! 372: } ! 373: np->n_flag |= NLOCKED; ! 374: } ! 375: #endif ! 376: ! 377: return (0); ! 378: } ! 379: ! 380: /* ! 381: * Unlock an nfsnode ! 382: */ ! 383: int ! 384: nfs_unlock(ap) ! 385: struct vop_unlock_args /* { ! 386: struct vnode *a_vp; ! 387: } */ *ap; ! 388: { ! 389: #if 0 ! 390: struct vnode* vp = ap->a_vp; ! 391: struct nfsnode* np = VTONFS(vp); ! 392: ! 393: if (vp->v_type == VREG || vp->v_type == VNON) { ! 394: if (!(np->n_flag & NLOCKED)) ! 395: panic("nfs_unlock: nfsnode not locked"); ! 396: np->n_flag &= ~NLOCKED; ! 397: if (np->n_flag & NWANTED) { ! 398: np->n_flag &= ~NWANTED; ! 399: wakeup((caddr_t) np); ! 400: } ! 401: } ! 402: #endif ! 403: ! 404: return (0); ! 405: } ! 406: ! 407: /* ! 408: * Check for a locked nfsnode ! 409: */ ! 410: int ! 411: nfs_islocked(ap) ! 412: struct vop_islocked_args /* { ! 413: struct vnode *a_vp; ! 414: } */ *ap; ! 415: { ! 416: return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; ! 417: } ! 418: #endif ! 419: ! 420: /* ! 421: * Nfs abort op, called after namei() when a CREATE/DELETE isn't actually ! 422: * done. Currently nothing to do. ! 423: */ ! 424: /* ARGSUSED */ ! 425: int ! 426: nfs_abortop(ap) ! 427: struct vop_abortop_args /* { ! 428: struct vnode *a_dvp; ! 429: struct componentname *a_cnp; ! 430: } */ *ap; ! 431: { ! 432: ! 433: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) ! 434: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); ! 435: return (0); ! 436: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.