diff options
-rw-r--r-- | sys/nfs/nfs_node.c | 3 | ||||
-rw-r--r-- | sys/nfs/nfs_subs.c | 14 | ||||
-rw-r--r-- | sys/nfs/nfs_var.h | 3 | ||||
-rw-r--r-- | sys/nfs/nfs_vnops.c | 88 | ||||
-rw-r--r-- | sys/nfs/nfsnode.h | 6 |
5 files changed, 96 insertions, 18 deletions
diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c index 43e7acdd2ab..26af6c2ceea 100644 --- a/sys/nfs/nfs_node.c +++ b/sys/nfs/nfs_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_node.c,v 1.37 2007/12/13 22:32:55 thib Exp $ */ +/* $OpenBSD: nfs_node.c,v 1.38 2008/06/10 22:59:09 thib Exp $ */ /* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */ /* @@ -150,6 +150,7 @@ loop: np->n_fhp = &np->n_fh; bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); np->n_fhsize = fhsize; + np->n_accstamp = -1; rw_exit(&nfs_hashlock); *npp = np; return (0); diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index ec707792590..a4104f7571a 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_subs.c,v 1.76 2008/06/09 22:49:15 djm Exp $ */ +/* $OpenBSD: nfs_subs.c,v 1.77 2008/06/10 22:59:09 thib Exp $ */ /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ /* @@ -1015,6 +1015,8 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) struct timespec mtime; struct vnode *nvp; int v3 = NFS_ISV3(vp); + uid_t uid; + gid_t gid; md = *mdp; t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; @@ -1091,6 +1093,15 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) vap->va_rdev = (dev_t)rdev; vap->va_mtime = mtime; vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; + + uid = fxdr_unsigned(uid_t, fp->fa_uid); + gid = fxdr_unsigned(gid_t, fp->fa_gid); + /* Invalidate access cache if uid, gid or mode changed. */ + if (np->n_accstamp != -1 && + (gid != vap->va_gid || uid != vap->va_uid || + vmode != vap->va_mode)) + np->n_accstamp = -1; + switch (vtyp) { case VBLK: vap->va_blocksize = BLKDEV_IOSIZE; @@ -1132,6 +1143,7 @@ nfs_loadattrcache(vpp, mdp, dposp, vaper) vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); vap->va_filerev = 0; } + if (vap->va_size != np->n_size) { if (vap->va_type == VREG) { if (np->n_flag & NMODIFIED) { diff --git a/sys/nfs/nfs_var.h b/sys/nfs/nfs_var.h index ff9c405c8ac..e6a6f8ca527 100644 --- a/sys/nfs/nfs_var.h +++ b/sys/nfs/nfs_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_var.h,v 1.37 2008/06/09 22:49:15 djm Exp $ */ +/* $OpenBSD: nfs_var.h,v 1.38 2008/06/10 22:59:09 thib Exp $ */ /* $NetBSD: nfs_var.h,v 1.3 1996/02/18 11:53:54 fvdl Exp $ */ /* @@ -249,6 +249,7 @@ int nfsm_disct(struct mbuf **, caddr_t *, int, int, caddr_t *); int nfs_adv(struct mbuf **, caddr_t *, int, int); int nfsm_strtmbuf(struct mbuf **, char **, char *, long); int nfs_vfs_init(struct vfsconf *); +int nfs_attrtimeo(struct nfsnode *); int nfs_loadattrcache(struct vnode **, struct mbuf **, caddr_t *, struct vattr *); int nfs_getattrcache(struct vnode *, struct vattr *); diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index d26824f8b0e..0c2806acedd 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nfs_vnops.c,v 1.85 2008/06/10 20:14:37 beck Exp $ */ +/* $OpenBSD: nfs_vnops.c,v 1.86 2008/06/10 22:59:09 thib Exp $ */ /* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */ /* @@ -82,6 +82,8 @@ #define TRUE 1 #define FALSE 0 +void nfs_cache_enter(struct vnode *, struct vnode *, struct componentname *); + /* * Global vfs data structures for nfs */ @@ -186,6 +188,24 @@ extern nfstype nfsv3_type[9]; struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; int nfs_numasync = 0; + +void +nfs_cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) +{ + struct nfsnode *np; + + if (vp != NULL) { + np = VTONFS(vp); + np->n_ctime = np->n_vattr.va_ctime.tv_sec; + } else { + np = VTONFS(dvp); + if (!np->n_ctime) + np->n_ctime = np->n_vattr.va_mtime.tv_sec; + } + + cache_enter(dvp, vp, cnp); +} + /* * nfs null call from vfs. */ @@ -226,6 +246,9 @@ nfs_access(v) struct mbuf *mreq, *mrep, *md, *mb; u_int32_t mode, rmode; int v3 = NFS_ISV3(vp); + int cachevalid; + + struct nfsnode *np = VTONFS(vp); /* * Disallow write attempts on filesystems mounted read-only; @@ -242,6 +265,23 @@ nfs_access(v) break; } } + + /* + * Check access cache first. If a request has been made for this uid + * shortly before, use the cached result. + */ + cachevalid = (np->n_accstamp != -1 && + (time_second - np->n_accstamp) < nfs_attrtimeo(np) && + np->n_accuid == ap->a_cred->cr_uid); + + if (cachevalid) { + if (!np->n_accerror) { + if ((np->n_accmode & ap->a_mode) == ap->a_mode) + return (np->n_accerror); + } else if ((np->n_accmode & ap->a_mode) == np->n_accmode) + return (np->n_accerror); + } + /* * For nfs v3, do an access rpc, otherwise you are stuck emulating * ufs_access() locally using the vattr. This may not be correct, @@ -285,11 +325,33 @@ nfs_access(v) if ((rmode & mode) != mode) error = EACCES; } - m_freem(mrep); -nfsmout: - return (error); + m_freem(mrep); } else return (nfsspec_access(ap)); + + + /* + * If we got the same result as for a previous, different request, OR + * it in. Don't update the timestamp in that case. + */ + if (!error || error == EACCES) { + if (cachevalid && np->n_accstamp != -1 && + error == np->n_accerror) { + if (!error) + np->n_accmode |= ap->a_mode; + else { + if ((np->n_accmode & ap->a_mode) == ap->a_mode) + np->n_accmode = ap->a_mode; + } + } else { + np->n_accstamp = time_second; + np->n_accuid = ap->a_cred->cr_uid; + np->n_accmode = ap->a_mode; + np->n_accerror = error; + } + } +nfsmout: + return (error); } /* @@ -813,8 +875,7 @@ dorpc: 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; - cache_enter(dvp, newvp, cnp); + nfs_cache_enter(dvp, newvp, cnp); } *vpp = newvp; m_freem(mrep); @@ -828,10 +889,7 @@ nfsmout: */ if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) { - if (VTONFS(dvp)->n_ctime == 0) - VTONFS(dvp)->n_ctime = - VTONFS(dvp)->n_vattr.va_mtime.tv_sec; - cache_enter(dvp, NULL, cnp); + nfs_cache_enter(dvp, NULL, cnp); } if (newvp != NULLVP) { vrele(newvp); @@ -1170,7 +1228,7 @@ nfsmout: vrele(newvp); } else { if (cnp->cn_flags & MAKEENTRY) - cache_enter(dvp, newvp, cnp); + nfs_cache_enter(dvp, newvp, cnp); *vpp = newvp; } pool_put(&namei_pool, cnp->cn_pnbuf); @@ -1294,7 +1352,7 @@ nfsmout: error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc); if (!error) { if (cnp->cn_flags & MAKEENTRY) - cache_enter(dvp, newvp, cnp); + nfs_cache_enter(dvp, newvp, cnp); *ap->a_vpp = newvp; } pool_put(&namei_pool, cnp->cn_pnbuf); @@ -1738,6 +1796,8 @@ nfsmout: vrele(newvp); } else { VN_KNOTE(dvp, NOTE_WRITE|NOTE_LINK); + if (cnp->cn_flags & MAKEENTRY) + nfs_cache_enter(dvp, newvp, cnp); *ap->a_vpp = newvp; } pool_put(&namei_pool, cnp->cn_pnbuf); @@ -1788,7 +1848,6 @@ nfsmout: VN_KNOTE(dvp, NOTE_WRITE|NOTE_LINK); VN_KNOTE(vp, NOTE_DELETE); - cache_purge(dvp); cache_purge(vp); vrele(vp); vrele(dvp); @@ -2320,7 +2379,8 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, cnp->cn_hash = hash32_str(cnp->cn_nameptr, HASHINIT); - cache_enter(ndp->ni_dvp, ndp->ni_vp, + cache_purge(ndp->ni_dvp); + nfs_cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); } } diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h index ab4a64d5e06..c20e0542ee1 100644 --- a/sys/nfs/nfsnode.h +++ b/sys/nfs/nfsnode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nfsnode.h,v 1.29 2007/12/13 22:32:55 thib Exp $ */ +/* $OpenBSD: nfsnode.h,v 1.30 2008/06/10 22:59:09 thib Exp $ */ /* $NetBSD: nfsnode.h,v 1.16 1996/02/18 11:54:04 fvdl Exp $ */ /* @@ -92,6 +92,10 @@ struct nfsnode { short n_fhsize; /* size in bytes, of fh */ short n_flag; /* Flag for locking.. */ nfsfh_t n_fh; /* Small File Handle */ + time_t n_accstamp; /* Access cache timestamp */ + uid_t n_accuid; /* Last access requester */ + int n_accmode; /* Last mode requested */ + int n_accerror; /* Last returned error */ struct ucred *n_rcred; struct ucred *n_wcred; |