Store the full timestamp when caching timestamps of files and
directories for purposes of validating name cache entries. This closes races where two updates to a file or directory within the same second could result in stale entries in the name cache. While here, remove the 'n_expiry' field as it is no longer used. Reviewed by: rmacklem MFC after: 1 week
This commit is contained in:
parent
b33adc1bec
commit
0f939dc96e
@ -3293,8 +3293,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
|
||||
ndp->ni_vp = newvp;
|
||||
NFSCNHASH(cnp, HASHINIT);
|
||||
if (cnp->cn_namelen <= NCHNAMLEN) {
|
||||
np->n_ctime =
|
||||
np->n_vattr.na_ctime.tv_sec;
|
||||
np->n_ctime = np->n_vattr.na_ctime;
|
||||
cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp);
|
||||
}
|
||||
if (unlocknewvp)
|
||||
|
@ -988,7 +988,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
struct nfsfh *nfhp;
|
||||
struct nfsvattr dnfsva, nfsva;
|
||||
struct vattr vattr;
|
||||
time_t dmtime;
|
||||
struct timespec dmtime;
|
||||
|
||||
*vpp = NULLVP;
|
||||
if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
|
||||
@ -1038,7 +1038,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
}
|
||||
if (nfscl_nodeleg(newvp, 0) == 0 ||
|
||||
(VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
vattr.va_ctime.tv_sec == newnp->n_ctime)) {
|
||||
timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==))) {
|
||||
NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
|
||||
if (cnp->cn_nameiop != LOOKUP &&
|
||||
(flags & ISLASTCN))
|
||||
@ -1065,13 +1065,13 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
if ((u_int)(ticks - np->n_dmtime_ticks) <
|
||||
(nmp->nm_negnametimeo * hz) &&
|
||||
VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
vattr.va_mtime.tv_sec == np->n_dmtime) {
|
||||
timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) {
|
||||
NFSINCRGLOBAL(newnfsstats.lookupcache_hits);
|
||||
return (ENOENT);
|
||||
}
|
||||
cache_purge_negative(dvp);
|
||||
mtx_lock(&np->n_mtx);
|
||||
np->n_dmtime = 0;
|
||||
timespecclear(&np->n_dmtime);
|
||||
mtx_unlock(&np->n_mtx);
|
||||
}
|
||||
|
||||
@ -1086,7 +1086,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* the lookup RPC has been performed on the server but before
|
||||
* n_dmtime is set at the end of this function.
|
||||
*/
|
||||
dmtime = np->n_vattr.na_mtime.tv_sec;
|
||||
dmtime = np->n_vattr.na_mtime;
|
||||
error = 0;
|
||||
newvp = NULLVP;
|
||||
NFSINCRGLOBAL(newnfsstats.lookupcache_misses);
|
||||
@ -1139,8 +1139,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* lookup.
|
||||
*/
|
||||
mtx_lock(&np->n_mtx);
|
||||
if (np->n_dmtime <= dmtime) {
|
||||
if (np->n_dmtime == 0) {
|
||||
if (timespeccmp(&np->n_dmtime, &dmtime, <=)) {
|
||||
if (!timespecisset(&np->n_dmtime)) {
|
||||
np->n_dmtime = dmtime;
|
||||
np->n_dmtime_ticks = ticks;
|
||||
}
|
||||
@ -1241,7 +1241,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
cnp->cn_flags |= SAVENAME;
|
||||
if ((cnp->cn_flags & MAKEENTRY) &&
|
||||
(cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
|
||||
np->n_ctime = np->n_vattr.na_vattr.va_ctime.tv_sec;
|
||||
np->n_ctime = np->n_vattr.na_vattr.va_ctime;
|
||||
cache_enter(dvp, newvp, cnp);
|
||||
}
|
||||
*vpp = newvp;
|
||||
|
@ -96,10 +96,9 @@ struct nfsnode {
|
||||
time_t n_attrstamp; /* Attr. 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. */
|
||||
struct timespec n_ctime; /* Prev create time. */
|
||||
struct timespec n_dmtime; /* Prev dir modify time. */
|
||||
int n_dmtime_ticks; /* Tick of -ve cache entry */
|
||||
time_t n_expiry; /* Lease expiry time */
|
||||
struct nfsfh *n_fhp; /* NFS File Handle */
|
||||
struct vnode *n_vnode; /* associated vnode */
|
||||
struct vnode *n_dvp; /* parent vnode */
|
||||
|
@ -916,7 +916,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct mount *mp = dvp->v_mount;
|
||||
struct vattr vattr;
|
||||
time_t dmtime;
|
||||
struct timespec dmtime;
|
||||
int flags = cnp->cn_flags;
|
||||
struct vnode *newvp;
|
||||
struct nfsmount *nmp;
|
||||
@ -970,7 +970,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
mtx_unlock(&newnp->n_mtx);
|
||||
}
|
||||
if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
vattr.va_ctime.tv_sec == newnp->n_ctime) {
|
||||
timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==)) {
|
||||
nfsstats.lookupcache_hits++;
|
||||
if (cnp->cn_nameiop != LOOKUP &&
|
||||
(flags & ISLASTCN))
|
||||
@ -997,13 +997,13 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
if ((u_int)(ticks - np->n_dmtime_ticks) <
|
||||
(nmp->nm_negnametimeo * hz) &&
|
||||
VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
|
||||
vattr.va_mtime.tv_sec == np->n_dmtime) {
|
||||
timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) {
|
||||
nfsstats.lookupcache_hits++;
|
||||
return (ENOENT);
|
||||
}
|
||||
cache_purge_negative(dvp);
|
||||
mtx_lock(&np->n_mtx);
|
||||
np->n_dmtime = 0;
|
||||
timespecclear(&np->n_dmtime);
|
||||
mtx_unlock(&np->n_mtx);
|
||||
}
|
||||
|
||||
@ -1018,7 +1018,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* the lookup RPC has been performed on the server but before
|
||||
* n_dmtime is set at the end of this function.
|
||||
*/
|
||||
dmtime = np->n_vattr.va_mtime.tv_sec;
|
||||
dmtime = np->n_vattr.va_mtime;
|
||||
error = 0;
|
||||
newvp = NULLVP;
|
||||
nfsstats.lookupcache_misses++;
|
||||
@ -1137,7 +1137,7 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
cnp->cn_flags |= SAVENAME;
|
||||
if ((cnp->cn_flags & MAKEENTRY) &&
|
||||
(cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
|
||||
np->n_ctime = np->n_vattr.va_ctime.tv_sec;
|
||||
np->n_ctime = np->n_vattr.va_ctime;
|
||||
cache_enter(dvp, newvp, cnp);
|
||||
}
|
||||
*vpp = newvp;
|
||||
@ -1183,8 +1183,8 @@ nfs_lookup(struct vop_lookup_args *ap)
|
||||
* lookup.
|
||||
*/
|
||||
mtx_lock(&np->n_mtx);
|
||||
if (np->n_dmtime <= dmtime) {
|
||||
if (np->n_dmtime == 0) {
|
||||
if (timespeccmp(&np->n_dmtime, &dmtime, <=)) {
|
||||
if (!timespecisset(&np->n_dmtime)) {
|
||||
np->n_dmtime = dmtime;
|
||||
np->n_dmtime_ticks = ticks;
|
||||
}
|
||||
@ -2657,8 +2657,11 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
|
||||
dp->d_type =
|
||||
IFTODT(VTTOIF(np->n_vattr.va_type));
|
||||
ndp->ni_vp = newvp;
|
||||
/* Update n_ctime, so subsequent lookup doesn't purge entry */
|
||||
np->n_ctime = np->n_vattr.va_ctime.tv_sec;
|
||||
/*
|
||||
* Update n_ctime so subsequent lookup
|
||||
* doesn't purge entry.
|
||||
*/
|
||||
np->n_ctime = np->n_vattr.va_ctime;
|
||||
cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
|
||||
}
|
||||
} else {
|
||||
|
@ -102,10 +102,9 @@ struct nfsnode {
|
||||
time_t n_attrstamp; /* Attr. 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. */
|
||||
struct timespec n_ctime; /* Prev create time. */
|
||||
struct timespec n_dmtime; /* Prev dir modify time. */
|
||||
int n_dmtime_ticks; /* Tick of -ve cache entry */
|
||||
time_t n_expiry; /* Lease expiry time */
|
||||
nfsfh_t *n_fhp; /* NFS File Handle */
|
||||
struct vnode *n_vnode; /* associated vnode */
|
||||
struct vnode *n_dvp; /* parent vnode */
|
||||
|
Loading…
Reference in New Issue
Block a user