]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_subs.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_subs.c
index 1e341e73e278632668249f4dbb13970fe677a65a..4b9a5b14669085523abc8f9a795be313b55756b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -79,6 +79,7 @@
 #include <sys/stat.h>
 #include <sys/malloc.h>
 #include <sys/syscall.h>
+#include <sys/sysctl.h>
 #include <sys/ubc.h>
 
 #include <sys/vm.h>
 
 #include <sys/kdebug.h>
 
+SYSCTL_DECL(_vfs_generic);
+SYSCTL_NODE(_vfs_generic, OID_AUTO, nfs, CTLFLAG_RW, 0, "nfs hinge");
+
 #define FSDBG(A, B, C, D, E) \
        KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
                (int)(B), (int)(C), (int)(D), (int)(E), 0)
@@ -589,15 +593,9 @@ extern nfstype nfsv3_type[9];
 extern struct nfsnodehashhead *nfsnodehashtbl;
 extern u_long nfsnodehash;
 
-struct getfh_args;
-extern int getfh(struct proc *, struct getfh_args *, int *);
-struct nfssvc_args;
-extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
 
 LIST_HEAD(nfsnodehashhead, nfsnode);
 
-int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
-
 /*
  * Create the header for an rpc request packet
  * The hsiz is the size of the rest of the nfs request header.
@@ -628,7 +626,7 @@ nfsm_reqh(vp, procid, hsiz, bposp)
         */
        if (vp) {
                nmp = VFSTONFS(vp->v_mount);
-               if (nmp->nm_flag & NFSMNT_NQNFS) {
+               if (nmp && (nmp->nm_flag & NFSMNT_NQNFS)) {
                        nqflag = NQNFS_NEEDLEASE(vp, procid);
                        if (nqflag) {
                                nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
@@ -674,7 +672,6 @@ nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
        struct mbuf *mreq, *mb2;
        int siz, grpsiz, authsiz;
        struct timeval tv;
-       static u_long base;
 
        authsiz = nfsm_rndup(auth_len);
        MGETHDR(mb, M_WAIT, MT_DATA);
@@ -696,12 +693,16 @@ nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
 
        /*
         * derive initial xid from system time
-        * XXX time is invalid if root not yet mounted
         */
-       if (!base && (rootvp)) {
+       if (!nfs_xid) {
+               /*
+                * Note: it's OK if this code inits nfs_xid to 0 (for example,
+                * due to a broken clock) because we immediately increment it
+                * and we guarantee to never use xid 0.  So, nfs_xid should only
+                * ever be 0 the first time this function is called.
+                */
                microtime(&tv);
-               base = tv.tv_sec << 12;
-               nfs_xid = base;
+               nfs_xid = tv.tv_sec << 12;
        }
        /*
         * Skip zero xid if it should ever happen.
@@ -1182,6 +1183,7 @@ nfs_init(vfsp)
                nfs_iodwant[i] = (struct proc *)0;
                nfs_iodmount[i] = (struct nfsmount *)0;
        }
+       nfs_nbinit();                   /* Init the nfsbuf table */
        nfs_nhinit();                   /* Init the nfsnode table */
 #ifndef NFS_NOSERVER
        nfsrv_init(0);                  /* Init server data structures */
@@ -1219,13 +1221,6 @@ nfs_init(vfsp)
        lease_updatetime = nfs_lease_updatetime;
 #endif
        vfsp->vfc_refcount++; /* make us non-unloadable */
-       sysent[SYS_nfssvc].sy_narg = 2;
-       sysent[SYS_nfssvc].sy_call = nfssvc;
-#ifndef NFS_NOSERVER
-       sysent[SYS_getfh].sy_narg = 2;
-       sysent[SYS_getfh].sy_call = getfh;
-#endif
-
        return (0);
 }
 
@@ -1263,18 +1258,15 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink, xidp)
        enum vtype vtyp;
        u_short vmode;
        struct timespec mtime;
+       struct timeval now;
        struct vnode *nvp;
        int v3;
 
        FSDBG_TOP(527, vp, 0, *xidp >> 32, *xidp);
-       /*
-        * this routine is a good place to check for VBAD again. We caught
-        * most of them in nfsm_request, but postprocessing may indirectly get
-        * here, so check again.
-        */
-       if (vp->v_type == VBAD) {
-               FSDBG_BOT(527, EINVAL, 1, 0, *xidp);
-               return (EINVAL); 
+
+       if (!VFSTONFS(vp->v_mount)) {
+               FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
+               return (ENXIO); 
        }
 
        v3 = NFS_ISV3(vp);
@@ -1333,7 +1325,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink, xidp)
         * information.
         */
        np = VTONFS(vp);
-if (*xidp < np->n_xid) {
+       if (*xidp < np->n_xid) {
                /*
                 * We have already updated attributes with a response from
                 * a later request.  The attributes we have here are probably
@@ -1344,7 +1336,7 @@ if (*xidp < np->n_xid) {
                 * to indicate the attributes were dropped - only getattr
                 * cares - it needs to retry the rpc.
                 */
-               np->n_attrstamp = 0;
+               np->n_xid = 0;
                FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
                *xidp = 0;
                return (0);
@@ -1352,12 +1344,6 @@ if (*xidp < np->n_xid) {
        if (vp->v_type != vtyp) {
                vp->v_type = vtyp;
 
-               if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))
-                       if ((error = ubc_info_init(vp))) { /* VREG */
-                               FSDBG_BOT(527, error, 3, 0, *xidp);
-                               return(error);
-                       }
-
                if (vp->v_type == VFIFO) {
                        vp->v_op = fifo_nfsv2nodeop_p;
                }
@@ -1399,7 +1385,7 @@ if (*xidp < np->n_xid) {
                vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
                vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
                fxdr_hyper(&fp->fa3_size, &vap->va_size);
-               vap->va_blocksize = NFS_FABLKSIZE;
+               vap->va_blocksize = 16*1024;
                fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
                vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
                fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
@@ -1422,7 +1408,21 @@ if (*xidp < np->n_xid) {
                vap->va_filerev = 0;
        }
 
-       np->n_attrstamp = time.tv_sec;
+       microuptime(&now);
+       np->n_attrstamp = now.tv_sec;
+
+       if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp)) {
+               if (UBCINFORECLAIMED(vp) && ISSET(vp->v_flag, (VXLOCK|VORECLAIM))) {
+                       // vnode is being vclean'ed, abort
+                       FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
+                       return (ENXIO);
+               }
+               if ((error = ubc_info_init(vp))) { /* VREG */
+                       FSDBG_BOT(527, error, 3, 0, *xidp);
+                       return(error);
+               }
+       }
+
        if (vap->va_size != np->n_size) {
                FSDBG(527, vp, vap->va_size, np->n_size,
                      (vap->va_type == VREG) |
@@ -1441,9 +1441,10 @@ if (*xidp < np->n_xid) {
                        if (!UBCINFOEXISTS(vp) ||
                            dontshrink && np->n_size < ubc_getsize(vp)) {
                                vap->va_size = np->n_size = orig_size;
-                               np->n_attrstamp = 0;
-                       } else
+                               np->n_xid = 0;
+                       } else {
                                ubc_setsize(vp, (off_t)np->n_size); /* XXX */
+                       }
                } else
                        np->n_size = vap->va_size;
        }
@@ -1473,8 +1474,31 @@ nfs_getattrcache(vp, vaper)
 {
        register struct nfsnode *np = VTONFS(vp);
        register struct vattr *vap;
+       struct timeval now, nowup;
+       int32_t timeo;
 
-       if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
+       if (np->n_xid == 0) {
+               FSDBG(528, vp, 0, 0, 0);
+               nfsstats.attrcache_misses++;
+               return (ENOENT);
+       }
+
+       /* Set attribute timeout based on how recently the file has been modified. */
+       if ((np)->n_flag & NMODIFIED)
+               timeo = NFS_MINATTRTIMO;
+       else {
+               /* Note that if the client and server clocks are way out of sync, */
+               /* timeout will probably get clamped to a min or max value */
+               microtime(&now);
+               timeo = (now.tv_sec - (np)->n_mtime) / 10;
+               if (timeo < NFS_MINATTRTIMO)
+                       timeo = NFS_MINATTRTIMO;
+               else if (timeo > NFS_MAXATTRTIMO)
+                       timeo = NFS_MAXATTRTIMO;
+       }
+
+       microuptime(&nowup);
+       if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
                FSDBG(528, vp, 0, 0, 1);
                nfsstats.attrcache_misses++;
                return (ENOENT);
@@ -1542,10 +1566,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
        int error, rdonly, linklen;
        struct componentname *cnp = &ndp->ni_cnd;
        int olen = len;
+       char *tmppn;
 
        *retdirp = (struct vnode *)0;
-       MALLOC_ZONE(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
-       cnp->cn_pnlen = len + 1;
+
+       if (len  > MAXPATHLEN - 1)
+               return (ENAMETOOLONG);
+
+       MALLOC_ZONE(cnp->cn_pnbuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+       cnp->cn_pnlen = MAXPATHLEN;
 
        /*
         * Copy the name from the mbuf list to ndp->ni_pnbuf
@@ -1609,14 +1638,16 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
        *retdirp = dp;
 
 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
-/* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */
 #ifdef notyet
        if (pubflag) {
                /*
                 * Oh joy. For WebNFS, handle those pesky '%' escapes,
                 * and the 'native path' indicator.
                 */
-               MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK);
+
+               assert(olen <= MAXPATHLEN - 1);
+
+               MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
                fromcp = cnp->cn_pnbuf;
                tocp = cp;
                if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
@@ -1634,7 +1665,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                         */
                        default:
                                error = EIO;
-                               FREE(cp, M_NAMEI);
+                               FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
                                goto out;
                        }
                }
@@ -1650,15 +1681,20 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                                        continue;
                                } else {
                                        error = ENOENT;
-                                       FREE(cp, M_NAMEI);
+                                       FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
                                        goto out;
                                }
                        } else
                                *tocp++ = *fromcp++;
                }
                *tocp = '\0';
-               FREE(cnp->cn_pnbuf, M_NAMEI);
+
+               tmppn = cnp->cn_pnbuf;
+               long len = cnp->cn_pnlen; 
                cnp->cn_pnbuf = cp;
+               cnp->cn_pnlen = MAXPATHLEN;
+               FREE_ZONE(tmppn, len, M_NAMEI);
+
        }
 #endif
 
@@ -1714,7 +1750,6 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                        error = EINVAL;
                        break;
 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
-/* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */
 #ifdef notyet
                }
 
