--- //depot/projects/smpng/sys/kern/vfs_cache.c 2009/01/28 22:38:17 +++ //depot/user/jhb/lock/kern/vfs_cache.c 2009/02/12 15:09:23 @@ -663,6 +663,24 @@ } /* + * Invalidate all negative entries for a particular directory vnode. + */ +void +cache_purge_negative(vp) + struct vnode *vp; +{ + struct namecache *cp, *ncp; + + CTR1(KTR_VFS, "cache_purge_negative(%p)", vp); + CACHE_WLOCK(); + LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) { + if (cp->nc_vp == NULL) + cache_zap(cp); + } + CACHE_WUNLOCK(); +} + +/* * Flush all entries referencing a particular filesystem. */ void --- //depot/projects/smpng/sys/nfsclient/nfs_vnops.c 2009/01/28 22:38:17 +++ //depot/user/jhb/lock/nfsclient/nfs_vnops.c 2009/02/17 20:09:54 @@ -594,13 +594,6 @@ error = nfs_vinvalbuf(vp, V_SAVE, ap->a_td, 1); mtx_lock(&np->n_mtx); } - /* - * Invalidate the attribute cache in all cases. - * An open is going to fetch fresh attrs any way, other procs - * on this node that have file open will be forced to do an - * otw attr fetch, but this is safe. - */ - np->n_attrstamp = 0; if (np->n_flag & NWRITEERR) { np->n_flag &= ~NWRITEERR; error = np->n_error; @@ -651,12 +644,6 @@ */ if (nfs_getattrcache(vp, &vattr) == 0) goto nfsmout; - if (v3 && nfsaccess_cache_timeout > 0) { - nfsstats.accesscache_misses++; - nfs3_access_otw(vp, NFSV3ACCESS_ALL, td, ap->a_cred); - if (nfs_getattrcache(vp, &vattr) == 0) - goto nfsmout; - } nfsstats.rpccnt[NFSPROC_GETATTR]++; mreq = nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3)); mb = mreq; @@ -865,6 +852,7 @@ struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; + struct vattr vattr; int flags = cnp->cn_flags; struct vnode *newvp; struct nfsmount *nmp; @@ -893,16 +881,20 @@ if (error > 0 && error != ENOENT) return (error); if (error == -1) { - struct vattr vattr; - + /* + * 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. + */ newvp = *vpp; if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred) && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { nfsstats.lookupcache_hits++; if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) cnp->cn_flags |= SAVENAME; return (0); } cache_purge(newvp); if (dvp != newvp) @@ -910,6 +902,24 @@ else vrele(newvp); *vpp = NULLVP; + } else if (error == ENOENT) { + /* + * We only accept a negative hit in the cache if the + * modification time of the parent directory matches + * our cached copy. Otherwise, we discard all of the + * negative cache entries for this directory. + */ + if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && + vattr.va_mtime.tv_sec == np->n_dmtime) { + nfsstats.lookupcache_hits++; + if ((cnp->cn_nameiop == CREATE || + cnp->cn_nameiop == RENAME) && + (flags & ISLASTCN)) + cnp->cn_flags |= SAVENAME; + return (ENOENT); + } + cache_purge_negative(dvp); + np->n_dmtime = 0; } error = 0; newvp = NULLVP; @@ -995,16 +1005,38 @@ vput(newvp); *vpp = NULLVP; } + + if (error != ENOENT) + goto done; + + /* The requested file was not found. */ if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && - (flags & ISLASTCN) && error == ENOENT) { + (flags & ISLASTCN)) { + /* + * XXX: UFS does a full VOP_ACCESS(dvp, + * VWRITE) here instead of just checking + * MNT_RDONLY. + */ if (dvp->v_mount->mnt_flag & MNT_RDONLY) - error = EROFS; - else - error = EJUSTRETURN; + return (EROFS); + cnp->cn_flags |= SAVENAME; + return (EJUSTRETURN); + } + + if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) { + /* + * Maintain n_dmtime as the modification time + * of the parent directory when the oldest -ve + * name cache entry for this directory was + * added. + */ + if (np->n_dmtime == 0) + np->n_dmtime = np->n_vattr.va_mtime.tv_sec; + cache_enter(dvp, NULL, cnp); } - if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) - cnp->cn_flags |= SAVENAME; + return (ENOENT); } +done: return (error); } --- //depot/projects/smpng/sys/nfsclient/nfsnode.h 2008/07/25 18:20:23 +++ //depot/user/jhb/lock/nfsclient/nfsnode.h 2009/02/12 16:15:28 @@ -109,6 +109,7 @@ time_t n_modestamp; /* mode cache timestamp */ struct timespec n_mtime; /* Prev modify time. */ time_t n_ctime; /* Prev create time. */ + time_t n_dmtime; /* Prev dir modify time. */ time_t n_expiry; /* Lease expiry time */ nfsfh_t *n_fhp; /* NFS File Handle */ struct vnode *n_vnode; /* associated vnode */ --- //depot/projects/smpng/sys/sys/vnode.h 2009/01/28 22:38:17 +++ //depot/user/jhb/lock/sys/vnode.h 2009/02/12 15:09:23 @@ -562,6 +562,7 @@ int cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); void cache_purge(struct vnode *vp); +void cache_purge_negative(struct vnode *vp); void cache_purgevfs(struct mount *mp); int change_dir(struct vnode *vp, struct thread *td); int change_root(struct vnode *vp, struct thread *td);