diff options
author | mav <mav@FreeBSD.org> | 2012-09-21 13:25:50 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2012-09-21 13:25:50 +0000 |
commit | 4415d2bdfd228486b8c7a38e43b084b5675fe3b5 (patch) | |
tree | 085780028ddfd6fd0473118cff4698dadbe40f4c /lib/libstand/nfs.c | |
parent | b9ef0ec7d18b64fc36bce6b12d77e0f13d87bfc2 (diff) | |
download | FreeBSD-src-4415d2bdfd228486b8c7a38e43b084b5675fe3b5.zip FreeBSD-src-4415d2bdfd228486b8c7a38e43b084b5675fe3b5.tar.gz |
Make nfs_readdir() more careful about using response data, cached in global
buffer. For now it fixes bug when following `ls` command will return data
from previous one aborted by pager. Also it should allow to read several
directories same time, for example, for recursive tracerse.
Diffstat (limited to 'lib/libstand/nfs.c')
-rw-r--r-- | lib/libstand/nfs.c | 44 |
1 files changed, 24 insertions, 20 deletions
diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c index c6fe382..bdca522 100644 --- a/lib/libstand/nfs.c +++ b/lib/libstand/nfs.c @@ -181,6 +181,7 @@ struct nfs_iodesc { uint32_t fhsize; u_char fh[NFS_V3MAXFHSIZE]; struct nfsv3_fattrs fa; /* all in network order */ + uint64_t cookie; }; #endif /* OLD_NFSV2 */ @@ -755,6 +756,7 @@ nfs_readdir(struct open_file *f, struct dirent *d) struct nfs_readdir_data *rd; struct nfs_readdir_off *roff = NULL; static char *buf; + static struct nfs_iodesc *pfp = NULL; static n_long cookie = 0; size_t cc; n_long eof; @@ -768,13 +770,14 @@ nfs_readdir(struct open_file *f, struct dirent *d) u_char d[NFS_READDIRSIZE]; } rdata; - if (cookie == 0) { + if (fp != pfp || fp->off != cookie) { + pfp = NULL; refill: args = &sdata.d; bzero(args, sizeof(*args)); bcopy(fp->fh, args->fh, NFS_FHSIZE); - args->cookie = htonl(cookie); + args->cookie = htonl(fp->off); args->count = htonl(NFS_READDIRSIZE); cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, @@ -784,6 +787,8 @@ nfs_readdir(struct open_file *f, struct dirent *d) roff = (struct nfs_readdir_off *)buf; if (ntohl(roff->cookie) != 0) return EIO; + pfp = fp; + cookie = fp->off; } roff = (struct nfs_readdir_off *)buf; @@ -804,7 +809,7 @@ nfs_readdir(struct open_file *f, struct dirent *d) buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); roff = (struct nfs_readdir_off *)buf; - cookie = ntohl(roff->cookie); + fp->off = cookie = ntohl(roff->cookie); return 0; } #else /* !OLD_NFSV2 */ @@ -1260,6 +1265,7 @@ out: #endif if (!error) { currfd->off = 0; + currfd->cookie = 0; f->f_fsdata = (void *)currfd; return (0); } @@ -1398,11 +1404,9 @@ nfs_readdir(struct open_file *f, struct dirent *d) struct nfsv3_readdir_repl *repl; struct nfsv3_readdir_entry *rent; static char *buf; - static uint32_t cookie0 = 0; - static uint32_t cookie1 = 0; + static struct nfs_iodesc *pfp = NULL; + static uint64_t cookie = 0; size_t cc; - static uint32_t cookieverf0 = 0; - static uint32_t cookieverf1 = 0; int pos; struct args { @@ -1418,7 +1422,8 @@ nfs_readdir(struct open_file *f, struct dirent *d) u_char d[NFS_READDIRSIZE]; } rdata; - if (cookie0 == 0 && cookie1 == 0) { + if (fp != pfp || fp->off != cookie) { + pfp = NULL; refill: args = &sdata.d; bzero(args, sizeof(*args)); @@ -1426,10 +1431,10 @@ nfs_readdir(struct open_file *f, struct dirent *d) args->fhsize = htonl(fp->fhsize); bcopy(fp->fh, args->fhpluscookie, fp->fhsize); pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); - args->fhpluscookie[pos++] = cookie0; - args->fhpluscookie[pos++] = cookie1; - args->fhpluscookie[pos++] = cookieverf0; - args->fhpluscookie[pos++] = cookieverf1; + args->fhpluscookie[pos++] = htonl(fp->off >> 32); + args->fhpluscookie[pos++] = htonl(fp->off); + args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); + args->fhpluscookie[pos++] = htonl(fp->cookie); args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, @@ -1440,8 +1445,10 @@ nfs_readdir(struct open_file *f, struct dirent *d) repl = (struct nfsv3_readdir_repl *)buf; if (repl->errno != 0) return (ntohl(repl->errno)); - cookieverf0 = repl->cookiev0; - cookieverf1 = repl->cookiev1; + pfp = fp; + cookie = fp->off; + fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | + ntohl(repl->cookiev1); buf += sizeof (struct nfsv3_readdir_repl); } rent = (struct nfsv3_readdir_entry *)buf; @@ -1449,10 +1456,7 @@ nfs_readdir(struct open_file *f, struct dirent *d) if (rent->follows == 0) { /* fid0 is actually eof */ if (rent->fid0 != 0) { - cookie0 = 0; - cookie1 = 0; - cookieverf0 = 0; - cookieverf1 = 0; + cookie = 0; return (ENOENT); } goto refill; @@ -1463,8 +1467,8 @@ nfs_readdir(struct open_file *f, struct dirent *d) d->d_name[d->d_namlen] = '\0'; pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); - cookie0 = rent->nameplus[pos++]; - cookie1 = rent->nameplus[pos++]; + fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos++]) << 32) | + ntohl(rent->nameplus[pos++]); buf = (u_char *)&rent->nameplus[pos]; return (0); } |