From: Neil Brown 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" "Trond Myklebust" Signed-off-by: Neil Brown Signed-off-by: Andrew Morton --- 25-akpm/fs/nfsd/vfs.c | 10 ++++++---- 25-akpm/fs/read_write.c | 10 ++++------ 25-akpm/include/linux/fs.h | 2 ++ 3 files changed, 12 insertions(+), 10 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-05 16:08:54.341788152 -0700 +++ 25-akpm/fs/nfsd/vfs.c 2004-07-05 16:08:54.349786936 -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, 0, 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-05 16:08:54.342788000 -0700 +++ 25-akpm/fs/read_write.c 2004-07-05 16:08:54.350786784 -0700 @@ -76,14 +76,12 @@ loff_t remote_llseek(struct file *file, unlock_kernel(); return retval; } - EXPORT_SYMBOL(remote_llseek); loff_t no_llseek(struct file *file, loff_t offset, int origin) { return -ESPIPE; } - EXPORT_SYMBOL(no_llseek); loff_t default_llseek(struct file *file, loff_t offset, int origin) @@ -109,10 +107,9 @@ loff_t default_llseek(struct file *file, unlock_kernel(); return retval; } - EXPORT_SYMBOL(default_llseek); -static inline loff_t llseek(struct file *file, loff_t offset, int origin) +loff_t vfs_llseek(struct file *file, loff_t offset, int origin) { loff_t (*fn)(struct file *, loff_t, int); @@ -121,6 +118,7 @@ static inline loff_t llseek(struct file fn = file->f_op->llseek; return fn(file, offset, origin); } +EXPORT_SYMBOL(vfs_llseek); asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) { @@ -135,7 +133,7 @@ asmlinkage off_t sys_lseek(unsigned int retval = -EINVAL; if (origin <= 2) { - loff_t res = llseek(file, offset, origin); + loff_t res = vfs_llseek(file, offset, origin); retval = res; if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ @@ -165,7 +163,7 @@ asmlinkage long sys_llseek(unsigned int if (origin > 2) goto out_putf; - offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, + offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); retval = (int)offset; 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-05 16:08:54.345787544 -0700 +++ 25-akpm/include/linux/fs.h 2004-07-05 16:08:54.352786480 -0700 @@ -1352,6 +1352,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 *); _