darwin-xnu/bsd/nfs/nfs_node.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 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/kauth.h>
  67#include <sys/mount_internal.h>
  68#include <sys/vnode.h>
  69#include <sys/ubc.h>
  70#include <sys/malloc.h>
  71
  72#include <nfs/rpcv2.h>
  73#include <nfs/nfsproto.h>
  74#include <nfs/nfs.h>
  75#include <nfs/nfsnode.h>
  76#include <nfs/nfsmount.h>
  77
  78LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
  79u_long nfsnodehash;
  80
  81lck_grp_t * nfs_node_hash_lck_grp;
  82lck_grp_attr_t * nfs_node_hash_lck_grp_attr;
  83lck_attr_t * nfs_node_hash_lck_attr;
  84lck_mtx_t *nfs_node_hash_mutex;
  85
  86/*
  87 * Initialize hash links for nfsnodes
  88 * and build nfsnode free list.
  89 */
  90void
  91nfs_nhinit(void)
  92{
  93        nfsnodehashtbl = hashinit(desiredvnodes, M_NFSNODE, &nfsnodehash);
  94
  95        nfs_node_hash_lck_grp_attr = lck_grp_attr_alloc_init();
  96        lck_grp_attr_setstat(nfs_node_hash_lck_grp_attr);
  97        nfs_node_hash_lck_grp = lck_grp_alloc_init("nfs_node_hash", nfs_node_hash_lck_grp_attr);
  98
  99        nfs_node_hash_lck_attr = lck_attr_alloc_init();
 100
 101        nfs_node_hash_mutex = lck_mtx_alloc_init(nfs_node_hash_lck_grp, nfs_node_hash_lck_attr);
 102}
 103
 104/*
 105 * Compute an entry in the NFS hash table structure
 106 */
 107u_long
 108nfs_hash(u_char *fhp, int fhsize)
 109{
 110        u_long fhsum;
 111        int i;
 112
 113        fhsum = 0;
 114        for (i = 0; i < fhsize; i++)
 115                fhsum += *fhp++;
 116        return (fhsum);
 117}
 118
 119/*
 120 * Look up a vnode/nfsnode by file handle.
 121 * Callers must check for mount points!!
 122 * In all cases, a pointer to a
 123 * nfsnode structure is returned.
 124 */
 125int
 126nfs_nget(
 127        mount_t mntp,
 128        vnode_t dvp,
 129        struct componentname *cnp,
 130        u_char *fhp,
 131        int fhsize,
 132        struct nfs_vattr *nvap,
 133        u_int64_t *xidp,
 134        int flags,
 135        struct nfsnode **npp)
 136{
 137        struct nfsnode *np;
 138        struct nfsnodehashhead *nhpp;
 139        vnode_t vp, nvp;
 140        int error;
 141        mount_t mp;
 142        struct vnode_fsparam vfsp;
 143        uint32_t vid;
 144
 145        /* Check for unmount in progress */
 146        if (!mntp || (mntp->mnt_kern_flag & MNTK_UNMOUNT)) {
 147                *npp = 0;
 148                return (!mntp ? ENXIO : EPERM);
 149        }
 150
 151        nhpp = NFSNOHASH(nfs_hash(fhp, fhsize));
 152loop:
 153        lck_mtx_lock(nfs_node_hash_mutex);
 154        for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
 155                mp = (np->n_flag & NINIT) ? np->n_mount : vnode_mount(NFSTOV(np));
 156                if (mntp != mp || np->n_fhsize != fhsize ||
 157                    bcmp(fhp, np->n_fhp, fhsize))
 158                        continue;
 159                /* if the node is still being initialized, sleep on it */
 160                if (np->n_flag & NINIT) {
 161                        np->n_flag |= NWINIT;
 162                        msleep(np, nfs_node_hash_mutex, PDROP | PINOD, "nfs_nget", 0);
 163                        goto loop;
 164                }
 165                vp = NFSTOV(np);
 166                vid = vnode_vid(vp);
 167                lck_mtx_unlock(nfs_node_hash_mutex);
 168                if ((error = vnode_getwithvid(vp, vid))) {
 169                        /*
 170                         * If vnode is being reclaimed or has already
 171                         * changed identity, no need to wait.
 172                         */
 173                        return (error);
 174                } 
 175                /* update attributes */
 176                error = nfs_loadattrcache(np, nvap, xidp, 0);
 177                if (error) {
 178                        vnode_put(vp);
 179                } else {
 180                        if (dvp && cnp && (flags & NG_MAKEENTRY))
 181                                cache_enter(dvp, vp, cnp);
 182                        *npp = np;
 183                }
 184                return(error);
 185        }
 186
 187        /*
 188         * allocate and initialize nfsnode and stick it in the hash
 189         * before calling getnewvnode().  Anyone finding it in the
 190         * hash before initialization is complete will wait for it.
 191         */
 192        MALLOC_ZONE(np, struct nfsnode *, sizeof *np, M_NFSNODE, M_WAITOK);
 193        if (!np) {
 194                lck_mtx_unlock(nfs_node_hash_mutex);
 195                *npp = 0;
 196                return (ENOMEM);
 197        }
 198        bzero((caddr_t)np, sizeof *np);
 199        np->n_flag |= NINIT;
 200        np->n_mount = mntp;
 201
 202        /* setup node's file handle */
 203        if (fhsize > NFS_SMALLFH) {
 204                MALLOC_ZONE(np->n_fhp, u_char *,
 205                                fhsize, M_NFSBIGFH, M_WAITOK);
 206                if (!np->n_fhp) {
 207                        lck_mtx_unlock(nfs_node_hash_mutex);
 208                        FREE_ZONE(np, sizeof *np, M_NFSNODE);
 209                        *npp = 0;
 210                        return (ENOMEM);
 211                }
 212        } else {
 213                np->n_fhp = &np->n_fh[0];
 214        }
 215        bcopy(fhp, np->n_fhp, fhsize);
 216        np->n_fhsize = fhsize;
 217
 218        /* Insert the nfsnode in the hash queue for its new file handle */
 219        np->n_flag |= NHASHED;
 220        LIST_INSERT_HEAD(nhpp, np, n_hash);
 221
 222        /* release lock on hash table */
 223        lck_mtx_unlock(nfs_node_hash_mutex);
 224
 225        /* do initial loading of attributes */
 226        error = nfs_loadattrcache(np, nvap, xidp, 1);
 227        if (error) {
 228                lck_mtx_lock(nfs_node_hash_mutex);
 229                LIST_REMOVE(np, n_hash);
 230                np->n_flag &= ~(NHASHED|NINIT);
 231                if (np->n_flag & NWINIT) {
 232                        np->n_flag &= ~NWINIT;
 233                        wakeup((caddr_t)np);
 234                }
 235                lck_mtx_unlock(nfs_node_hash_mutex);
 236                if (np->n_fhsize > NFS_SMALLFH)
 237                        FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
 238                FREE_ZONE(np, sizeof *np, M_NFSNODE);
 239                *npp = 0;
 240                return (error);
 241        }
 242        np->n_mtime = nvap->nva_mtime;
 243        if (nvap->nva_type == VDIR)
 244                np->n_ncmtime = nvap->nva_mtime;
 245        NMODEINVALIDATE(np);
 246
 247        /* now, attempt to get a new vnode */
 248        vfsp.vnfs_mp = mntp;
 249        vfsp.vnfs_vtype = nvap->nva_type;
 250        vfsp.vnfs_str = "nfs";
 251        vfsp.vnfs_dvp = dvp;
 252        vfsp.vnfs_fsnode = np;
 253        if (nvap->nva_type == VFIFO)
 254                vfsp.vnfs_vops = fifo_nfsv2nodeop_p;
 255        else if (nvap->nva_type == VBLK || nvap->nva_type == VCHR)
 256                vfsp.vnfs_vops = spec_nfsv2nodeop_p;
 257        else
 258                vfsp.vnfs_vops = nfsv2_vnodeop_p;
 259        vfsp.vnfs_markroot = (flags & NG_MARKROOT) ? 1 : 0;
 260        vfsp.vnfs_marksystem = 0;
 261        vfsp.vnfs_rdev = 0;
 262        vfsp.vnfs_filesize = nvap->nva_size;
 263        vfsp.vnfs_cnp = cnp;
 264        if (dvp && cnp && (flags & NG_MAKEENTRY))
 265                vfsp.vnfs_flags = 0;
 266        else
 267                vfsp.vnfs_flags = VNFS_NOCACHE;
 268        error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &nvp);
 269        if (error) {
 270                lck_mtx_lock(nfs_node_hash_mutex);
 271                LIST_REMOVE(np, n_hash);
 272                np->n_flag &= ~(NHASHED|NINIT);
 273                if (np->n_flag & NWINIT) {
 274                        np->n_flag &= ~NWINIT;
 275                        wakeup((caddr_t)np);
 276                }
 277                lck_mtx_unlock(nfs_node_hash_mutex);
 278                if (np->n_fhsize > NFS_SMALLFH)
 279                        FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
 280                FREE_ZONE(np, sizeof *np, M_NFSNODE);
 281                *npp = 0;
 282                return (error);
 283        }
 284        vp = nvp;
 285        np->n_vnode = vp;
 286        vnode_addfsref(vp);
 287        vnode_settag(vp, VT_NFS); // XXX shouldn't this be a vnode_create() parameter?
 288        *npp = np;
 289        /* node is now initialized */
 290
 291        /* check if anyone's waiting on this node */
 292        lck_mtx_lock(nfs_node_hash_mutex);
 293        np->n_flag &= ~NINIT;
 294        if (np->n_flag & NWINIT) {
 295                np->n_flag &= ~NWINIT;
 296                wakeup((caddr_t)np);
 297        }
 298        lck_mtx_unlock(nfs_node_hash_mutex);
 299
 300        return (error);
 301}
 302
 303
 304int
 305nfs_inactive(ap)
 306        struct vnop_inactive_args /* {
 307                struct vnodeop_desc *a_desc;
 308                vnode_t a_vp;
 309                vfs_context_t a_context;
 310        } */ *ap;
 311{
 312        register struct nfsnode *np;
 313        register struct sillyrename *sp;
 314        kauth_cred_t cred;
 315
 316        np = VTONFS(ap->a_vp);
 317        if (vnode_vtype(ap->a_vp) != VDIR) {
 318                sp = np->n_sillyrename;
 319                np->n_sillyrename = (struct sillyrename *)0;
 320        } else
 321                sp = (struct sillyrename *)0;
 322
 323        if (sp) {
 324                /*
 325                 * Remove the silly file that was rename'd earlier
 326                 */
 327#if DIAGNOSTIC
 328                kprintf("nfs_inactive removing %s, dvp=%x, a_vp=%x, ap=%x, np=%x, sp=%x\n",
 329                        &sp->s_name[0], (unsigned)sp->s_dvp, (unsigned)ap->a_vp, (unsigned)ap,
 330                        (unsigned)np, (unsigned)sp);
 331#endif
 332                nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, vfs_context_proc(ap->a_context), 1);
 333                np->n_size = 0;
 334                ubc_setsize(ap->a_vp, (off_t)0);
 335                nfs_removeit(sp);
 336                /*
 337                 * remove nfsnode from hash now so we can't accidentally find it
 338                 * again if another object gets created with the same filehandle
 339                 * before this vnode gets reclaimed
 340                 */
 341                lck_mtx_lock(nfs_node_hash_mutex);
 342                LIST_REMOVE(np, n_hash);
 343                np->n_flag &= ~NHASHED;
 344                lck_mtx_unlock(nfs_node_hash_mutex);
 345                cred = sp->s_cred;
 346                if (cred != NOCRED) {
 347                        sp->s_cred = NOCRED;
 348                        kauth_cred_rele(cred);
 349                }
 350                vnode_rele(sp->s_dvp);
 351                FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ);
 352                vnode_recycle(ap->a_vp);
 353        }
 354        /* clear all flags other than these */
 355        np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NHASHED);
 356        return (0);
 357}
 358
 359/*
 360 * Reclaim an nfsnode so that it can be used for other purposes.
 361 */
 362int
 363nfs_reclaim(ap)
 364        struct vnop_reclaim_args /* {
 365                struct vnodeop_desc *a_desc;
 366                vnode_t a_vp;
 367                vfs_context_t a_context;
 368        } */ *ap;
 369{
 370        vnode_t vp = ap->a_vp;
 371        struct nfsnode *np = VTONFS(vp);
 372        struct nfsdmap *dp, *dp2;
 373
 374        vnode_removefsref(vp);
 375
 376        if (np->n_flag & NHASHED) {
 377                lck_mtx_lock(nfs_node_hash_mutex);
 378                LIST_REMOVE(np, n_hash);
 379                np->n_flag &= ~NHASHED;
 380                lck_mtx_unlock(nfs_node_hash_mutex);
 381        }
 382
 383        /*
 384         * Free up any directory cookie structures and
 385         * large file handle structures that might be associated with
 386         * this nfs node.
 387         */
 388        if (vnode_vtype(vp) == VDIR) {
 389                dp = np->n_cookies.lh_first;
 390                while (dp) {
 391                        dp2 = dp;
 392                        dp = dp->ndm_list.le_next;
 393                        FREE_ZONE((caddr_t)dp2,
 394                                        sizeof (struct nfsdmap), M_NFSDIROFF);
 395                }
 396        }
 397        if (np->n_fhsize > NFS_SMALLFH) {
 398                FREE_ZONE(np->n_fhp, np->n_fhsize, M_NFSBIGFH);
 399        }
 400        vnode_clearfsnode(vp);
 401
 402        FREE_ZONE(np, sizeof(struct nfsnode), M_NFSNODE);
 403        return (0);
 404}
 405
 406
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.