dir.c | 21 +++++++++++++++++++++ nfs2xdr.c | 4 ++-- nfs3xdr.c | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.4.26-01-fix_unlink/fs/nfs/dir.c linux-2.4.26-02-seekdir/fs/nfs/dir.c --- linux-2.4.26-01-fix_unlink/fs/nfs/dir.c 2004-04-16 09:35:23.000000000 -0700 +++ linux-2.4.26-02-seekdir/fs/nfs/dir.c 2004-04-16 09:35:24.000000000 -0700 @@ -34,6 +34,7 @@ #define NFS_PARANOIA 1 /* #define NFS_DEBUG_VERBOSE 1 */ +static loff_t nfs_dir_llseek(struct file *, loff_t, int); static int nfs_readdir(struct file *, void *, filldir_t); static struct dentry *nfs_lookup(struct inode *, struct dentry *); static int nfs_create(struct inode *, struct dentry *, int); @@ -48,6 +49,7 @@ static int nfs_rename(struct inode *, st static int nfs_fsync_dir(struct file *, struct dentry *, int); struct file_operations nfs_dir_operations = { + llseek: nfs_dir_llseek, read: generic_read_dir, readdir: nfs_readdir, open: nfs_open, @@ -70,6 +72,25 @@ struct inode_operations nfs_dir_inode_op setattr: nfs_notify_change, }; +static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin) +{ + switch (origin) { + case 1: + if (offset == 0) { + offset = file->f_pos; + break; + } + case 2: + return -EINVAL; + } + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + return (offset <= 0) ? 0 : offset; +} + typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int); typedef struct { struct file *file; diff -u --recursive --new-file --show-c-function linux-2.4.26-01-fix_unlink/fs/nfs/nfs2xdr.c linux-2.4.26-02-seekdir/fs/nfs/nfs2xdr.c --- linux-2.4.26-01-fix_unlink/fs/nfs/nfs2xdr.c 2004-04-14 11:28:20.000000000 -0700 +++ linux-2.4.26-02-seekdir/fs/nfs/nfs2xdr.c 2004-04-16 09:35:24.000000000 -0700 @@ -369,7 +369,7 @@ nfs_xdr_readdirargs(struct rpc_rqst *req count = count >> 2; p = xdr_encode_fhandle(p, args->fh); - *p++ = htonl(args->cookie); + *p++ = htonl(args->cookie & 0xFFFFFFFF); *p++ = htonl(count); /* see above */ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -466,7 +466,7 @@ nfs_decode_dirent(u32 *p, struct nfs_ent entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; - entry->cookie = ntohl(*p++); + entry->cookie = (s64)((off_t)ntohl(*p++)); entry->eof = !p[0] && p[1]; return p; diff -u --recursive --new-file --show-c-function linux-2.4.26-01-fix_unlink/fs/nfs/nfs3xdr.c linux-2.4.26-02-seekdir/fs/nfs/nfs3xdr.c --- linux-2.4.26-01-fix_unlink/fs/nfs/nfs3xdr.c 2004-04-14 11:28:57.000000000 -0700 +++ linux-2.4.26-02-seekdir/fs/nfs/nfs3xdr.c 2004-04-16 09:35:24.000000000 -0700 @@ -465,6 +465,13 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, return 0; } +/* Hack to sign-extending 32-bit cookies */ +static inline +u64 nfs_transform_cookie64(u64 cookie) +{ + return (cookie & 0x80000000) ? (cookie ^ 0xFFFFFFFF00000000) : cookie; +} + /* * Encode arguments to readdir call */ @@ -476,7 +483,7 @@ nfs3_xdr_readdirargs(struct rpc_rqst *re u32 count = args->count; p = xdr_encode_fhandle(p, args->fh); - p = xdr_encode_hyper(p, args->cookie); + p = xdr_encode_hyper(p, nfs_transform_cookie64(args->cookie)); *p++ = args->verf[0]; *p++ = args->verf[1]; if (args->plus) { @@ -599,6 +606,8 @@ err_unmap: u32 * nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) { + u64 cookie; + if (!*p++) { if (!*p) return ERR_PTR(-EAGAIN); @@ -611,7 +620,8 @@ nfs3_decode_dirent(u32 *p, struct nfs_en entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; - p = xdr_decode_hyper(p, &entry->cookie); + p = xdr_decode_hyper(p, &cookie); + entry->cookie = nfs_transform_cookie64(cookie); if (plus) { struct nfs_fattr fattr;