@@ -1722,8 +1757,9 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                        error = ELOOP;
                        break;
                }
+               /* XXX assert(olen <= MAXPATHLEN - 1); */
                if (ndp->ni_pathlen > 1)
-                       MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK);
+                       MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
                else
                        cp = cnp->cn_pnbuf;
                aiov.iov_base = cp;
@@ -1737,9 +1773,9 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                auio.uio_resid = MAXPATHLEN;
                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                if (error) {
-               badlink:
+badlink:
                        if (ndp->ni_pathlen > 1)
-                               FREE(cp, M_NAMEI);
+                               FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
                        break;
                }
                linklen = MAXPATHLEN - auio.uio_resid;
@@ -1752,9 +1788,12 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
                        goto badlink;
                }
                if (ndp->ni_pathlen > 1) {
-                       bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
-                       FREE(cnp->cn_pnbuf, M_NAMEI);
+                       long len = cnp->cn_pnlen;
+                       tmppn = cnp->cn_pnbuf;
                        cnp->cn_pnbuf = cp;
+                       cnp->cn_pnlen = olen + 1;
+                       bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
+                       FREE_ZONE(tmppn, len, M_NAMEI);
                } else
                        cnp->cn_pnbuf[linklen] = '\0';
                ndp->ni_pathlen += linklen;
