mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
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
This commit is contained in:
parent
ab42e8b2df
commit
2a3f3a09c6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=190176
@ -241,11 +241,11 @@ SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_misses, CTLFLAG_RD,
|
||||
| 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 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user