* Implement optional 32 <-> 64 bit directory cookie translation. This uses

the directory cache as translation table. See nfs_subs.c for comments.
  Makes the code a bit more complex to look at than I would have liked,
  but doesn't affect the speed of the default behavior.
* Optimize caching behavior a bit when buffers are invalidated.
* Save some RPCs in readdir operations by not bothering if there is
  a small amount left to do to fill the buffer. It'll be done in the
  next RPC with a larger chunk anyway. Wastes a bit of buffer space
  but is faster.
* Make n_vattr an allocated vattr struct. This avoids nfsnode bloat,
  and is friendlier to the malloc routines.
This commit is contained in:
fvdl 1997-10-19 01:46:15 +00:00
parent adecb9addf
commit 1cf3a3db94
10 changed files with 353 additions and 136 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs.h,v 1.16 1997/10/10 01:53:17 fvdl Exp $ */
/* $NetBSD: nfs.h,v 1.17 1997/10/19 01:46:15 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
@ -328,7 +328,7 @@ TAILQ_HEAD(, nfsreq) nfs_reqq;
(&nfsnodehashtbl[(fhsum) & nfsnodehash])
#ifndef NFS_DIRHASHSIZ
#define NFS_DIRHASHSIZ 32
#define NFS_DIRHASHSIZ 64
#endif
#define NFSDIRHASH(np, off) \
(&np->n_dircache[(nfs_dirhash((off)) & nfsdirhashmask)])
@ -340,11 +340,11 @@ TAILQ_HEAD(, nfsreq) nfs_reqq;
*((off_t *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t))) = off
#define NFS_GETCOOKIE(dp) \
(*((off_t *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t))))
#define NFS_MARKCACHED(dp, val) \
*((int *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t) - \
#define NFS_STASHCOOKIE32(dp, val) \
*((u_int32_t *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t) - \
sizeof (int))) = val
#define NFS_ISCACHED(dp) \
(*((int *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t) - \
#define NFS_GETCOOKIE32(dp) \
(*((u_int32_t *)((caddr_t)(dp) + (dp)->d_reclen - sizeof (off_t) - \
sizeof (int))))
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bio.c,v 1.34 1997/10/10 01:53:18 fvdl Exp $ */
/* $NetBSD: nfs_bio.c,v 1.35 1997/10/19 01:46:20 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -82,7 +82,7 @@ nfs_bioread(vp, uio, ioflag, cred, cflag)
struct vattr vattr;
struct proc *p;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct nfsdircache *ndp = NULL;
struct nfsdircache *ndp = NULL, *nndp = NULL;
daddr_t lbn, bn, rabn;
caddr_t baddr, ep, edp;
int got_buf = 0, nra, error = 0, n = 0, on = 0, not_readin, en, enn;
@ -128,7 +128,8 @@ nfs_bioread(vp, uio, ioflag, cred, cflag)
if (vp->v_type != VREG) {
if (vp->v_type != VDIR)
panic("nfs: bioread, not dir");
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
np->n_direofoffset = 0;
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@ -143,8 +144,10 @@ nfs_bioread(vp, uio, ioflag, cred, cflag)
if (error)
return (error);
if (np->n_mtime != vattr.va_mtime.tv_sec) {
if (vp->v_type == VDIR)
nfs_invaldircache(vp);
if (vp->v_type == VDIR) {
nfs_invaldircache(vp, 0);
np->n_direofoffset = 0;
}
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
@ -167,16 +170,19 @@ nfs_bioread(vp, uio, ioflag, cred, cflag)
if (np->n_lrev != np->n_brev ||
(np->n_flag & NQNFSNONCACHE) ||
((np->n_flag & NMODIFIED) && vp->v_type == VDIR)) {
if (vp->v_type == VDIR)
nfs_invaldircache(vp);
if (vp->v_type == VDIR) {
nfs_invaldircache(vp, 0);
np->n_direofoffset = 0;
}
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
if (error)
return (error);
np->n_brev = np->n_lrev;
}
} else if (vp->v_type == VDIR && (np->n_flag & NMODIFIED)) {
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
np->n_direofoffset = 0;
if (error)
return (error);
}
@ -304,20 +310,37 @@ again:
case VDIR:
diragain:
nfsstats.biocache_readdirs++;
ndp = nfs_searchdircache(vp, uio->uio_offset,
(nmp->nm_flag & NFSMNT_XLATECOOKIE), 0);
if (!ndp) {
/*
* We've been handed a cookie that is not
* in the cache. If we're not translating
* 32 <-> 64, it may be a value that was
* flushed out of the cache because it grew
* too big. Let the server judge if it's
* valid or not. In the translation case,
* we have no way of validating this value,
* so punt.
*/
if (nmp->nm_flag & NFSMNT_XLATECOOKIE)
return (EINVAL);
ndp = nfs_enterdircache(vp, uio->uio_offset,
uio->uio_offset, 0, 0);
}
if (uio->uio_offset != 0 &&
uio->uio_offset == np->n_direofoffset)
ndp->dc_cookie == np->n_direofoffset) {
nfsstats.direofcache_hits++;
return (0);
ndp = nfs_lookdircache(vp, uio->uio_offset, 0, 0, 1);
#ifdef DIAGNOSTIC
if (!ndp)
panic("nfs_bioread: bad dir cache");
#endif
}
bp = nfs_getcacheblk(vp, ndp->dc_blkno, NFS_DIRBLKSIZ, p);
if (!bp)
return (EINTR);
if ((bp->b_flags & B_DONE) == 0) {
bp->b_flags |= B_READ;
bp->b_dcookie = ndp->dc_cookie;
bp->b_dcookie = ndp->dc_blkcookie;
error = nfs_doio(bp, cred, p);
if (error) {
/*
@ -327,7 +350,7 @@ diragain:
*/
brelse(bp);
if (error == NFSERR_BAD_COOKIE) {
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
nfs_vinvalbuf(vp, 0, cred, p, 1);
error = EINVAL;
}
@ -358,7 +381,7 @@ diragain:
* the server).
*/
if ((caddr_t)dp >= edp || (caddr_t)dp + dp->d_reclen > edp ||
(en > 0 && NFS_GETCOOKIE(pdp) != uio->uio_offset)) {
(en > 0 && NFS_GETCOOKIE(pdp) != ndp->dc_cookie)) {
#ifdef DEBUG
printf("invalid cache: %p %p %p len %u off %lx %lx\n",
pdp, dp, edp, dp->d_reclen,
@ -366,7 +389,7 @@ diragain:
(unsigned long)NFS_GETCOOKIE(pdp));
#endif
brelse(bp);
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
nfs_vinvalbuf(vp, 0, cred, p, 0);
goto diragain;
}
@ -400,9 +423,14 @@ diragain:
*/
while ((caddr_t)dp < ep && (caddr_t)dp + dp->d_reclen <= ep) {
if (cflag & NFSBIO_CACHECOOKIES)
nfs_lookdircache(vp, NFS_GETCOOKIE(pdp), enn,
bp->b_lblkno, 1);
if (cflag & NFSBIO_CACHECOOKIES) {
nndp = nfs_enterdircache(vp, NFS_GETCOOKIE(pdp),
ndp->dc_blkcookie, enn, bp->b_lblkno);
if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
NFS_STASHCOOKIE32(pdp,
nndp->dc_cookie32);
}
}
pdp = dp;
dp = (struct dirent *)((caddr_t)dp + dp->d_reclen);
enn++;
@ -417,10 +445,27 @@ diragain:
if ((on + n) < bp->b_validend) {
curoff = NFS_GETCOOKIE(pdp);
nfs_lookdircache(vp, curoff, enn, bp->b_lblkno, 1);
nndp = nfs_enterdircache(vp, curoff, ndp->dc_blkcookie,
enn, bp->b_lblkno);
if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
NFS_STASHCOOKIE32(pdp, nndp->dc_cookie32);
curoff = nndp->dc_cookie32;
}
} else
curoff = bp->b_dcookie;
/*
* Always cache the entry for the next block,
* so that readaheads can use it.
*/
nndp = nfs_enterdircache(vp, bp->b_dcookie, bp->b_dcookie, 0,0);
if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
if (curoff == bp->b_dcookie) {
NFS_STASHCOOKIE32(pdp, nndp->dc_cookie32);
curoff = nndp->dc_cookie32;
}
}
n = ((caddr_t)pdp + pdp->d_reclen) - (bp->b_data + on);
/*
@ -430,12 +475,11 @@ diragain:
*/
if (nfs_numasync > 0 && nmp->nm_readahead > 0 &&
np->n_direofoffset == 0 && !(np->n_flag & NQNFSNONCACHE)) {
ndp = nfs_lookdircache(vp, bp->b_dcookie, 0, 0, 1);
rabp = nfs_getcacheblk(vp, ndp->dc_blkno,
rabp = nfs_getcacheblk(vp, nndp->dc_blkno,
NFS_DIRBLKSIZ, p);
if (rabp) {
if ((rabp->b_flags & (B_DONE | B_DELWRI)) == 0) {
rabp->b_dcookie = ndp->dc_cookie;
rabp->b_dcookie = nndp->dc_cookie;
rabp->b_flags |= (B_READ | B_ASYNC);
if (nfs_asyncio(rabp, cred)) {
rabp->b_flags |= B_INVAL;
@ -973,7 +1017,7 @@ nfs_doio(bp, cr, p)
NQNFS_CKINVALID(vp, np, ND_READ) &&
np->n_lrev != np->n_brev) ||
(!(nmp->nm_flag & NFSMNT_NQNFS) &&
np->n_mtime != np->n_vattr.va_mtime.tv_sec))) {
np->n_mtime != np->n_vattr->va_mtime.tv_sec))) {
uprintf("Process killed due to text file modification\n");
psignal(p, SIGKILL);
p->p_holdcnt++;

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_node.c,v 1.23 1997/10/10 01:53:19 fvdl Exp $ */
/* $NetBSD: nfs_node.c,v 1.24 1997/10/19 01:46:24 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -155,6 +155,9 @@ loop:
np->n_fhp = &np->n_fh;
bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize);
np->n_fhsize = fhsize;
MALLOC(np->n_vattr, struct vattr *, sizeof (struct vattr),
M_NFSNODE, M_WAITOK);
bzero(np->n_vattr, sizeof (struct vattr));
lockmgr(&nfs_hashlock, LK_RELEASE, 0, p);
*npp = np;
return (0);
@ -257,13 +260,14 @@ nfs_reclaim(v)
* this nfs node.
*/
if (vp->v_type == VDIR && np->n_dircache) {
nfs_invaldircache(vp);
nfs_invaldircache(vp, 1);
FREE(np->n_dircache, M_NFSDIROFF);
}
if (np->n_fhsize > NFS_SMALLFH) {
FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
}
FREE(np->n_vattr, M_NFSNODE);
cache_purge(vp);
FREE(vp->v_data, M_NFSNODE);
vp->v_data = (void *)0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_nqlease.c,v 1.21 1997/10/10 01:53:20 fvdl Exp $ */
/* $NetBSD: nfs_nqlease.c,v 1.22 1997/10/19 01:46:27 fvdl Exp $ */
/*
* Copyright (c) 1992, 1993
@ -1068,7 +1068,7 @@ nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) {
if (np->n_flag & NQNFSEVICTED) {
if (vp->v_type == VDIR)
nfs_invaldircache(vp);
nfs_invaldircache(vp,0);
cache_purge(vp);
(void) nfs_vinvalbuf(vp,
V_SAVE, cred, p, 0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_subs.c,v 1.48 1997/10/11 02:09:48 fvdl Exp $ */
/* $NetBSD: nfs_subs.c,v 1.49 1997/10/19 01:46:32 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -1120,6 +1120,41 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
return (0);
}
/*
* Directory caching routines. They work as follows:
* - a cache is maintained per VDIR nfsnode.
* - for each offset cookie that is exported to userspace, and can
* thus be thrown back at us as an offset to VOP_READDIR, store
* information in the cache.
* - cached are:
* - cookie itself
* - blocknumber (essentially just a search key in the buffer cache)
* - entry number in block.
* - offset cookie of block in which this entry is stored
* - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
* - entries are looked up in a hash table
* - also maintained is an LRU list of entries, used to determine
* which ones to delete if the cache grows too large.
* - if 32 <-> 64 translation mode is requested for a filesystem,
* the cache also functions as a translation table
* - in the translation case, invalidating the cache does not mean
* flushing it, but just marking entries as invalid, except for
* the <64bit cookie, 32bitcookie> pair which is still valid, to
* still be able to use the cache as a translation table.
* - 32 bit cookies are uniquely created by combining the hash table
* entry value, and one generation count per hash table entry,
* incremented each time an entry is appended to the chain.
* - the cache is invalidated each time a direcory is modified
* - sanity checks are also done; if an entry in a block turns
* out not to have a matching cookie, the cache is invalidated
* and a new block starting from the wanted offset is fetched from
* the server.
* - directory entries as read from the server are extended to contain
* the 64bit and, optionally, the 32bit cookies, for sanity checking
* the cache and exporting them to userspace through the cookie
* argument to VOP_READDIR.
*/
u_long
nfs_dirhash(off)
off_t off;
@ -1134,34 +1169,142 @@ nfs_dirhash(off)
return sum;
}
void
nfs_initdircache(vp)
struct vnode *vp;
{
struct nfsnode *np = VTONFS(vp);
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
np->n_dircachesize = 0;
np->n_dblkno = 1;
np->n_dircache =
hashinit(NFS_DIRHASHSIZ, M_NFSDIROFF, &nfsdirhashmask);
TAILQ_INIT(&np->n_dirchain);
if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
MALLOC(np->n_dirgens, unsigned *,
NFS_DIRHASHSIZ * sizeof (unsigned), M_NFSDIROFF,
M_WAITOK);
bzero((caddr_t)np->n_dirgens,
NFS_DIRHASHSIZ * sizeof (unsigned));
}
}
static struct nfsdircache dzero = {0, 0, {0, 0}, {0, 0}, 0, 0, 0};
struct nfsdircache *
nfs_lookdircache(vp, off, en, blkno, alloc)
nfs_searchdircache(vp, off, do32, hashent)
struct vnode *vp;
off_t off;
int do32;
int *hashent;
{
struct nfsdirhashhead *ndhp;
struct nfsdircache *ndp = NULL;
struct nfsnode *np = VTONFS(vp);
unsigned ent;
/*
* Zero is always a valid cookie.
*/
if (off == 0)
return &dzero;
/*
* We use a 32bit cookie as search key, directly reconstruct
* the hashentry. Else use the hashfunction.
*/
if (do32) {
ent = (u_int32_t)off >> 24;
if (ent >= NFS_DIRHASHSIZ)
return NULL;
ndhp = &np->n_dircache[ent];
} else {
ndhp = NFSDIRHASH(np, off);
}
if (hashent)
*hashent = (int)(ndhp - np->n_dircache);
if (do32) {
for (ndp = ndhp->lh_first; ndp; ndp = ndp->dc_hash.le_next) {
if (ndp->dc_cookie32 == (u_int32_t)off) {
/*
* An invalidated entry will become the
* start of a new block fetched from
* the server.
*/
if (ndp->dc_blkno == -1) {
ndp->dc_blkcookie = ndp->dc_cookie;
ndp->dc_blkno = np->n_dblkno++;
ndp->dc_entry = 0;
}
break;
}
}
} else {
for (ndp = ndhp->lh_first; ndp; ndp = ndp->dc_hash.le_next)
if (ndp->dc_cookie == off)
break;
}
return ndp;
}
struct nfsdircache *
nfs_enterdircache(vp, off, blkoff, en, blkno)
struct vnode *vp;
off_t off, blkoff;
daddr_t blkno;
int en, alloc;
int en;
{
struct nfsnode *np = VTONFS(vp);
struct nfsdirhashhead *ndhp;
struct nfsdircache *ndp, *first;
struct nfsdircache *ndp = NULL, *first;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
int hashent, gen, overwrite;
if (!np->n_dircache) {
np->n_dircachesize = 0;
np->n_dircache =
hashinit(NFS_DIRHASHSIZ, M_NFSDIROFF, &nfsdirhashmask);
TAILQ_INIT(&np->n_dirchain);
if (!np->n_dircache)
/*
* XXX would like to do this in nfs_nget but vtype
* isn't known at that time.
*/
nfs_initdircache(vp);
ndp = nfs_searchdircache(vp, off, 0, &hashent);
if (ndp && ndp->dc_blkno != -1) {
/*
* Overwriting an old entry. Check if it's the same.
* If so, just return. If not, remove the old entry.
*/
if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
return ndp;
TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
LIST_REMOVE(ndp, dc_hash);
FREE(ndp, M_NFSDIROFF);
ndp = 0;
}
ndhp = NFSDIRHASH(np, off);
for (ndp = ndhp->lh_first; ndp; ndp = ndp->dc_hash.le_next)
if (ndp->dc_cookie == off)
break;
ndhp = &np->n_dircache[hashent];
if (!alloc || ndp)
return ndp;
MALLOC(ndp, struct nfsdircache *, sizeof (*ndp), M_NFSDIROFF, M_WAITOK);
ndp->dc_cookie = off;
if (!ndp) {
MALLOC(ndp, struct nfsdircache *, sizeof (*ndp), M_NFSDIROFF,
M_WAITOK);
overwrite = 0;
if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
/*
* We're allocating a new entry, so bump the
* generation number.
*/
gen = ++np->n_dirgens[hashent];
if (gen == 0) {
np->n_dirgens[hashent]++;
gen++;
}
ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
}
} else
overwrite = 1;
/*
* If the entry number is 0, we are at the start of a new block, so
@ -1171,8 +1314,14 @@ nfs_lookdircache(vp, off, en, blkno, alloc)
ndp->dc_blkno = np->n_dblkno++;
else
ndp->dc_blkno = blkno;
ndp->dc_cookie = off;
ndp->dc_blkcookie = blkoff;
ndp->dc_entry = en;
if (overwrite)
return ndp;
/*
* If the maximum directory cookie cache size has been reached
* for this node, take one off the front. The idea is that
@ -1194,11 +1343,13 @@ nfs_lookdircache(vp, off, en, blkno, alloc)
}
void
nfs_invaldircache(vp)
nfs_invaldircache(vp, forcefree)
struct vnode *vp;
int forcefree;
{
struct nfsnode *np = VTONFS(vp);
struct nfsdircache *ndp = NULL;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
#ifdef DIAGNOSTIC
if (vp->v_type != VDIR)
@ -1208,14 +1359,23 @@ nfs_invaldircache(vp)
if (!np->n_dircache)
return;
while ((ndp = np->n_dirchain.tqh_first)) {
TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
LIST_REMOVE(ndp, dc_hash);
FREE(ndp, M_NFSDIROFF);
if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
while ((ndp = np->n_dirchain.tqh_first)) {
TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
LIST_REMOVE(ndp, dc_hash);
FREE(ndp, M_NFSDIROFF);
}
np->n_dircachesize = 0;
if (forcefree && np->n_dirgens) {
FREE(np->n_dirgens, M_NFSDIROFF);
}
} else {
for (ndp = np->n_dirchain.tqh_first; ndp;
ndp = ndp->dc_chain.tqe_next)
ndp->dc_blkno = -1;
}
np->n_dblkno = 0;
np->n_dircachesize = 0;
np->n_dblkno = 1;
}
/*
@ -1420,7 +1580,7 @@ nfs_loadattrcache(vpp, fp, vaper)
}
np->n_mtime = mtime.tv_sec;
}
vap = &np->n_vattr;
vap = np->n_vattr;
vap->va_type = vtyp;
vap->va_mode = vmode & ALLPERMS;
vap->va_rdev = (dev_t)rdev;
@ -1507,7 +1667,7 @@ nfs_getattrcache(vp, vaper)
return (ENOENT);
}
nfsstats.attrcache_hits++;
vap = &np->n_vattr;
vap = np->n_vattr;
if (vap->va_size != np->n_size) {
if (vap->va_type == VREG) {
if (np->n_flag & NMODIFIED) {
@ -1588,7 +1748,7 @@ nfs_cookieheuristic(vp, flagp, p, cred)
if (dp->d_fileno != 0 && len >= dp->d_reclen) {
if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
*flagp |= NFSMNT_SWAPCOOKIE;
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
nfs_vinvalbuf(vp, 0, cred, p, 1);
}
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_var.h,v 1.10 1997/10/10 01:53:28 fvdl Exp $ */
/* $NetBSD: nfs_var.h,v 1.11 1997/10/19 01:46:36 fvdl Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
@ -231,9 +231,10 @@ int nfsm_disct __P((struct mbuf **, caddr_t *, int, int, caddr_t *));
int nfs_adv __P((struct mbuf **, caddr_t *, int, int));
int nfsm_strtmbuf __P((struct mbuf **, char **, const char *, long));
u_long nfs_dirhash __P((off_t));
struct nfsdircache *nfs_lookdircache __P((struct vnode *, off_t, int, daddr_t,
int));
void nfs_invaldircache __P((struct vnode *));
void nfs_initdircache __P((struct vnode *));
struct nfsdircache *nfs_searchdircache __P((struct vnode *, off_t, int, int *));
struct nfsdircache *nfs_enterdircache __P((struct vnode *, off_t, off_t, daddr_t, int));
void nfs_invaldircache __P((struct vnode *, int));
void nfs_init __P((void));
int nfsm_loadattrcache __P((struct vnode **, struct mbuf **, caddr_t *,
struct vattr *));
@ -256,7 +257,6 @@ int nfsrv_setpublicfs __P((struct mount *, struct netexport *,
struct export_args *));
int nfs_ispublicfh __P((fhandle_t *));
int netaddr_match __P((int, union nethostaddr *, struct mbuf *));
void nfs_invaldircache __P((struct vnode *));
void nfs_clearcommit __P((struct mount *));
int nfsrv_errmap __P((struct nfsrv_descript *, int));
void nfsrvw_sort __P((gid_t *, int));

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_vfsops.c,v 1.65 1997/10/10 01:53:29 fvdl Exp $ */
/* $NetBSD: nfs_vfsops.c,v 1.66 1997/10/19 01:46:40 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993, 1995
@ -471,6 +471,13 @@ nfs_decode_args(nmp, argp)
if (argp->sotype == SOCK_STREAM)
argp->flags &= ~NFSMNT_NOCONN;
/*
* Cookie translation is not needed for v2, silently ignore it.
*/
if ((argp->flags & (NFSMNT_XLATECOOKIE|NFSMNT_NFSV3)) ==
NFSMNT_XLATECOOKIE)
argp->flags &= ~NFSMNT_XLATECOOKIE;
/* Re-bind if rsrvd port requested and wasn't on one */
adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT)
&& (argp->flags & NFSMNT_RESVPORT);
@ -614,10 +621,12 @@ nfs_mount(mp, path, data, ndp, p)
return (EIO);
/*
* When doing an update, we can't change from or to
* v3 and/or nqnfs.
* v3 and/or nqnfs, or change cookie translation
*/
args.flags = (args.flags & ~(NFSMNT_NFSV3|NFSMNT_NQNFS)) |
(nmp->nm_flag & (NFSMNT_NFSV3|NFSMNT_NQNFS));
args.flags = (args.flags &
~(NFSMNT_NFSV3|NFSMNT_NQNFS|NFSMNT_XLATECOOKIE)) |
(nmp->nm_flag &
(NFSMNT_NFSV3|NFSMNT_NQNFS|NFSMNT_XLATECOOKIE));
nfs_decode_args(nmp, &args);
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_vnops.c,v 1.84 1997/10/17 00:00:41 christos Exp $ */
/* $NetBSD: nfs_vnops.c,v 1.85 1997/10/19 01:46:47 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -433,7 +433,7 @@ nfs_open(v)
(void) vnode_pager_uncache(vp);
np->n_attrstamp = 0;
if (vp->v_type == VDIR) {
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
np->n_direofoffset = 0;
}
error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
@ -446,7 +446,7 @@ nfs_open(v)
return (error);
if (np->n_mtime != vattr.va_mtime.tv_sec) {
if (vp->v_type == VDIR) {
nfs_invaldircache(vp);
nfs_invaldircache(vp, 0);
np->n_direofoffset = 0;
}
if ((error = nfs_vinvalbuf(vp, V_SAVE,
@ -642,7 +642,7 @@ nfs_setattr(v)
return (error);
}
tsize = np->n_size;
np->n_size = np->n_vattr.va_size = vap->va_size;
np->n_size = np->n_vattr->va_size = vap->va_size;
}
} else if ((vap->va_mtime.tv_sec != VNOVAL ||
vap->va_atime.tv_sec != VNOVAL) &&
@ -652,7 +652,7 @@ nfs_setattr(v)
return (error);
error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
if (error && vap->va_size != VNOVAL) {
np->n_size = np->n_vattr.va_size = tsize;
np->n_size = np->n_vattr->va_size = tsize;
vnode_pager_setsize(vp, np->n_size);
}
return (error);
@ -918,7 +918,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;
np->n_ctime = np->n_vattr->va_ctime.tv_sec;
cache_enter(dvp, newvp, cnp);
}
*vpp = newvp;
@ -928,7 +928,7 @@ dorpc:
cnp->cn_nameiop != CREATE) {
if (VTONFS(dvp)->n_nctime == 0)
VTONFS(dvp)->n_nctime =
VTONFS(dvp)->n_vattr.va_mtime.tv_sec;
VTONFS(dvp)->n_vattr->va_mtime.tv_sec;
cache_enter(dvp, NULL, cnp);
}
if (newvp != NULLVP)
@ -1182,7 +1182,7 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
} else
nfsm_loadattr(vp, (struct vattr *)0);
if (wccflag)
VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr->va_mtime.tv_sec;
m_freem(mrep);
if (error)
break;
@ -1959,11 +1959,10 @@ nfs_readdir(v)
int a_ncookies;
} */ *ap = v;
register struct vnode *vp = ap->a_vp;
register struct nfsnode *np = VTONFS(vp);
register struct uio *uio = ap->a_uio;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
char *base = uio->uio_iov->iov_base;
int tresid, error;
struct vattr vattr;
size_t count, lost;
if (vp->v_type != VDIR)
@ -1974,25 +1973,6 @@ nfs_readdir(v)
if (count <= 0)
return (EINVAL);
/*
* First, check for hit on the EOF offset cache
*/
if (np->n_direofoffset != 0 && uio->uio_offset == np->n_direofoffset &&
(np->n_flag & NMODIFIED) == 0) {
if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
if (NQNFS_CKCACHABLE(vp, ND_READ)) {
nfsstats.direofcache_hits++;
*ap->a_eofflag = 1;
return (0);
}
} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
np->n_mtime == vattr.va_mtime.tv_sec) {
nfsstats.direofcache_hits++;
*ap->a_eofflag = 1;
return (0);
}
}
/*
* Call nfs_bioread() to do the real work.
*/
@ -2009,7 +1989,7 @@ nfs_readdir(v)
if (!error && ap->a_cookies) {
struct dirent *dp;
off_t *cookies = ap->a_cookies, *offp;
off_t *cookies = ap->a_cookies;
int ncookies = ap->a_ncookies;
/*
@ -2023,9 +2003,10 @@ nfs_readdir(v)
dp = (struct dirent *) base;
if (dp->d_reclen == 0)
break;
offp = (off_t *)((caddr_t)dp + dp->d_reclen -
sizeof (off_t));
*(cookies++) = NFS_GETCOOKIE(dp);
if (nmp->nm_flag & NFSMNT_XLATECOOKIE)
*(cookies++) = (off_t)NFS_GETCOOKIE32(dp);
else
*(cookies++) = NFS_GETCOOKIE(dp);
base += dp->d_reclen;
}
uio->uio_resid += (uio->uio_iov->iov_base - base);
@ -2059,7 +2040,7 @@ nfs_readdirrpc(vp, uiop, cred)
struct nfsnode *dnp = VTONFS(vp);
u_quad_t fileno;
int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
int attrflag;
int attrflag, nrpcs = 0;
int v3 = NFS_ISV3(vp);
nfsquad_t cookie;
@ -2078,6 +2059,16 @@ nfs_readdirrpc(vp, uiop, cred)
* The stopping criteria is EOF or buffer full.
*/
while (more_dirs && bigenough) {
/*
* Heuristic: don't bother to do another RPC to further
* fill up this block if there is not much room left. (< 50%
* of the readdir RPC size). This wastes some buffer space
* but can save up to 50% in RPC calls.
*/
if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) {
bigenough = 0;
break;
}
nfsstats.rpccnt[NFSPROC_READDIR]++;
nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
NFSX_READDIR(v3));
@ -2099,6 +2090,7 @@ nfs_readdirrpc(vp, uiop, cred)
}
*tl = txdr_unsigned(nmp->nm_readdirsize);
nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
nrpcs++;
if (v3) {
nfsm_postop_attr(vp, attrflag);
if (!error) {
@ -2254,7 +2246,7 @@ nfs_readdirplusrpc(vp, uiop, cred)
nfsfh_t *fhp;
u_quad_t fileno;
int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
int attrflag, fhsize;
int attrflag, fhsize, nrpcs = 0;
struct nfs_fattr fattr, *fp;
#ifdef DIAGNOSTIC
@ -2270,6 +2262,10 @@ nfs_readdirplusrpc(vp, uiop, cred)
* The stopping criteria is EOF or buffer full.
*/
while (more_dirs && bigenough) {
if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) {
bigenough = 0;
break;
}
nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
NFSX_FH(1) + 6 * NFSX_UNSIGNED);
@ -2291,6 +2287,7 @@ nfs_readdirplusrpc(vp, uiop, cred)
m_freem(mrep);
goto nfsmout;
}
nrpcs++;
nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
dnp->n_cookieverf.nfsuquad[0] = *tl++;
dnp->n_cookieverf.nfsuquad[1] = *tl++;
@ -2383,7 +2380,7 @@ nfs_readdirplusrpc(vp, uiop, cred)
if (!error) {
nfs_loadattrcache(&newvp, &fattr, 0);
dp->d_type =
IFTODT(VTTOIF(np->n_vattr.va_type));
IFTODT(VTTOIF(np->n_vattr->va_type));
ndp->ni_vp = newvp;
cnp->cn_hash = 0;
for (hcp = cnp->cn_nameptr, i = 1; i <= len;
@ -2983,7 +2980,7 @@ nfs_print(v)
register struct nfsnode *np = VTONFS(vp);
printf("tag VT_NFS, fileid %ld fsid 0x%lx",
np->n_vattr.va_fileid, np->n_vattr.va_fsid);
np->n_vattr->va_fileid, np->n_vattr->va_fsid);
#ifdef FIFO
if (vp->v_type == VFIFO)
fifo_printinfo(vp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfsnode.h,v 1.23 1997/10/16 23:59:34 christos Exp $ */
/* $NetBSD: nfsnode.h,v 1.24 1997/10/19 01:46:51 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -78,11 +78,13 @@ LIST_HEAD(nfsdirhashhead, nfsdircache);
TAILQ_HEAD(nfsdirchainhead, nfsdircache);
struct nfsdircache {
LIST_ENTRY(nfsdircache) dc_hash;
TAILQ_ENTRY(nfsdircache) dc_chain;
off_t dc_cookie;
daddr_t dc_blkno;
int dc_entry;
off_t dc_cookie; /* Own offset (key) */
off_t dc_blkcookie; /* Offset of block we're in */
LIST_ENTRY(nfsdircache) dc_hash; /* Hash chain */
TAILQ_ENTRY(nfsdircache) dc_chain; /* Least recently entered chn */
u_int32_t dc_cookie32; /* Key for 64<->32 xlate case */
daddr_t dc_blkno; /* Number of block we're in */
int dc_entry; /* Entry number within block */
};
@ -100,39 +102,40 @@ struct nfsdircache {
* be well aligned and, therefore, tightly packed.
*/
struct nfsnode {
LIST_ENTRY(nfsnode) n_hash; /* Hash chain */
CIRCLEQ_ENTRY(nfsnode) n_timer; /* Nqnfs timer chain */
u_quad_t n_size; /* Current size of file */
u_quad_t n_brev; /* Modify rev when cached */
u_quad_t n_lrev; /* Modify rev for lease */
struct vattr n_vattr; /* Vnode attribute cache */
time_t n_attrstamp; /* Attr. cache timestamp */
time_t n_mtime; /* Prev modify time. */
time_t n_ctime; /* Prev create time. */
time_t n_nctime; /* Last neg cache entry (dir) */
time_t n_expiry; /* Lease expiry time */
nfsfh_t *n_fhp; /* NFS File Handle */
struct vnode *n_vnode; /* associated vnode */
struct lockf *n_lockf; /* Locking record of file */
int n_error; /* Save write error value */
union {
struct timespec nf_atim; /* Special file times */
nfsuint64 nd_cookieverf; /* Cookie verifier (dir only) */
} n_un1;
union {
struct timespec nf_mtim;
off_t nd_direof; /* Dir. EOF offset cache */
} n_un2;
union {
struct timespec nf_atim; /* Special file times */
nfsuint64 nd_cookieverf; /* Cookie verifier (dir only) */
} n_un1;
union {
struct sillyrename *nf_silly; /* Ptr to silly rename struct */
struct nfsdirhashhead *nd_dircache;
} n_un3;
LIST_ENTRY(nfsnode) n_hash; /* Hash chain */
CIRCLEQ_ENTRY(nfsnode) n_timer; /* Nqnfs timer chain */
struct nfsdirchainhead n_dirchain; /* Chain of dir cookies */
nfsfh_t *n_fhp; /* NFS File Handle */
struct vattr *n_vattr; /* Vnode attribute cache */
struct vnode *n_vnode; /* associated vnode */
struct lockf *n_lockf; /* Locking record of file */
unsigned *n_dirgens; /* 32<->64bit xlate gen. no. */
time_t n_attrstamp; /* Attr. cache timestamp */
time_t n_mtime; /* Prev modify time. */
time_t n_ctime; /* Prev create time. */
time_t n_nctime; /* Last neg cache entry (dir) */
time_t n_expiry; /* Lease expiry time */
daddr_t n_dblkno; /* To keep faked dir blkno */
unsigned n_dircachesize; /* Size of dir cookie cache */
int n_error; /* Save write error value */
short n_fhsize; /* size in bytes, of fh */
short n_flag; /* Flag for locking.. */
nfsfh_t n_fh; /* Small File Handle */
daddr_t n_dblkno; /* To keep faked dir blkno */
unsigned n_dircachesize; /* Size of dir cookie cache */
struct nfsdirchainhead n_dirchain; /* Chain of dir cookies */
};
#define n_atim n_un1.nf_atim

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfsproto.h,v 1.6 1997/10/17 08:10:22 fvdl Exp $ */
/* $NetBSD: nfsproto.h,v 1.7 1997/10/19 01:46:54 fvdl Exp $ */
/*
* Copyright (c) 1989, 1993
@ -252,7 +252,7 @@ typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5,
* NFS_SMALLFH should be in the range of 32 to 64 and be divisible by 4.
*/
#ifndef NFS_SMALLFH
#define NFS_SMALLFH 32
#define NFS_SMALLFH 64
#endif
union nfsfh {
fhandle_t fh_generic;