svn commit: r190176 - in head/sys: nfs4client nfsclient

John Baldwin jhb at FreeBSD.org
Fri Mar 20 14:12:40 PDT 2009


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. */


More information about the svn-src-all mailing list