Add a timeout on positive name cache entries in the NFS client. That is,
we will only trust a positive name cache entry for a specified amount of time before falling back to a LOOKUP RPC, even if the ctime for the file handle matches the cached copy in the name cache entry. The timeout is configured via a new 'nametimeo' mount option and defaults to 60 seconds. It may be set to zero to disable positive name caching entirely. Reviewed by: rmacklem MFC after: 1 week
This commit is contained in:
parent
07dbb38763
commit
0b17c7bea5
@ -157,6 +157,10 @@ Force the mount protocol to use UDP transport, even for TCP NFS mounts.
|
||||
(Necessary for some old
|
||||
.Bx
|
||||
servers.)
|
||||
.It Cm nametimeo Ns = Ns Aq Ar value
|
||||
Override the default of NFS_DEFAULT_NAMETIMEO for the timeout (in seconds)
|
||||
for positive name cache entries.
|
||||
If this is set to 0 it disables positive name caching for the mount point.
|
||||
.It Cm negnametimeo Ns = Ns Aq Ar value
|
||||
Override the default of NFS_DEFAULT_NEGNAMETIMEO for the timeout (in seconds)
|
||||
for negative name cache entries. If this is set to 0 it disables negative
|
||||
|
@ -104,7 +104,7 @@ static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
|
||||
static int mountnfs(struct nfs_args *, struct mount *,
|
||||
struct sockaddr *, char *, u_char *, int, u_char *, int,
|
||||
u_char *, int, struct vnode **, struct ucred *,
|
||||
struct thread *, int);
|
||||
struct thread *, int, int);
|
||||
static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
|
||||
struct sockaddr_storage *, int *, off_t *,
|
||||
struct timeval *);
|
||||
@ -520,7 +520,8 @@ nfs_mountdiskless(char *path,
|
||||
dirlen = 0;
|
||||
nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
|
||||
if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
|
||||
NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
|
||||
NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
|
||||
NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
|
||||
printf("nfs_mountroot: mount %s on /: %d\n", path, error);
|
||||
return (error);
|
||||
}
|
||||
@ -715,7 +716,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
|
||||
"retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport",
|
||||
"readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec",
|
||||
"principal", "nfsv4", "gssname", "allgssname", "dirpath",
|
||||
"negnametimeo", "nocto", "wcommitsize",
|
||||
"nametimeo", "negnametimeo", "nocto", "wcommitsize",
|
||||
NULL };
|
||||
|
||||
/*
|
||||
@ -760,6 +761,7 @@ nfs_mount(struct mount *mp)
|
||||
char hst[MNAMELEN];
|
||||
u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
|
||||
char *opt, *name, *secname;
|
||||
int nametimeo = NFS_DEFAULT_NAMETIMEO;
|
||||
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
|
||||
int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen;
|
||||
size_t hstlen;
|
||||
@ -968,6 +970,14 @@ nfs_mount(struct mount *mp)
|
||||
}
|
||||
args.flags |= NFSMNT_TIMEO;
|
||||
}
|
||||
if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
|
||||
ret = sscanf(opt, "%d", &nametimeo);
|
||||
if (ret != 1 || nametimeo < 0) {
|
||||
vfs_mount_error(mp, "illegal nametimeo: %s", opt);
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
|
||||
== 0) {
|
||||
ret = sscanf(opt, "%d", &negnametimeo);
|
||||
@ -1126,7 +1136,7 @@ nfs_mount(struct mount *mp)
|
||||
args.fh = nfh;
|
||||
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
|
||||
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
|
||||
negnametimeo);
|
||||
nametimeo, negnametimeo);
|
||||
out:
|
||||
if (!error) {
|
||||
MNT_ILOCK(mp);
|
||||
@ -1170,7 +1180,7 @@ static int
|
||||
mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
|
||||
char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen,
|
||||
u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp,
|
||||
struct ucred *cred, struct thread *td, int negnametimeo)
|
||||
struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo)
|
||||
{
|
||||
struct nfsmount *nmp;
|
||||
struct nfsnode *np;
|
||||
@ -1237,13 +1247,14 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
|
||||
}
|
||||
vfs_getnewfsid(mp);
|
||||
nmp->nm_mountp = mp;
|
||||
mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
|
||||
mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK);
|
||||
|
||||
/*
|
||||
* Since nfs_decode_args() might optionally set them, these need to
|
||||
* set to defaults before the call, so that the optional settings
|
||||
* aren't overwritten.
|
||||
* Since nfs_decode_args() might optionally set them, these
|
||||
* need to be set to defaults before the call, so that the
|
||||
* optional settings aren't overwritten.
|
||||
*/
|
||||
nmp->nm_nametimeo = nametimeo;
|
||||
nmp->nm_negnametimeo = negnametimeo;
|
||||
nmp->nm_timeo = NFS_TIMEO;
|
||||
nmp->nm_retry = NFS_RETRANS;
|
||||
|
@ -1063,7 +1063,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* We only accept a positive hit in the cache if the
|
||||
* change time of the file matches our cached copy.
|
||||
* Otherwise, we discard the cache entry and fallback
|
||||
* to doing a lookup RPC.
|
||||
* to doing a lookup RPC. We also only trust cache
|
||||
* entries for less than nm_nametimeo seconds.
|
||||
*
|
||||
* To better handle stale file handles and attributes,
|
||||
* clear the attribute cache of this node if it is a
|
||||
@ -1085,7 +1086,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
mtx_unlock(&newnp->n_mtx);
|
||||
}
|
||||
if (nfscl_nodeleg(newvp, 0) == 0 ||
|
||||
(VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) &&
|
||||
VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_ctime, &nctime, ==))) {
|
||||
NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
|
||||
if (cnp->cn_nameiop != LOOKUP &&
|
||||
|
@ -66,6 +66,7 @@ struct nfsmount {
|
||||
u_int64_t nm_maxfilesize; /* maximum file size */
|
||||
int nm_tprintf_initial_delay; /* initial delay */
|
||||
int nm_tprintf_delay; /* interval for messages */
|
||||
int nm_nametimeo; /* timeout for +ve entries (sec) */
|
||||
int nm_negnametimeo; /* timeout for -ve entries (sec) */
|
||||
|
||||
/* Newnfs additions */
|
||||
@ -106,6 +107,10 @@ struct nfsmount {
|
||||
*/
|
||||
#define VFSTONFS(mp) ((struct nfsmount *)((mp)->mnt_data))
|
||||
|
||||
#ifndef NFS_DEFAULT_NAMETIMEO
|
||||
#define NFS_DEFAULT_NAMETIMEO 60
|
||||
#endif
|
||||
|
||||
#ifndef NFS_DEFAULT_NEGNAMETIMEO
|
||||
#define NFS_DEFAULT_NEGNAMETIMEO 60
|
||||
#endif
|
||||
|
@ -117,7 +117,7 @@ static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp,
|
||||
struct nfs_args *argp, const char *hostname);
|
||||
static int mountnfs(struct nfs_args *, struct mount *,
|
||||
struct sockaddr *, char *, struct vnode **,
|
||||
struct ucred *cred, int);
|
||||
struct ucred *cred, int, int);
|
||||
static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *,
|
||||
struct sockaddr_storage *, int *, off_t *,
|
||||
struct timeval *);
|
||||
@ -559,8 +559,8 @@ nfs_mountdiskless(char *path,
|
||||
int error;
|
||||
|
||||
nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
|
||||
if ((error = mountnfs(args, mp, nam, path, vpp,
|
||||
td->td_ucred, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
|
||||
if ((error = mountnfs(args, mp, nam, path, vpp, td->td_ucred,
|
||||
NFS_DEFAULT_NAMETIMEO, NFS_DEFAULT_NEGNAMETIMEO)) != 0) {
|
||||
printf("nfs_mountroot: mount %s on /: %d\n", path, error);
|
||||
return (error);
|
||||
}
|
||||
@ -788,6 +788,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
|
||||
"wsize", "rsize", "retrans", "acregmin", "acregmax", "acdirmin",
|
||||
"acdirmax", "deadthresh", "hostname", "timeout", "addr", "fh", "nfsv3",
|
||||
"sec", "maxgroups", "principal", "negnametimeo", "nocto", "wcommitsize",
|
||||
"nametimeo",
|
||||
NULL };
|
||||
|
||||
/*
|
||||
@ -836,6 +837,7 @@ nfs_mount(struct mount *mp)
|
||||
size_t len;
|
||||
u_char nfh[NFSX_V3FHMAX];
|
||||
char *opt;
|
||||
int nametimeo = NFS_DEFAULT_NAMETIMEO;
|
||||
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
|
||||
|
||||
has_nfs_args_opt = 0;
|
||||
@ -1058,6 +1060,14 @@ nfs_mount(struct mount *mp)
|
||||
}
|
||||
args.flags |= NFSMNT_MAXGRPS;
|
||||
}
|
||||
if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) {
|
||||
ret = sscanf(opt, "%d", &nametimeo);
|
||||
if (ret != 1 || nametimeo < 0) {
|
||||
vfs_mount_error(mp, "illegal nametimeo: %s", opt);
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL)
|
||||
== 0) {
|
||||
ret = sscanf(opt, "%d", &negnametimeo);
|
||||
@ -1182,7 +1192,7 @@ nfs_mount(struct mount *mp)
|
||||
goto out;
|
||||
}
|
||||
error = mountnfs(&args, mp, nam, args.hostname, &vp,
|
||||
curthread->td_ucred, negnametimeo);
|
||||
curthread->td_ucred, nametimeo, negnametimeo);
|
||||
out:
|
||||
if (!error) {
|
||||
MNT_ILOCK(mp);
|
||||
@ -1224,7 +1234,8 @@ nfs_cmount(struct mntarg *ma, void *data, uint64_t flags)
|
||||
*/
|
||||
static int
|
||||
mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
|
||||
char *hst, struct vnode **vpp, struct ucred *cred, int negnametimeo)
|
||||
char *hst, struct vnode **vpp, struct ucred *cred, int nametimeo,
|
||||
int negnametimeo)
|
||||
{
|
||||
struct nfsmount *nmp;
|
||||
struct nfsnode *np;
|
||||
@ -1274,6 +1285,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
|
||||
nmp->nm_numgrps = NFS_MAXGRPS;
|
||||
nmp->nm_readahead = NFS_DEFRAHEAD;
|
||||
nmp->nm_deadthresh = NFS_MAXDEADTHRESH;
|
||||
nmp->nm_nametimeo = nametimeo;
|
||||
nmp->nm_negnametimeo = negnametimeo;
|
||||
nmp->nm_tprintf_delay = nfs_tprintf_delay;
|
||||
if (nmp->nm_tprintf_delay < 0)
|
||||
|
@ -959,7 +959,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* We only accept a positive hit in the cache if the
|
||||
* change time of the file matches our cached copy.
|
||||
* Otherwise, we discard the cache entry and fallback
|
||||
* to doing a lookup RPC.
|
||||
* to doing a lookup RPC. We also only trust cache
|
||||
* entries for less than nm_nametimeo seconds.
|
||||
*
|
||||
* To better handle stale file handles and attributes,
|
||||
* clear the attribute cache of this node if it is a
|
||||
@ -980,7 +981,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
|
||||
mtx_unlock(&newnp->n_mtx);
|
||||
}
|
||||
if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
if ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) &&
|
||||
VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
timespeccmp(&vattr.va_ctime, &nctime, ==)) {
|
||||
nfsstats.lookupcache_hits++;
|
||||
if (cnp->cn_nameiop != LOOKUP &&
|
||||
|
@ -83,6 +83,7 @@ struct nfsmount {
|
||||
struct rpc_timers nm_timers[NFS_MAX_TIMER]; /* RTT Timers for rpcs */
|
||||
char nm_principal[MNAMELEN]; /* GSS-API principal of server */
|
||||
gss_OID nm_mech_oid; /* OID of selected GSS-API mechanism */
|
||||
int nm_nametimeo; /* timeout for +ve entries (sec) */
|
||||
int nm_negnametimeo; /* timeout for -ve entries (sec) */
|
||||
|
||||
/* NFSv4 */
|
||||
@ -116,6 +117,10 @@ struct nfsmount {
|
||||
#define NFS_TPRINTF_DELAY 30
|
||||
#endif
|
||||
|
||||
#ifndef NFS_DEFAULT_NAMETIMEO
|
||||
#define NFS_DEFAULT_NAMETIMEO 60
|
||||
#endif
|
||||
|
||||
#ifndef NFS_DEFAULT_NEGNAMETIMEO
|
||||
#define NFS_DEFAULT_NEGNAMETIMEO 60
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user