]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_vnops.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
index b460a0411a3529c7b1fc2aa716d358a2be6447b1..4f9208b251b27fcc07b96fe53f32e067def28887 100644 (file)
@@ -65,6 +65,8 @@
  * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
  */
 
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS_CLIENT
 
 /*
  * vnode op calls for Sun NFS version 2 and 3
@@ -462,6 +464,35 @@ int     nfs_getattr_internal(nfsnode_t, struct nfs_vattr *, vfs_context_t, int);
 int     nfs_refresh_fh(nfsnode_t, vfs_context_t);
 
 
+/*
+ * Update nfsnode attributes to avoid extra getattr calls for each direntry.
+ * This function should be called only if RDIRPLUS flag is enabled.
+ */
+void
+nfs_rdirplus_update_node_attrs(nfsnode_t dnp, struct direntry *dp, fhandle_t *fhp, struct nfs_vattr *nvattrp, uint64_t *savedxidp)
+{
+       nfsnode_t np;
+       struct componentname cn;
+       int isdot = (dp->d_namlen == 1) && (dp->d_name[0] == '.');
+       int isdotdot = (dp->d_namlen == 2) && (dp->d_name[0] == '.') && (dp->d_name[1] == '.');
+
+       if (isdot || isdotdot) {
+               return;
+       }
+
+       np = NULL;
+       bzero(&cn, sizeof(cn));
+       cn.cn_nameptr = dp->d_name;
+       cn.cn_namelen = dp->d_namlen;
+       cn.cn_nameiop = LOOKUP;
+
+       nfs_nget(NFSTOMP(dnp), dnp, &cn, fhp->fh_data, fhp->fh_len, nvattrp, savedxidp, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+       if (np) {
+               nfs_node_unlock(np);
+               vnode_put(NFSTOV(np));
+       }
+}
+
 /*
  * Find the slot in the access cache for this UID.
  * If adding and no existing slot is found, reuse slots in FIFO order.
@@ -1238,7 +1269,7 @@ nfs_close(
        struct nfs_open_file *nofp,
        uint32_t accessMode,
        uint32_t denyMode,
-       vfs_context_t ctx)
+       __unused vfs_context_t ctx)
 {
 #if CONFIG_NFS4
        struct nfs_lock_owner *nlop;
@@ -1827,20 +1858,6 @@ nfsmout:
        return error;
 }
 
-static int
-nfs_parse_user_access(
-       mount_t mp,
-       enum vtype type)
-{
-       int user_access = R_OK;
-       if ((vfs_flags(mp) & MNT_RDONLY) == 0) {
-               user_access |= W_OK;
-       }
-       if (type == VDIR) {
-               user_access |= X_OK;
-       }
-       return user_access;
-}
 
 /*
  * NFS getattr call from vfs.
@@ -1878,6 +1895,8 @@ nfs3_vnop_getattr(
                                   *  } */*ap)
 {
        int error;
+       nfsnode_t np;
+       uint64_t supported_attrs;
        struct nfs_vattr nva;
        struct vnode_attr *vap = ap->a_vap;
        struct nfsmount *nmp;
@@ -1892,7 +1911,9 @@ nfs3_vnop_getattr(
        /* Return the io size no matter what, since we don't go over the wire for this */
        VATTR_RETURN(vap, va_iosize, nfs_iosize);
 
-       if ((vap->va_active & NFS3_SUPPORTED_VATTRS) == 0) {
+       supported_attrs = NFS3_SUPPORTED_VATTRS;
+
+       if ((vap->va_active & supported_attrs) == 0) {
                return 0;
        }
 
@@ -1901,6 +1922,18 @@ nfs3_vnop_getattr(
                    (uint64_t)VM_KERNEL_ADDRPERM(ap->a_vp),
                    ap->a_vp->v_name ? ap->a_vp->v_name : "empty");
        }
+
+       /*
+        * We should not go over the wire if only fileid was requested and has ever been populated.
+        */
+       if ((vap->va_active & supported_attrs) == VNODE_ATTR_va_fileid) {
+               np = VTONFS(ap->a_vp);
+               if (np->n_attrstamp) {
+                       VATTR_RETURN(vap, va_fileid, np->n_vattr.nva_fileid);
+                       return 0;
+               }
+       }
+
        error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, NGA_CACHED);
        if (error) {
                return error;
@@ -3631,6 +3664,9 @@ skipread:
 out:
        nfs_node_lock_force(np);
        np->n_wrbusy--;
+       if ((ioflag & IO_SYNC) && !np->n_wrbusy && !np->n_numoutput) {
+               np->n_flag &= ~NMODIFIED;
+       }
        nfs_node_unlock(np);
        nfs_data_unlock(np);
        FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), error);
