summaryrefslogtreecommitdiffstats
path: root/lib/libstand
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-09-21 13:25:50 +0000
committermav <mav@FreeBSD.org>2012-09-21 13:25:50 +0000
commit4415d2bdfd228486b8c7a38e43b084b5675fe3b5 (patch)
tree085780028ddfd6fd0473118cff4698dadbe40f4c /lib/libstand
parentb9ef0ec7d18b64fc36bce6b12d77e0f13d87bfc2 (diff)
downloadFreeBSD-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')
-rw-r--r--lib/libstand/nfs.c44
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);
}
OpenPOWER on IntegriCloud