summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-03-20 21:12:38 +0000
committerjhb <jhb@FreeBSD.org>2009-03-20 21:12:38 +0000
commit79aaac6e7b4553e4799500d20a8d63ea337b8925 (patch)
treedeb7778d132a1e3e54c04c506baa768ad0e61400 /sys/nfsclient
parent5dee97ce8610e3adf8c9f937bd5fe961ca124c90 (diff)
downloadFreeBSD-src-79aaac6e7b4553e4799500d20a8d63ea337b8925.zip
FreeBSD-src-79aaac6e7b4553e4799500d20a8d63ea337b8925.tar.gz
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
Diffstat (limited to 'sys/nfsclient')
-rw-r--r--sys/nfsclient/nfs.h3
-rw-r--r--sys/nfsclient/nfs_vnops.c66
-rw-r--r--sys/nfsclient/nfsnode.h10
3 files changed, 55 insertions, 24 deletions
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index c5b1c51..783fe07 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -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 */
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c
index fd44c1a..a209327 100644
--- a/sys/nfsclient/nfs_vnops.c
+++ b/sys/nfsclient/nfs_vnops.c
@@ -270,11 +270,11 @@ SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_misses, CTLFLAG_RD,
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 wmode, struct thread *td,
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 vattr *vap, struct ucred *cred)
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 vattr *vap, struct ucred *cred)
}
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);
diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h
index 7781ae6..6f10d79 100644
--- a/sys/nfsclient/nfsnode.h
+++ b/sys/nfsclient/nfsnode.h
@@ -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. */
OpenPOWER on IntegriCloud