Author: jhb
Date: Fri Mar 20 21:12:38 2009
New Revision: 190176
URL: http://svn.freebsd.org/changeset/base/190176

Log:
  Expand the per-node access cache to cache permissions for multiple users.
  The number of entries in the cache defaults to 8 but is easily changed in
  nfsclient/nfs.h.  When the cache is filled, the oldest cache entry is
  evicted when space is needed.
  
  I mirrored the changes to the NFSv[23] client in the NFSv4 client to fix
  compile breakage.  However, the NFSv4 client doesn't actually use the
  access cache currently.
  
  Submitted by: rmacklem

Modified:
  head/sys/nfs4client/nfs4_vnops.c
  head/sys/nfsclient/nfs.h
  head/sys/nfsclient/nfs_vnops.c
  head/sys/nfsclient/nfsnode.h

Modified: head/sys/nfs4client/nfs4_vnops.c
==============================================================================
--- head/sys/nfs4client/nfs4_vnops.c    Fri Mar 20 20:55:57 2009        
(r190175)
+++ head/sys/nfs4client/nfs4_vnops.c    Fri Mar 20 21:12:38 2009        
(r190176)
@@ -241,11 +241,11 @@ SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_c
                         | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
 static int
 nfs4_v3_access_otw(struct vnode *vp, int wmode, struct thread *td,
-    struct ucred *cred)
+    struct ucred *cred, uint32_t *retmode)
 {
        const int v3 = 1;
        u_int32_t *tl;
-       int error = 0, attrflag;
+       int error = 0, attrflag, i, lrupos;
 
        return (0);
 
@@ -264,11 +264,26 @@ nfs4_v3_access_otw(struct vnode *vp, int
        nfsm_request(vp, NFSPROC_ACCESS, td, cred);
        nfsm_postop_attr(vp, attrflag);
        if (!error) {
+               lrupos = 0;
                tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
                rmode = fxdr_unsigned(u_int32_t, *tl);
-               np->n_mode = rmode;
-               np->n_modeuid = cred->cr_uid;
-               np->n_modestamp = time_second;
+               for (i = 0; i < NFS_ACCESSCACHESIZE; i++) {
+                       if (np->n_accesscache[i].uid == cred->cr_uid) {
+                               np->n_accesscache[i].mode = rmode;
+                               np->n_accesscache[i].stamp = time_second;
+                               break;
+                       }
+                       if (i > 0 && np->n_accesscache[i].stamp <
+                           np->n_accesscache[lrupos].stamp)
+                               lrupos = i;
+               }
+               if (i == NFS_ACCESSCACHESIZE) {
+                       np->n_accesscache[lrupos].uid = cred->cr_uid;
+                       np->n_accesscache[lrupos].mode = rmode;
+                       np->n_accesscache[lrupos].stamp = time_second;
+               }
+               if (retmode != NULL)
+                       *retmode = rmode;
        }
        m_freem(mrep);
 nfsmout:
@@ -285,8 +300,8 @@ static int
 nfs4_access(struct vop_access_args *ap)
 {
        struct vnode *vp = ap->a_vp;
-       int error = 0;
-       u_int32_t mode, wmode;
+       int error = 0, i, gotahit;
+       u_int32_t mode, rmode, wmode;
        int v3 = NFS_ISV3(vp);  /* v3 \in v4 */
        struct nfsnode *np = VTONFS(vp);
        caddr_t bpos, dpos;
@@ -350,19 +365,27 @@ nfs4_access(struct vop_access_args *ap)
                 * Does our cached result allow us to give a definite yes to
                 * this request?
                 */
-               if (time_second < np->n_modestamp + nfs4_access_cache_timeout &&
-                   ap->a_cred->cr_uid == np->n_modeuid &&
-                   (np->n_mode & mode) == mode) {
-                       nfsstats.accesscache_hits++;
-               } else {
+               gotahit = 0;
+               for (i = 0; i < NFS_ACCESSCACHESIZE; i++) {
+                       if (ap->a_cred->cr_uid == np->n_accesscache[i].uid) {
+                               if (time_second < (np->n_accesscache[i].stamp +
+                                   nfs4_access_cache_timeout) &&
+                                   (np->n_accesscache[i].mode & mode) == mode) 
{
+                                       nfsstats.accesscache_hits++;
+                                       gotahit = 1;
+                               }
+                               break;
+                       }
+               }
+               if (gotahit == 0) {
                        /*
                         * Either a no, or a don't know.  Go to the wire.
                         */
                        nfsstats.accesscache_misses++;
                        error = nfs4_v3_access_otw(vp, wmode, ap->a_td,
-                           ap->a_cred);
+                           ap->a_cred, &rmode);
                        if (error == 0) {
-                               if ((np->n_mode & mode) != mode)
+                               if ((rmode & mode) != mode)
                                        error = EACCES;
                        }
                }

Modified: head/sys/nfsclient/nfs.h
==============================================================================
--- head/sys/nfsclient/nfs.h    Fri Mar 20 20:55:57 2009        (r190175)
+++ head/sys/nfsclient/nfs.h    Fri Mar 20 21:12:38 2009        (r190176)
@@ -68,6 +68,9 @@
 #ifndef NFS_MAXDIRATTRTIMO
 #define        NFS_MAXDIRATTRTIMO 60
 #endif
+#ifndef        NFS_ACCESSCACHESIZE
+#define        NFS_ACCESSCACHESIZE 8           /* Per-node access cache 
entries */
+#endif
 #define        NFS_WSIZE       8192            /* Def. write data size <= 8192 
*/
 #define        NFS_RSIZE       8192            /* Def. read data size <= 8192 
*/
 #define NFS_READDIRSIZE        8192            /* Def. readdir size */

Modified: head/sys/nfsclient/nfs_vnops.c
==============================================================================
--- head/sys/nfsclient/nfs_vnops.c      Fri Mar 20 20:55:57 2009        
(r190175)
+++ head/sys/nfsclient/nfs_vnops.c      Fri Mar 20 21:12:38 2009        
(r190176)
@@ -270,11 +270,11 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, access_ca
 
 static int
 nfs3_access_otw(struct vnode *vp, int wmode, struct thread *td,
-    struct ucred *cred)
+    struct ucred *cred, uint32_t *retmode)
 {
        const int v3 = 1;
        u_int32_t *tl;
-       int error = 0, attrflag;
+       int error = 0, attrflag, i, lrupos;
 
        struct mbuf *mreq, *mrep, *md, *mb;
        caddr_t bpos, dpos;
@@ -291,13 +291,28 @@ nfs3_access_otw(struct vnode *vp, int wm
        nfsm_request(vp, NFSPROC_ACCESS, td, cred);
        nfsm_postop_attr(vp, attrflag);
        if (!error) {
+               lrupos = 0;
                tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
                rmode = fxdr_unsigned(u_int32_t, *tl);
                mtx_lock(&np->n_mtx);
-               np->n_mode = rmode;
-               np->n_modeuid = cred->cr_uid;
-               np->n_modestamp = time_second;
+               for (i = 0; i < NFS_ACCESSCACHESIZE; i++) {
+                       if (np->n_accesscache[i].uid == cred->cr_uid) {
+                               np->n_accesscache[i].mode = rmode;
+                               np->n_accesscache[i].stamp = time_second;
+                               break;
+                       }
+                       if (i > 0 && np->n_accesscache[i].stamp <
+                           np->n_accesscache[lrupos].stamp)
+                               lrupos = i;
+               }
+               if (i == NFS_ACCESSCACHESIZE) {
+                       np->n_accesscache[lrupos].uid = cred->cr_uid;
+                       np->n_accesscache[lrupos].mode = rmode;
+                       np->n_accesscache[lrupos].stamp = time_second;
+               }
                mtx_unlock(&np->n_mtx);
+               if (retmode != NULL)
+                       *retmode = rmode;
        }
        m_freem(mrep);
 nfsmout:
@@ -314,8 +329,8 @@ static int
 nfs_access(struct vop_access_args *ap)
 {
        struct vnode *vp = ap->a_vp;
-       int error = 0;
-       u_int32_t mode, wmode;
+       int error = 0, i, gotahit;
+       u_int32_t mode, rmode, wmode;
        int v3 = NFS_ISV3(vp);
        struct nfsnode *np = VTONFS(vp);
 
@@ -372,26 +387,32 @@ nfs_access(struct vop_access_args *ap)
                 * Does our cached result allow us to give a definite yes to
                 * this request?
                 */
+               gotahit = 0;
                mtx_lock(&np->n_mtx);
-               if ((time_second < (np->n_modestamp + nfsaccess_cache_timeout)) 
&&
-                   (ap->a_cred->cr_uid == np->n_modeuid) &&
-                   ((np->n_mode & mode) == mode)) {
-                       nfsstats.accesscache_hits++;
-               } else {
+               for (i = 0; i < NFS_ACCESSCACHESIZE; i++) {
+                       if (ap->a_cred->cr_uid == np->n_accesscache[i].uid) {
+                               if (time_second < (np->n_accesscache[i].stamp +
+                                   nfsaccess_cache_timeout) &&
+                                   (np->n_accesscache[i].mode & mode) == mode) 
{
+                                       nfsstats.accesscache_hits++;
+                                       gotahit = 1;
+                               }
+                               break;
+                       }
+               }
+               mtx_unlock(&np->n_mtx);
+               if (gotahit == 0) {
                        /*
                         * Either a no, or a don't know.  Go to the wire.
                         */
                        nfsstats.accesscache_misses++;
-                       mtx_unlock(&np->n_mtx);
-                       error = nfs3_access_otw(vp, wmode, ap->a_td,ap->a_cred);
-                       mtx_lock(&np->n_mtx);
+                       error = nfs3_access_otw(vp, wmode, ap->a_td, ap->a_cred,
+                           &rmode);
                        if (!error) {
-                               if ((np->n_mode & mode) != mode) {
+                               if ((rmode & mode) != mode)
                                        error = EACCES;
-                               }
                        }
                }
-               mtx_unlock(&np->n_mtx);
                return (error);
        } else {
                if ((error = nfsspec_access(ap)) != 0) {
@@ -651,7 +672,7 @@ nfs_getattr(struct vop_getattr_args *ap)
                goto nfsmout;
        if (v3 && nfs_prime_access_cache && nfsaccess_cache_timeout > 0) {
                nfsstats.accesscache_misses++;
-               nfs3_access_otw(vp, NFSV3ACCESS_ALL, td, ap->a_cred);
+               nfs3_access_otw(vp, NFSV3ACCESS_ALL, td, ap->a_cred, NULL);
                if (nfs_getattrcache(vp, &vattr) == 0)
                        goto nfsmout;
        }
@@ -810,7 +831,7 @@ nfs_setattrrpc(struct vnode *vp, struct 
        struct nfsnode *np = VTONFS(vp);
        caddr_t bpos, dpos;
        u_int32_t *tl;
-       int error = 0, wccflag = NFSV3_WCCRATTR;
+       int error = 0, i, wccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb;
        int v3 = NFS_ISV3(vp);
 
@@ -843,7 +864,10 @@ nfs_setattrrpc(struct vnode *vp, struct 
        }
        nfsm_request(vp, NFSPROC_SETATTR, curthread, cred);
        if (v3) {
-               np->n_modestamp = 0;
+               mtx_lock(&np->n_mtx);
+               for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
+                       np->n_accesscache[i].stamp = 0;
+               mtx_unlock(&np->n_mtx);
                nfsm_wcc_data(vp, wccflag);
        } else
                nfsm_loadattr(vp, NULL);

Modified: head/sys/nfsclient/nfsnode.h
==============================================================================
--- head/sys/nfsclient/nfsnode.h        Fri Mar 20 20:55:57 2009        
(r190175)
+++ head/sys/nfsclient/nfsnode.h        Fri Mar 20 21:12:38 2009        
(r190176)
@@ -84,6 +84,12 @@ struct nfs_attrcache_timestamp {
        unsigned long   nfs_ac_ts_syscalls;     
 };
 
+struct nfs_accesscache {
+       u_int32_t               mode;           /* ACCESS mode cache */
+       uid_t                   uid;            /* credentials having mode */
+       time_t                  stamp;          /* mode cache timestamp */
+};
+       
 /*
  * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
  * is purely coincidental.
@@ -104,9 +110,7 @@ struct nfsnode {
        u_quad_t                n_lrev;         /* Modify rev for lease */
        struct vattr            n_vattr;        /* Vnode attribute cache */
        time_t                  n_attrstamp;    /* Attr. cache timestamp */
-       u_int32_t               n_mode;         /* ACCESS mode cache */
-       uid_t                   n_modeuid;      /* credentials having mode */
-       time_t                  n_modestamp;    /* mode cache timestamp */
+       struct nfs_accesscache  n_accesscache[NFS_ACCESSCACHESIZE];
        struct timespec         n_mtime;        /* Prev modify time. */
        time_t                  n_ctime;        /* Prev create time. */
        time_t                  n_dmtime;       /* Prev dir modify time. */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to