@@ -1772,7 +1811,11 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
        }
    }
 out:
-       FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
+       tmppn = cnp->cn_pnbuf;
+       cnp->cn_pnbuf = NULL;
+       cnp->cn_flags &= ~HASBUF;
+       FREE_ZONE(tmppn, cnp->cn_pnlen, M_NAMEI);
+
        return (error);
 }
 
@@ -2162,8 +2205,8 @@ nfs_invaldir(vp)
 
 /*
  * The write verifier has changed (probably due to a server reboot), so all
- * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
- * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
+ * NB_NEEDCOMMIT blocks will have to be written again. Since they are on the
+ * dirty block list as NB_DELWRI, all this takes is clearing the NB_NEEDCOMMIT
  * flag. Once done the new write verifier can be set for the mount point.
  */
 void
@@ -2171,7 +2214,8 @@ nfs_clearcommit(mp)
        struct mount *mp;
 {
        register struct vnode *vp, *nvp;
-       register struct buf *bp, *nbp;
+       register struct nfsbuf *bp, *nbp;
+       struct nfsnode *np;
        int s;
 
        s = splbio();
@@ -2180,11 +2224,15 @@ loop:
                if (vp->v_mount != mp)  /* Paranoia */
                        goto loop;
                nvp = vp->v_mntvnodes.le_next;
-               for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
-                       nbp = bp->b_vnbufs.le_next;
-                       if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
-                               == (B_DELWRI | B_NEEDCOMMIT))
-                               bp->b_flags &= ~B_NEEDCOMMIT;
+               np = VTONFS(vp);
+               for (bp = np->n_dirtyblkhd.lh_first; bp; bp = nbp) {
+                       nbp = bp->nb_vnbufs.le_next;
+                       if ((bp->nb_flags & (NB_BUSY | NB_DELWRI | NB_NEEDCOMMIT))
+                               == (NB_DELWRI | NB_NEEDCOMMIT)) {
+                               bp->nb_flags &= ~NB_NEEDCOMMIT;
+                               np->n_needcommitcnt--;
+                               CHECK_NEEDCOMMITCNT(np);
+                       }
                }
        }
        splx(s);