From owner-svn-src-head@FreeBSD.ORG Thu Feb 19 22:28:49 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 74C2F1065672; Thu, 19 Feb 2009 22:28:49 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 570AC8FC2A; Thu, 19 Feb 2009 22:28:49 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1JMSnAB009476; Thu, 19 Feb 2009 22:28:49 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1JMSn2Q009472; Thu, 19 Feb 2009 22:28:49 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <200902192228.n1JMSn2Q009472@svn.freebsd.org> From: John Baldwin Date: Thu, 19 Feb 2009 22:28:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188833 - in head/sys: kern nfsclient sys X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Feb 2009 22:28:50 -0000 Author: jhb Date: Thu Feb 19 22:28:48 2009 New Revision: 188833 URL: http://svn.freebsd.org/changeset/base/188833 Log: Enable caching of negative pathname lookups in the NFS client. To avoid stale entries, we save a copy of the directory's modification time when the first negative cache entry was added in the directory's NFS node. When a negative cache entry is hit during a pathname lookup, the parent directory's modification time is checked. If it has changed, all of the negative cache entries for that parent are purged and the lookup falls back to using the RPC. This required adding a new cache_purge_negative() method to the name cache to purge only negative cache entries for a given directory. Submitted by: mohans, Rick Macklem, Ricardo Labiaga @ NetApp Reviewed by: mohans Modified: head/sys/kern/vfs_cache.c head/sys/nfsclient/nfs_vnops.c head/sys/nfsclient/nfsnode.h head/sys/sys/vnode.h Modified: head/sys/kern/vfs_cache.c ============================================================================== --- head/sys/kern/vfs_cache.c Thu Feb 19 22:18:00 2009 (r188832) +++ head/sys/kern/vfs_cache.c Thu Feb 19 22:28:48 2009 (r188833) @@ -663,6 +663,24 @@ cache_purge(vp) } /* + * 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 Modified: head/sys/nfsclient/nfs_vnops.c ============================================================================== --- head/sys/nfsclient/nfs_vnops.c Thu Feb 19 22:18:00 2009 (r188832) +++ head/sys/nfsclient/nfs_vnops.c Thu Feb 19 22:28:48 2009 (r188833) @@ -852,6 +852,7 @@ nfs_lookup(struct vop_lookup_args *ap) 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; @@ -880,8 +881,12 @@ nfs_lookup(struct vop_lookup_args *ap) 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) { @@ -897,6 +902,24 @@ nfs_lookup(struct vop_lookup_args *ap) 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; @@ -982,16 +1005,38 @@ nfsmout: 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; - } - if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) + 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); + } + return (ENOENT); } +done: return (error); } Modified: head/sys/nfsclient/nfsnode.h ============================================================================== --- head/sys/nfsclient/nfsnode.h Thu Feb 19 22:18:00 2009 (r188832) +++ head/sys/nfsclient/nfsnode.h Thu Feb 19 22:28:48 2009 (r188833) @@ -109,6 +109,7 @@ struct nfsnode { 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 */ Modified: head/sys/sys/vnode.h ============================================================================== --- head/sys/sys/vnode.h Thu Feb 19 22:18:00 2009 (r188832) +++ head/sys/sys/vnode.h Thu Feb 19 22:28:48 2009 (r188833) @@ -562,6 +562,7 @@ void cache_enter(struct vnode *dvp, stru 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);