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