From e62c2bba1fb7cf068eb78d731da46e4447a9efb1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 9 May 2007 09:00:17 -0400 Subject: NFS: Fix a jiffie wraparound issue dentry verifiers are always set to the parent directory's cache_change_attribute. There is no reason to be testing for anything other than equality when we're trying to find out if the dentry has been checked since the last time the directory was modified. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 625d8e5fb39..fced7d1d48d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -650,12 +650,17 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) */ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { + unsigned long verf; + if (IS_ROOT(dentry)) return 1; + verf = (unsigned long)dentry->d_fsdata; if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0 - || nfs_attribute_timeout(dir)) + || nfs_attribute_timeout(dir) + || nfs_caches_unstable(dir) + || verf != NFS_I(dir)->cache_change_attribute) return 0; - return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata); + return 1; } static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) @@ -665,8 +670,7 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) { - if (time_after(verf, (unsigned long)dentry->d_fsdata)) - nfs_set_verifier(dentry, verf); + nfs_set_verifier(dentry, verf); } /* -- cgit v1.2.3 From e70c490810dc683fad39e57cf00e69d5f120c542 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 9 May 2007 09:00:18 -0400 Subject: NFS: Remove redundant check in nfs_check_verifier() The check for nfs_attribute_timeout(dir) in nfs_check_verifier is redundant: nfs_lookup_revalidate() will already call nfs_revalidate_inode() on the parent dir when necessary. The only case where this is not done is the case of a negative dentry. Fix this case by moving up the revalidation code. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index fced7d1d48d..469cf66e1dc 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -655,9 +655,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) if (IS_ROOT(dentry)) return 1; verf = (unsigned long)dentry->d_fsdata; - if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0 - || nfs_attribute_timeout(dir) - || nfs_caches_unstable(dir) + if (nfs_caches_unstable(dir) || verf != NFS_I(dir)->cache_change_attribute) return 0; return 1; @@ -769,6 +767,10 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); inode = dentry->d_inode; + /* Revalidate parent directory attribute cache */ + if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) + goto out_zap_parent; + if (!inode) { if (nfs_neg_need_reval(dir, dentry, nd)) goto out_bad; @@ -782,10 +784,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) goto out_bad; } - /* Revalidate parent directory attribute cache */ - if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) - goto out_zap_parent; - /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { if (nfs_lookup_verify_inode(inode, nd)) -- cgit v1.2.3 From aa3d1faebe6e214cd96be0e587571477ff6fd9fc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 May 2007 18:23:28 -0400 Subject: SUNRPC: Fix pointer arithmetic bug recently introduced in rpc_malloc/free Use a cleaner method to find the size of an rpc_buffer. This actually works on x86-64! Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 99014516b73..b28a0b037f4 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -736,6 +736,11 @@ static void rpc_async_schedule(struct work_struct *work) __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); } +struct rpc_buffer { + size_t len; + char data[]; +}; + /** * rpc_malloc - allocate an RPC buffer * @task: RPC task that will use this buffer @@ -754,18 +759,18 @@ static void rpc_async_schedule(struct work_struct *work) */ void *rpc_malloc(struct rpc_task *task, size_t size) { - size_t *buf; + struct rpc_buffer *buf; gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT; - size += sizeof(size_t); + size += sizeof(struct rpc_buffer); if (size <= RPC_BUFFER_MAXSIZE) buf = mempool_alloc(rpc_buffer_mempool, gfp); else buf = kmalloc(size, gfp); - *buf = size; + buf->len = size; dprintk("RPC: %5u allocated buffer of size %zu at %p\n", task->tk_pid, size, buf); - return ++buf; + return &buf->data; } /** @@ -775,15 +780,18 @@ void *rpc_malloc(struct rpc_task *task, size_t size) */ void rpc_free(void *buffer) { - size_t size, *buf = buffer; + size_t size; + struct rpc_buffer *buf; if (!buffer) return; - size = *buf; - buf--; + + buf = container_of(buffer, struct rpc_buffer, data); + size = buf->len; dprintk("RPC: freeing buffer of size %zu at %p\n", size, buf); + if (size <= RPC_BUFFER_MAXSIZE) mempool_free(buf, rpc_buffer_mempool); else -- cgit v1.2.3 From 6ce7dc940701cf3fde3c6e826a696b333092cbb1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 May 2007 18:23:28 -0400 Subject: NFS: NFS client underestimates how large an NFSv4 SETATTR reply can be The maximum size of an NFSv4 SETATTR compound reply should include the GETATTR operation that we send. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b8c28f2380a..f1e2b8cdf33 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -224,7 +224,8 @@ static int nfs4_stat_to_errno(int); encode_getattr_maxsz) #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 3) + op_decode_hdr_maxsz + 3 + \ + nfs4_fattr_maxsz) #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_fsinfo_maxsz) -- cgit v1.2.3 From e4cc6ee2e40bdd57990577b7f851fa2ca48edf47 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 8 May 2007 18:23:28 -0400 Subject: NFS: Clean up NFSv4 XDR error message Make it more useful for debugging purposes. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index f1e2b8cdf33..938f3716678 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2080,9 +2080,11 @@ out: #define READ_BUF(nbytes) do { \ p = xdr_inline_decode(xdr, nbytes); \ - if (!p) { \ - printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \ - __FUNCTION__, __LINE__); \ + if (unlikely(!p)) { \ + printk(KERN_INFO "%s: prematurely hit end of receive" \ + " buffer\n", __FUNCTION__); \ + printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ + __FUNCTION__, xdr->p, nbytes, xdr->end); \ return -EIO; \ } \ } while (0) -- cgit v1.2.3 From ddce40df6e14dd474bbd9daa006dcc290dea6326 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 9 May 2007 08:30:11 +0200 Subject: sunrpc: fix crash in rpc_malloc() While the comment says: * To prevent rpciod from hanging, this allocator never sleeps, * returning NULL if the request cannot be serviced immediately. The function does not actually check for NULL pointers being returned. Signed-off-by: Peter Zijlstra Signed-off-by: Trond Myklebust --- net/sunrpc/sched.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index b28a0b037f4..b011eb625e4 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -767,6 +767,10 @@ void *rpc_malloc(struct rpc_task *task, size_t size) buf = mempool_alloc(rpc_buffer_mempool, gfp); else buf = kmalloc(size, gfp); + + if (!buf) + return NULL; + buf->len = size; dprintk("RPC: %5u allocated buffer of size %zu at %p\n", task->tk_pid, size, buf); -- cgit v1.2.3 From fee7f23feaf0845fdfd47d20cddc75652552fbb8 Mon Sep 17 00:00:00 2001 From: Milind Arun Choudhary Date: Thu, 26 Apr 2007 00:29:03 -0700 Subject: NFS: use __set_current_state() use __set_current_state(TASK_*) instead of current->state = TASK_*, in fs/nfs Signed-off-by: Milind Arun Choudhary Cc: Trond Myklebust Cc: "J. Bruce Fields" Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/idmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 9d4a6b2d199..d11eb055265 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -272,7 +272,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, set_current_state(TASK_UNINTERRUPTIBLE); mutex_unlock(&idmap->idmap_im_lock); schedule(); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&idmap->idmap_wq, &wq); mutex_lock(&idmap->idmap_im_lock); @@ -333,7 +333,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, set_current_state(TASK_UNINTERRUPTIBLE); mutex_unlock(&idmap->idmap_im_lock); schedule(); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&idmap->idmap_wq, &wq); mutex_lock(&idmap->idmap_im_lock); -- cgit v1.2.3 From 7a13e932281e7042a592f4f14db0b348199e7aac Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 26 Apr 2007 00:29:02 -0700 Subject: NFS: Kill the obsolete NFS_PARANOIA Signed-off-by: Jesper Juhl Acked-by: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 17 ++--------------- fs/nfs/getroot.c | 1 - fs/nfs/inode.c | 3 --- fs/nfs/nfs2xdr.c | 1 - fs/nfs/pagelist.c | 7 ------- 5 files changed, 2 insertions(+), 27 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 469cf66e1dc..3df42881655 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -38,7 +38,6 @@ #include "delegation.h" #include "iostat.h" -#define NFS_PARANOIA 1 /* #define NFS_DEBUG_VERBOSE 1 */ static int nfs_opendir(struct inode *, struct file *); @@ -1362,11 +1361,6 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) atomic_read(&dentry->d_count)); nfs_inc_stats(dir, NFSIOS_SILLYRENAME); -#ifdef NFS_PARANOIA -if (!dentry->d_inode) -printk("NFS: silly-renaming %s/%s, negative dentry??\n", -dentry->d_parent->d_name.name, dentry->d_name.name); -#endif /* * We don't allow a dentry to be silly-renamed twice. */ @@ -1683,16 +1677,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, new_inode = NULL; /* instantiate the replacement target */ d_instantiate(new_dentry, NULL); - } else if (atomic_read(&new_dentry->d_count) > 1) { - /* dentry still busy? */ -#ifdef NFS_PARANOIA - printk("nfs_rename: target %s/%s busy, d_count=%d\n", - new_dentry->d_parent->d_name.name, - new_dentry->d_name.name, - atomic_read(&new_dentry->d_count)); -#endif + } else if (atomic_read(&new_dentry->d_count) > 1) + /* dentry still busy? */ goto out; - } } else drop_nlink(new_inode); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 234778576f0..d1cbf0a0fbb 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -41,7 +41,6 @@ #include "internal.h" #define NFSDBG_FACILITY NFSDBG_CLIENT -#define NFS_PARANOIA 1 /* * get an NFS2/NFS3 root dentry from the root filehandle diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 1e9a915d1fe..2a3fd957320 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -48,7 +48,6 @@ #include "internal.h" #define NFSDBG_FACILITY NFSDBG_VFS -#define NFS_PARANOIA 1 static void nfs_invalidate_inode(struct inode *); static int nfs_update_inode(struct inode *, struct nfs_fattr *); @@ -1075,10 +1074,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) /* * Big trouble! The inode has become a different object. */ -#ifdef NFS_PARANOIA printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); -#endif out_err: /* * No need to worry about unhashing the dentry, as the diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index abd9f8b4894..cd3ca7b5d3d 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -26,7 +26,6 @@ #include "internal.h" #define NFSDBG_FACILITY NFSDBG_XDR -/* #define NFS_PARANOIA 1 */ /* Mapping from NFS error code to "errno" error code. */ #define errno_NFSERR_IO EIO diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 388950118f5..e12054c86d0 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -20,8 +20,6 @@ #include "internal.h" -#define NFS_PARANOIA 1 - static struct kmem_cache *nfs_page_cachep; static inline struct nfs_page * @@ -167,11 +165,6 @@ nfs_release_request(struct nfs_page *req) if (!atomic_dec_and_test(&req->wb_count)) return; -#ifdef NFS_PARANOIA - BUG_ON (!list_empty(&req->wb_list)); - BUG_ON (NFS_WBACK_BUSY(req)); -#endif - /* Release struct file or cached credential */ nfs_clear_request(req); put_nfs_open_context(req->wb_context); -- cgit v1.2.3