Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 Sep 2012 13:25:50 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r240780 - head/lib/libstand
Message-ID:  <201209211325.q8LDPoFw041429@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Fri Sep 21 13:25:50 2012
New Revision: 240780
URL: http://svn.freebsd.org/changeset/base/240780

Log:
  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.

Modified:
  head/lib/libstand/nfs.c

Modified: head/lib/libstand/nfs.c
==============================================================================
--- head/lib/libstand/nfs.c	Fri Sep 21 12:40:31 2012	(r240779)
+++ head/lib/libstand/nfs.c	Fri Sep 21 13:25:50 2012	(r240780)
@@ -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 
 	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 
 		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 
 		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 
 
 	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 
 	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 
 		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 
 		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 
 		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 
 	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 
 	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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209211325.q8LDPoFw041429>