@@ -5455,7 +5491,7 @@ nfs_vnop_readdir(
        nfsnode_t dnp = VTONFS(dvp);
        struct nfsmount *nmp;
        uio_t uio = ap->a_uio;
-       int error, nfsvers, extended, numdirent, bigcookies, ptc, done;
+       int error, nfsvers, extended, numdirent, bigcookies, ptc, done, attrcachetimeout;
        uint16_t i, iptc, rlen, nlen;
        uint64_t cookie, nextcookie, lbn = 0;
        struct nfsbuf *bp = NULL;
@@ -5463,6 +5499,7 @@ nfs_vnop_readdir(
        struct direntry *dp, *dpptc;
        struct dirent dent;
        char *cp = NULL;
+       struct timeval now;
        thread_t thd;
 
        nmp = VTONMP(dvp);
@@ -5512,6 +5549,23 @@ nfs_vnop_readdir(
                }
        }
 
+       if (dnp->n_rdirplusstamp_eof && dnp->n_rdirplusstamp_sof) {
+               attrcachetimeout = nfs_attrcachetimeout(dnp);
+               microuptime(&now);
+               if (attrcachetimeout && (now.tv_sec - dnp->n_rdirplusstamp_sof > attrcachetimeout - 1)) {
+                       dnp->n_rdirplusstamp_eof = dnp->n_rdirplusstamp_sof = 0;
+                       nfs_invaldir(dnp);
+                       nfs_node_unlock(dnp);
+                       error = nfs_vinvalbuf(dvp, 0, ctx, 1);
+                       if (!error) {
+                               error = nfs_node_lock(dnp);
+                       }
+                       if (error) {
+                               goto out;
+                       }
+               }
+       }
+
        /*
         * check for need to invalidate when (re)starting at beginning
         */
@@ -5975,7 +6029,7 @@ nfs_dir_buf_search(
                if ((cnp->cn_namelen == dp->d_namlen) && !strcmp(cnp->cn_nameptr, dp->d_name)) {
                        fhlen = dp->d_name[dp->d_namlen + 1];
                        nvattrp = NFS_DIR_BUF_NVATTR(bp, i);
-                       if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhp->fh_len == 0) ||
+                       if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhlen == 0) ||
                            (nvattrp->nva_type == VNON) || (nvattrp->nva_fileid == 0)) {
                                /* entry is not valid */
                                error = ENOENT;
@@ -6035,6 +6089,8 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
        struct nfsbuflists blist;
        daddr64_t lbn, nextlbn;
        int dotunder = (cnp->cn_namelen > 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '_');
+       int isdot = (cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.');
+       int isdotdot = (cnp->cn_namelen == 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '.');
 
        nmp = NFSTONMP(dnp);
        if (nfs_mount_gone(nmp)) {
@@ -6044,6 +6100,10 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn
                *npp = NULL;
        }
 
+       if (isdot || isdotdot) {
+               return 0;
+       }
+
        /* first check most recent buffer (and next one too) */
        lbn = dnp->n_lastdbl;
        for (i = 0; i < 2; i++) {
@@ -6280,6 +6340,10 @@ noplus:
 
                if (rdirplus) {
                        microuptime(&now);
+                       if (lastcookie == 0) {
+                               dnp->n_rdirplusstamp_sof = now.tv_sec;
+                               dnp->n_rdirplusstamp_eof = 0;
+                       }
                }
 
                /* loop through the entries packing them into the buffer */
@@ -6405,6 +6469,7 @@ nextbuffer:
                                }
                                *(time_t*)(&dp->d_name[dp->d_namlen + 1 + fhlen]) = now.tv_sec;
                                dp->d_reclen = reclen;
+                               nfs_rdirplus_update_node_attrs(dnp, dp, &fh, nvattrp, &savedxid);
                        }
                        padstart = dp->d_name + dp->d_namlen + 1 + xlen;
                        ndbhp->ndbh_count++;
@@ -6428,6 +6493,9 @@ nextbuffer:
                        ndbhp->ndbh_flags |= (NDB_FULL | NDB_EOF);
                        nfs_node_lock_force(dnp);
                        dnp->n_eofcookie = lastcookie;
+                       if (rdirplus) {
+                               dnp->n_rdirplusstamp_eof = now.tv_sec;
+                       }
                        nfs_node_unlock(dnp);
                } else {
                        more_entries = 1;
@@ -8588,3 +8656,4 @@ nfs_vnode_notify(nfsnode_t np, uint32_t events)
        vnode_notify(NFSTOV(np), events, vap);
 }
 
+#endif /* CONFIG_NFS_CLIENT */