
From: Neil Brown <neilb@cse.unsw.edu.au>

nfsd currently just sets f_pos when seeking in a directory.  This bypasses
any checking and other handling that a filesystem might want to do.

So instead, we define "vfs_llseek" to be an exported "llseek", and use
that, both to seek at the start, and the find the new position at the end.

Thanks to
    "Derrick Schommer" <dschommer@acopia.com>
    "Trond Myklebust" <trond.myklebust@fys.uio.no>

Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/nfsd/vfs.c      |   10 ++++++----
 25-akpm/fs/read_write.c    |    7 +++++++
 25-akpm/include/linux/fs.h |    2 ++
 3 files changed, 15 insertions(+), 4 deletions(-)

diff -puN fs/nfsd/vfs.c~use-llseek-instead-of-f_pos=-for-directory-seeking fs/nfsd/vfs.c
--- 25/fs/nfsd/vfs.c~use-llseek-instead-of-f_pos=-for-directory-seeking	2004-07-01 20:29:10.552949160 -0700
+++ 25-akpm/fs/nfsd/vfs.c	2004-07-01 20:29:10.560947944 -0700
@@ -1477,10 +1477,12 @@ nfsd_readdir(struct svc_rqst *rqstp, str
 	err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
 	if (err)
 		goto out;
-	if (offset > ~(u32) 0)
-		goto out_close;
 
-	file.f_pos = offset;
+	offset = vfs_llseek(&file, offset, 0);
+	if (offset < 0) {
+		err = nfserrno((int)offset);
+		goto out_close;
+	}
 
 	/*
 	 * Read the directory entries. This silly loop is necessary because
@@ -1496,7 +1498,7 @@ nfsd_readdir(struct svc_rqst *rqstp, str
 		err = nfserrno(err);
 	else
 		err = cdp->err;
-	*offsetp = file.f_pos;
+	*offsetp = vfs_llseek(&file, 0LL, 1);
 
 	if (err == nfserr_eof || err == nfserr_toosmall)
 		err = nfs_ok; /* can still be found in ->err */
diff -puN fs/read_write.c~use-llseek-instead-of-f_pos=-for-directory-seeking fs/read_write.c
--- 25/fs/read_write.c~use-llseek-instead-of-f_pos=-for-directory-seeking	2004-07-01 20:29:10.553949008 -0700
+++ 25-akpm/fs/read_write.c	2004-07-01 20:29:10.560947944 -0700
@@ -122,6 +122,13 @@ static inline loff_t llseek(struct file 
 	return fn(file, offset, origin);
 }
 
+loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
+{
+	return llseek(file, offset, origin);
+}
+
+EXPORT_SYMBOL(vfs_llseek);
+
 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
 	off_t retval;
diff -puN include/linux/fs.h~use-llseek-instead-of-f_pos=-for-directory-seeking include/linux/fs.h
--- 25/include/linux/fs.h~use-llseek-instead-of-f_pos=-for-directory-seeking	2004-07-01 20:29:10.555948704 -0700
+++ 25-akpm/include/linux/fs.h	2004-07-01 20:29:10.570946424 -0700
@@ -1354,6 +1354,8 @@ extern ino_t find_inode_number(struct de
 /* needed for stackable file system support */
 extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
 
+extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin);
+
 extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
_
