From 768a468c15a95c443b29381081ac318debea4846 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 25 Jan 2012 20:05:58 +0000 Subject: 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 --- sys/nfsclient/nfs_vfsops.c | 22 +++++++++++++++++----- sys/nfsclient/nfs_vnops.c | 6 ++++-- sys/nfsclient/nfsmount.h | 5 +++++ 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'sys/nfsclient') diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index e43c048..5c257fc 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -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) diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index a39b29b..e032448 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -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 && diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h index 6b84bdd..77171a1 100644 --- a/sys/nfsclient/nfsmount.h +++ b/sys/nfsclient/nfsmount.h @@ -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 -- cgit v1.1