2.6.23-rc9-CITI_NFS4_ALL-1 connectathon suite testdir error
Subsystems (2)
Hi,
Running 2.6.23-rc9-CITI_NFS4_ALL-1 on two Intel X86_64 bi-ways machines as client and server, get the following error with the runtest (-s) of the special tests of the connectathon suite when running it with several other robustness tests (fsx,iozone,fssbfss_stress) in the same time:
Second check for lost reply on non-idempotent requests testing 50 idempotencies in directory "testdir" rmdir 1: Directory not empty
special tests failed
-------------------------------------------------------------
Bug:
http://bugzilla.linux-nfs.org/show_bug.cgi?id=150
Cheers
Signature · 18 lines
----------------------------------------------------------------- Company : Bull, Architect of an Open World TM (www.bull.com) Name : Aime Le Rouzic Mail : Bull - BP 208 - 38432 Echirolles Cedex - France E-Mail : [email protected] Phone : 33 (4) 76.29.75.51 Fax : 33 (4) 76.29.75.18 ----------------------------------------------------------------- ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ NFS maillist - [email protected] https://lists.sourceforge.net/lists/listinfo/nfs
Quoted 14 lines · On Fri, 2007-10-12 at 16:12 +0200, Le Rouzic wrote:
Hi,
Running 2.6.23-rc9-CITI_NFS4_ALL-1 on two Intel
X86_64bi-ways machines as client and server, get the following error with the runtest (-s) of the special tests of the connectathon suite when running it with several other robustness tests (fsx,iozone,fssbfss_stress) in the same time:Second check for lost reply on non-idempotent requests testing 50 idempotencies in directory "testdir" rmdir 1: Directory not empty
special tests failed
Quoted 5 lines
-------------------------------------------------------------
Bug:
http://bugzilla.linux-nfs.org/show_bug.cgi?id=150Cheers
I'm hoping that the attached patch will fix this problem. It basically ensures that lookup(), readdir(), and open() cannot race with the sillyrename code.
Cheers
Trond
lookup() and sillyrename() can race one another because the sillyrename() completion cannot take the parent directory's inode->i_mutex since the latter may be held by whoever is calling dput().
We therefore have little option but to add extra locking to ensure that nfs_lookup() and nfs_atomic_open() do not race with the sillyrename completion.
If somebody has looked up the sillyrenamed file in the meantime, we just transfer the sillydelete information to the new dentry.
---
fs/nfs/dir.c | 14 +++++- fs/nfs/inode.c | 3 + fs/nfs/nfs4proc.c | 6 +++ fs/nfs/unlink.c | 114 ++++++++++++++++++++++++++++++++++++++++++------ include/linux/nfs_fs.h | 8 +++ 5 files changed, 127 insertions(+), 18 deletions(-)
fs/nfs/dir.c +11 -3
@@ -562,6 +562,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)nfs_fattr_init (&fattr); desc->entry = &my_entry; +nfs_block_sillyrename (dentry);while (!desc->entry->eof) { res =readdir_search_pagecache (desc);
@@ -592,6 +593,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)break ; } } +nfs_unblock_sillyrename (dentry);unlock_kernel ();if (res >0 ) res =0 ;
@@ -866,6 +868,7 @@ struct dentry_operations nfs_dentry_operations = {static struct dentry *nfs_lookup (struct inode *dir,struct dentry * dentry,struct nameidata *nd) {struct dentry *res; +struct dentry *parent;struct inode *inode =NULL ;int error;struct nfs_fh fhandle;
@@ -894,26 +897,31 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru goto out_unlock; } + parent = dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent); error =NFS_PROTO (dir)->lookup (dir, &dentry->d_name, &fhandle, &fattr);if (error == -ENOENT ) goto no_entry;if (error <0 ) { res =ERR_PTR (error); - goto out_unlock; + goto out_unblock_sillyrename; } inode =nfs_fhget (dentry->d_sb, &fhandle, &fattr); res = (struct dentry *)inode;if (IS_ERR (res)) - goto out_unlock; + goto out_unblock_sillyrename; no_entry: res =d_materialise_unique (dentry, inode);if (res !=NULL ) {if (IS_ERR (res)) - goto out_unlock; + goto out_unblock_sillyrename; dentry = res; }nfs_set_verifier (dentry,nfs_save_change_attribute (dir)); +out_unblock_sillyrename: +nfs_unblock_sillyrename (parent); out_unlock:unlock_kernel (); out:
fs/nfs/inode.c +3 -0
@@ -1165,6 +1165,9 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flagINIT_RADIX_TREE (&nfsi->nfs_page_tree,GFP_ATOMIC ); nfsi->ncommit =0 ; nfsi->npages =0 ; +atomic_set (&nfsi->silly_count,1 ); +INIT_HLIST_HEAD (&nfsi->silly_list); +init_waitqueue_head (&nfsi->waitqueue);nfs4_init_once (nfsi); }
fs/nfs/nfs4proc.c +6 -0
@@ -1372,6 +1372,7 @@ out_close:struct dentry *nfs4_atomic_open (struct inode *dir,struct dentry *dentry,struct nameidata *nd) { +struct dentry *parent;struct path path = { .mnt = nd->mnt, .dentry = dentry,
@@ -1394,6 +1395,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) cred =rpcauth_lookupcred (NFS_CLIENT (dir)->cl_auth,0 );if (IS_ERR (cred))return (struct dentry *)cred; + parent = dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent); state =nfs4_do_open (dir, &path, nd->intent.open.flags, &attr, cred);put_rpccred (cred);if (IS_ERR (state)) {
@@ -1401,12 +1405,14 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)d_add (dentry,NULL );nfs_set_verifier (dentry,nfs_save_change_attribute (dir)); } +nfs_unblock_sillyrename (parent);return (struct dentry *)state; } res =d_add_unique (dentry,igrab (state->inode));if (res !=NULL ) path.dentry = res;nfs_set_verifier (path.dentry,nfs_save_change_attribute (dir)); +nfs_unblock_sillyrename (parent);nfs4_intent_set_file (nd, &path, state);return res; }
fs/nfs/unlink.c +99 -15
150 lines not on this page · raw message
include/linux/nfs_fs.h +8 -0
@@ -160,6 +160,12 @@ struct nfs_inode {/* Open contexts for shared mmap writes */ struct list_head open_files; +/* Number of in-flight sillydelete RPC calls */ +atomic_t silly_count; +/* List of deferred sillydelete requests */ +struct hlist_head silly_list; +wait_queue_head_t waitqueue; +#ifdef CONFIG_NFS_V4 struct nfs4_cached_acl *nfs4_acl;/* NFSv4 state */
@@ -394,6 +400,8 @@ extern void nfs_release_automount_timer(void);*/ extern int nfs_async_unlink (struct inode *dir,struct dentry *dentry);extern void nfs_complete_unlink (struct dentry *dentry,struct inode *); +extern void nfs_block_sillyrename (struct dentry *dentry); +extern void nfs_unblock_sillyrename (struct dentry *dentry);/* * linux/fs/nfs/write.c
_______________________________________________
NFSv4 mailing list
[email protected]
http://linux-nfs.org/cgi-bin/mailman/listinfo/nfsv4
Hi,
Unfortunately not the case I was mentioning.
More on
------------------------------------------------------------- =
Bug: =
http://bugzilla.linux-nfs.org/show_bug.cgi?id=3D150 =
=
Cheers
Trond Myklebust a =E9crit :
Quoted 8 lines · On Fri, 2007-10-12 at 16:12 +0200, Le Rouzic wrote:
=
Quoted 4 lines
Hi,
Running 2.6.23-rc9-CITI_NFS4_ALL-1 on two Intel
X86_64bi-ways machines as client and server, get the following error with the runtest (-s) of the s=
pecial
Quoted 1 line
Quoted 1 line
tests of the connectathon suite when running it with several other robust=
ness
Quoted 53 lines
Quoted 12 lines
tests (fsx,iozone,fssbfss_stress) in the same time:
Second check for lost reply on non-idempotent requests testing 50 idempotencies in directory "testdir" rmdir 1: Directory not empty
special tests failed=
------------------------------------------------------------- =
Quoted 10 lines
Bug: =
http://bugzilla.linux-nfs.org/show_bug.cgi?id=3D150 =
=
Cheers
=I'm hoping that the attached patch will fix this problem. It basically ensures that
lookup(),readdir(), andopen()cannot race with the sillyrename code.Cheers
Trond
=------------------------------------------------------------------------
Sujet:
No Subject
Exp=E9diteur:
Trond Myklebust <[email protected]>
Date:
Mon, 15 Oct 2007 18:17:53 -0400
lookup()andsillyrename()can race one another because thesillyrename()completion cannot take the parent directory'sinode->i_mutexsince the latter may be held by whoever is callingdput().We therefore have little option but to add extra locking to ensure that
nfs_lookup()andnfs_atomic_open()do not race with the sillyrename completion.
If somebody has looked up the sillyrenamed file in the meantime, we just transfer the sillydelete information to the new dentry.
Quoted 7 lines
Signed-off-by Trond Myklebust <[email protected]>---
fs/nfs/dir.c | 14 +++++- fs/nfs/inode.c | 3 + fs/nfs/nfs4proc.c | 6 +++ fs/nfs/unlink.c | 114 ++++++++++++++++++++++++++++++++++++++++++-=
-----
fs/nfs/dir.c static int nfs_readdir(struct file *filp, void *dirent=
Quoted 8 lines
include/linux/nfs_fs.h| 8 +++5 files changed, 127 insertions(+), 18 deletions(-)fs/nfs/dir.c +0
-0@@ -562,6 +562,7 @@ static int nfs_readdir(struct file *filp, void *dirent=
, filldir_t filldir)
fs/nfs/dir.c static int nfs_readdir(struct file *filp, void *dirent=
Quoted 10 lines
fs/nfs/dir.c +0
-0nfs_fattr_init (&fattr); desc->entry =3D &my_entry;=
fs/nfs/dir.c +1
-0+nfs_block_sillyrename (dentry);while(!desc->entry->eof) { res =3D readdir_search_pagecache(desc);=
fs/nfs/dir.c +0
-0@@ -592,6 +593,7 @@ static int nfs_readdir(struct file *filp, void *dirent=
, filldir_t filldir)
Quoted 9 lines
fs/nfs/dir.c +1
-0break ; } } +nfs_unblock_sillyrename (dentry);unlock_kernel ();if (res >0 ) res =3D 0;@@ -866,6 +868,7 @@ struct dentry_operations nfs_dentry_operations =3D {static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentr=
y, struct nameidata *nd)
fs/nfs/dir.c static struct dentry *nfs_lookup(struct inode *dir, =
Quoted 7 lines
{ struct dentry *res;fs/nfs/dir.c +1
-0+struct dentry *parent;struct inode *inode =3D NULL; int error; struct nfs_fh fhandle;fs/nfs/dir.c +0
-0@@ -894,26 +897,31 @@ static struct dentry *nfs_lookup(struct inode *dir, =
struct dentry * dentry, stru
fs/nfs/inode.c static void init_once(void * foo, struct kmem_cache =
Quoted 41 lines
fs/nfs/dir.c +0
-0goto out_unlock; }=
fs/nfs/dir.c +3
-0+ parent =3D dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent);error =3D NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error =3D=3D -ENOENT) goto no_entry; if (error < 0) { res =3D ERR_PTR(error);fs/nfs/dir.c +1
-1- goto out_unlock; + goto out_unblock_sillyrename;} inode =3D nfs_fhget(dentry->d_sb, &fhandle, &fattr); res =3D (struct dentry *)inode; if (IS_ERR(res))fs/nfs/dir.c +1
-1- goto out_unlock; + goto out_unblock_sillyrename;=
no_entry:res =3D d_materialise_unique(dentry, inode); if (res !=3D NULL) { if (IS_ERR(res))fs/nfs/dir.c +1
-1- goto out_unlock; + goto out_unblock_sillyrename;dentry =3D res; } nfs_set_verifier(dentry, nfs_save_change_attribute(dir));fs/nfs/dir.c +2
-0+out_unblock_sillyrename: +nfs_unblock_sillyrename (parent);
out_unlock:unlock_kernel();out:
fs/nfs/inode.c +0
-0@@ -1165,6 +1165,9 @@ static void init_once(void * foo, struct kmem_cache =
* cachep, unsigned long flag
Quoted 15 lines
fs/nfs/inode.c +3
-0INIT_RADIX_TREE (&nfsi->nfs_page_tree,GFP_ATOMIC ); nfsi->ncommit =3D 0; nfsi->npages =3D 0; +atomic_set (&nfsi->silly_count,1 ); +INIT_HLIST_HEAD (&nfsi->silly_list); +init_waitqueue_head (&nfsi->waitqueue);nfs4_init_once (nfsi); }=
fs/nfs/nfs4proc.c +0
-0@@ -1372,6 +1372,7 @@ out_close:
Quoted 2 lines
struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameida=
ta *nd)
fs/nfs/nfs4proc.c nfs4_atomic_open(struct inode *dir, struct dentry *d=
Quoted 6 lines
{
fs/nfs/nfs4proc.c +1
-0+struct dentry *parent;struct path path =3D { .mnt =3D nd->mnt, .dentry =3D dentry,fs/nfs/nfs4proc.c +0
-0@@ -1394,6 +1395,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *d=
entry, struct nameidata *nd)
fs/nfs/nfs4proc.c nfs4_atomic_open(struct inode *dir, struct dentry =
Quoted 10 lines
fs/nfs/nfs4proc.c +3
-0cred =3D rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);if (IS_ERR (cred))return (struct dentry *)cred; + parent =3D dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent); state =3D nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);put_rpccred (cred);if (IS_ERR (state)) {@@ -1401,12 +1405,14 @@ nfs4_atomic_open(struct inode *dir, struct dentry =
*dentry, struct nameidata *nd)
fs/nfs/unlink.c static int nfs_copy_dname(struct dentry *dentry, struct=
Quoted 29 lines
fs/nfs/nfs4proc.c +2
-0d_add (dentry,NULL );nfs_set_verifier (dentry,nfs_save_change_attribute (dir)); } +nfs_unblock_sillyrename (parent);return (struct dentry *)state; } res =3D d_add_unique(dentry, igrab(state->inode)); if (res !=3D NULL) path.dentry =3D res;nfs_set_verifier (path.dentry,nfs_save_change_attribute (dir)); +nfs_unblock_sillyrename (parent);nfs4_intent_set_file (nd, &path, state);return res; }fs/nfs/unlink.c +0
-0@@ -14,6 +14,7 @@=
=
struct
nfs_unlinkdata{fs/nfs/unlink.c +1
-0+struct hlist_node list;struct nfs_removeargs args; struct nfs_removeres res; struct inode *dir;fs/nfs/unlink.c +0
-0@@ -52,6 +53,20 @@ static int nfs_copy_dname(struct dentry *dentry, struct=
nfs_unlinkdata *data)
fs/nfs/unlink.c static void nfs_async_unlink_done(struct rpc_task *task=
Quoted 22 lines
fs/nfs/unlink.c +0
-0return 0 ; }=
fs/nfs/unlink.c +14
-0+static void nfs_free_dname (struct nfs_unlinkdata *data) +{ +kfree (data->args.name.name); + data->args.name.name =3D NULL; + data->args.name.len =3D 0; +} + +static void nfs_dec_sillycount (struct inode *dir) +{ + struct nfs_inode *nfsi =3D NFS_I(dir); + if (atomic_dec_return(&nfsi->silly_count) =3D=3D 1) +wake_up (&nfsi->waitqueue); +} +/**
*nfs_async_unlink_init- Initialize the RPC info
* task:rpc_taskof the sillydeletefs/nfs/unlink.c +0
-0@@ -95,6 +110,8 @@ static void nfs_async_unlink_done(struct rpc_task *task=
, void *calldata)
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops =3D=
Quoted 10 lines
fs/nfs/unlink.c +2
-0static void nfs_async_unlink_release (void *calldata) { struct nfs_unlinkdata *data =3D calldata; + +nfs_dec_sillycount (data->dir);nfs_free_unlinkdata (data); }=
fs/nfs/unlink.c +0
-0@@ -104,33 +121,100 @@ static const struct rpc_call_ops nfs_unlink_ops =3D=
{
Quoted 5 lines
fs/nfs/unlink.c +0
-0.rpc_release =3D nfs_async_unlink_release, };=
-static int nfs_call_unlink(struct dentry *dentry, struct
nfs_unlinkdata*=
data)
Quoted 1 line
+static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, s=
truct nfs_unlinkdata *data)
Quoted 22 lines
{ struct rpc_task *task;fs/nfs/unlink.c +20
-0+struct dentry *alias; + + alias =3D d_lookup(parent, &data->args.name); + if (alias !=3D NULL) { + int ret =3D 0; +/* +* Hey, we raced with lookup... See if we need to transfer +* the sillyrename information to the aliased dentry. +*/ +nfs_free_dname (data); +spin_lock (&alias->d_lock); +if (!(alias->d_flags &DCACHE_NFSFS_RENAMED )) { + alias->d_fsdata =3D data; + alias->d_flags ^=3D DCACHE_NFSFS_RENAMED; + ret =3D 1; + } +spin_unlock (&alias->d_lock); +nfs_dec_sillycount (dir); +dput (alias); +return ret;
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 10 lines
fs/nfs/unlink.c +10
-0+ } + data->dir =3D igrab(dir); +if (!data->dir) { +nfs_dec_sillycount (dir); +return 0 ; + } + data->args.fh =3D NFS_FH(dir); +nfs_fattr_init (&data->res.dir_attr); + + task =3D rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, =
data);
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 6 lines
fs/nfs/unlink.c +6
-0+if (!IS_ERR (task)) +rpc_put_task (task); +return 1 ; +} + +static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *=
data)
Quoted 45 lines
+{ struct dentry *parent; struct inode *dir;fs/nfs/unlink.c +1
-0+ int ret =3D 0;=
fs/nfs/unlink.c +0
-2-if (nfs_copy_dname (dentry, data) <0 ) - goto out_free;=
parent =3D dget_parent(dentry); if (parent =3D=3D NULL) goto out_free;fs/nfs/unlink.c +15
-1- dir =3D igrab(parent->d_inode); + dir =3D parent->d_inode; + if (nfs_copy_dname(dentry, data) =3D=3D 0) + goto out_dput; +/* Non-exclusive lock protects against concurrent lookup() calls */ +spin_lock (&dir->i_lock); + if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) =3D=3D 0) { +/* Deferred delete */ +hlist_add_head (&data->list, &NFS_I (dir)->silly_list); +spin_unlock (&dir->i_lock); + ret =3D 1; + goto out_dput; + } +spin_unlock (&dir->i_lock); + ret =3D nfs_do_call_unlink(parent, dir, data); +out_dput:dput(parent);fs/nfs/unlink.c +3
-2- if (dir =3D=3D NULL) - goto out_free; +out_free: +return ret; +}=
fs/nfs/unlink.c +3
-3- data->dir =3D dir; - data->args.fh =3D NFS_FH(dir); -nfs_fattr_init (&data->res.dir_attr); +void nfs_block_sillyrename (struct dentry *dentry) +{ + struct nfs_inode *nfsi =3D NFS_I(dentry->d_inode);=
fs/nfs/unlink.c
Quoted 1 line
fs/nfs/unlink.c +0
-1- task =3D rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, =
data);
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 6 lines
fs/nfs/unlink.c +1
-5-if (!IS_ERR (task)) -rpc_put_task (task); -return 1 ; -out_free: -return 0 ; + wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) =3D=
=3D 1);
Quoted 4 lines
fs/nfs/unlink.c +4
-0+} + +void nfs_unblock_sillyrename (struct dentry *dentry) +{
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 10 lines
fs/nfs/unlink.c +10
-0+ struct inode *dir =3D dentry->d_inode; + struct nfs_inode *nfsi =3D NFS_I(dir); +struct nfs_unlinkdata *data; + +atomic_inc (&nfsi->silly_count); +spin_lock (&dir->i_lock); + while (!hlist_empty(&nfsi->silly_list)) { + if (!atomic_inc_not_zero(&nfsi->silly_count)) + break; + data =3D hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, lis=
t);
Quoted 37 lines
fs/nfs/unlink.c +7
-0+hlist_del (&data->list); +spin_unlock (&dir->i_lock); + if (nfs_do_call_unlink(dentry, dir, data) =3D=3D 0) +nfs_free_unlinkdata (data); +spin_lock (&dir->i_lock); + } +spin_unlock (&dir->i_lock);}
=/**
include/linux/nfs_fs.h +0
-0@@ -160,6 +160,12 @@ struct nfs_inode {/* Open contexts for shared mmap writes */ struct list_head open_files;=
include/linux/nfs_fs.h +6
-0+/* Number of in-flight sillydelete RPC calls */ +atomic_t silly_count; +/* List of deferred sillydelete requests */ +struct hlist_head silly_list; +wait_queue_head_t waitqueue; +#ifdef CONFIG_NFS_V4 struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */include/linux/nfs_fs.h +2
-0@@ -394,6 +400,8 @@ extern void nfs_release_automount_timer(void);*/ extern int nfs_async_unlink (struct inode *dir,struct dentry *dentry);extern void nfs_complete_unlink (struct dentry *dentry,struct inode *); +extern void nfs_block_sillyrename (struct dentry *dentry); +extern void nfs_unblock_sillyrename (struct dentry *dentry);=
Quoted 5 lines
/*
*linux/fs/nfs/write.c
=
-- =
-----------------------------------------------------------------
Company : Bull, Architect of an Open World TM (www.bull.com)
Name : Aime Le Rouzic =
Mail : Bull - BP 208 - 38432 Echirolles Cedex - France
E-Mail : [email protected]
Phone : 33 (4) 76.29.75.51
Fax : 33 (4) 76.29.75.18
----------------------------------------------------------------- =
Hi,
It is fixed now thanks to a second patch delivered by Trond.
You will find this second patch at :
Bug: =
http://bugzilla.linux-nfs.org/show_bug.cgi?id=3D150 =
=
Regards
Le Rouzic a =E9crit :
Quoted 15 lines
Hi,
Unfortunately not the case I was mentioning.
More on------------------------------------------------------------- =
Bug: =
http://bugzilla.linux-nfs.org/show_bug.cgi?id=3D150 =
=
Quoted 19 lines
Cheers
Trond Myklebust a =E9crit :
=
Quoted 10 lines · On Fri, 2007-10-12 at 16:12 +0200, Le Rouzic wrote:
=
=Quoted 3 lines
Hi,
Running 2.6.23-rc9-CITI_NFS4_ALL-1 on two Intel
X86_64bi-ways machines =
as
Quoted 1 line
Quoted 1 line
Quoted 1 line
client and server, get the following error with the runtest (-s) of the =
special
Quoted 1 line
Quoted 1 line
Quoted 1 line
tests of the connectathon suite when running it with several other robus=
tness
Quoted 54 lines
Quoted 54 lines
Quoted 15 lines
tests (fsx,iozone,fssbfss_stress) in the same time:
Second check for lost reply on non-idempotent requests testing 50 idempotencies in directory "testdir" rmdir 1: Directory not empty
special tests failed------------------------------------------------------------- =
Bug: =
Quoted 9 lines
=
Cheers
==I'm hoping that the attached patch will fix this problem. It basically ensures that
lookup(),readdir(), andopen()cannot race with the sillyrename code.Cheers
Trond
=------------------------------------------------------------------------
Sujet:
No Subject
Exp=E9diteur:
Trond Myklebust <[email protected]>
Date:
Mon, 15 Oct 2007 18:17:53 -0400
lookup()andsillyrename()can race one another because thesillyrename()completion cannot take the parent directory'sinode->i_mutexsince the latter may be held by whoever is callingdput().We therefore have little option but to add extra locking to ensure that
nfs_lookup()andnfs_atomic_open()do not race with the sillyrename completion.
If somebody has looked up the sillyrenamed file in the meantime, we just transfer the sillydelete information to the new dentry.
Quoted 7 lines
Quoted 7 lines
Signed-off-by Trond Myklebust <[email protected]>---
fs/nfs/dir.c | 14 +++++- fs/nfs/inode.c | 3 + fs/nfs/nfs4proc.c | 6 +++ fs/nfs/unlink.c | 114 ++++++++++++++++++++++++++++++++++++++++++-=
-----
Quoted 8 lines
fs/nfs/dir.c static int nfs_readdir(struct file *filp, void *diren=
Quoted 8 lines
include/linux/nfs_fs.h| 8 +++5 files changed, 127 insertions(+), 18 deletions(-)fs/nfs/dir.c +0
-0@@ -562,6 +562,7 @@ static int nfs_readdir(struct file *filp, void *diren=
t, filldir_t filldir)
Quoted 8 lines
fs/nfs/dir.c static int nfs_readdir(struct file *filp, void *diren=
Quoted 8 lines
fs/nfs/dir.c +1
-0nfs_fattr_init (&fattr); desc->entry =3D &my_entry; +nfs_block_sillyrename (dentry);while (!desc->entry->eof) { res =3D readdir_search_pagecache(desc);@@ -592,6 +593,7 @@ static int nfs_readdir(struct file *filp, void *diren=
t, filldir_t filldir)
Quoted 9 lines
Quoted 9 lines
fs/nfs/dir.c +1
-0break ; } } +nfs_unblock_sillyrename (dentry);unlock_kernel ();if (res >0 ) res =3D 0;@@ -866,6 +868,7 @@ struct dentry_operations nfs_dentry_operations =3D {static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentr=
y, struct nameidata *nd)
Quoted 7 lines
fs/nfs/dir.c static struct dentry *nfs_lookup(struct inode *dir,=
Quoted 7 lines
{ struct dentry *res;fs/nfs/dir.c +1
-0+struct dentry *parent;struct inode *inode =3D NULL; int error; struct nfs_fh fhandle;fs/nfs/dir.c +0
-0@@ -894,26 +897,31 @@ static struct dentry *nfs_lookup(struct inode *dir,=
struct dentry * dentry, stru
Quoted 31 lines
Quoted 31 lines
fs/nfs/dir.c +5
-2goto out_unlock; } + parent =3D dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent); error =3D NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error =3D=3D -ENOENT) goto no_entry;if (error <0 ) { res =3D ERR_PTR(error); - goto out_unlock; + goto out_unblock_sillyrename; } inode =3D nfs_fhget(dentry->d_sb, &fhandle, &fattr); res =3D (struct dentry *)inode;if (IS_ERR (res)) - goto out_unlock; + goto out_unblock_sillyrename;
no_entry:res =3D d_materialise_unique(dentry, inode); if (res !=3D NULL) { if (IS_ERR(res))fs/nfs/dir.c +1
-1- goto out_unlock; + goto out_unblock_sillyrename;dentry =3D res; } nfs_set_verifier(dentry, nfs_save_change_attribute(dir));fs/nfs/dir.c +2
-0+out_unblock_sillyrename: +nfs_unblock_sillyrename (parent);
Quoted 8 lines
fs/nfs/inode.c static void init_once(void * foo, struct kmem_cache=
Quoted 8 lines
out_unlock:unlock_kernel();out:
fs/nfs/inode.c +0
-0@@ -1165,6 +1165,9 @@ static void init_once(void * foo, struct kmem_cache=
* cachep, unsigned long flag
Quoted 9 lines
Quoted 9 lines
fs/nfs/inode.c +3
-0INIT_RADIX_TREE (&nfsi->nfs_page_tree,GFP_ATOMIC ); nfsi->ncommit =3D 0; nfsi->npages =3D 0; +atomic_set (&nfsi->silly_count,1 ); +INIT_HLIST_HEAD (&nfsi->silly_list); +init_waitqueue_head (&nfsi->waitqueue);nfs4_init_once (nfsi); }
Quoted 7 lines
Quoted 7 lines
fs/nfs/nfs4proc.c +0
-0@@ -1372,6 +1372,7 @@ out_close:struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameida=
ta *nd)
Quoted 6 lines
fs/nfs/nfs4proc.c nfs4_atomic_open(struct inode *dir, struct dentry *=
Quoted 6 lines
{
fs/nfs/nfs4proc.c +1
-0+struct dentry *parent;struct path path =3D { .mnt =3D nd->mnt, .dentry =3D dentry,fs/nfs/nfs4proc.c +0
-0@@ -1394,6 +1395,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *=
dentry, struct nameidata *nd)
Quoted 10 lines
fs/nfs/nfs4proc.c nfs4_atomic_open(struct inode *dir, struct dentry=
Quoted 10 lines
fs/nfs/nfs4proc.c +3
-0cred =3D rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);if (IS_ERR (cred))return (struct dentry *)cred; + parent =3D dentry->d_parent; +/* Protect against concurrent sillydeletes */ +nfs_block_sillyrename (parent); state =3D nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);put_rpccred (cred);if (IS_ERR (state)) {@@ -1401,12 +1405,14 @@ nfs4_atomic_open(struct inode *dir, struct dentry=
*dentry, struct nameidata *nd)
Quoted 21 lines
Quoted 21 lines
fs/nfs/nfs4proc.c +2
-0d_add (dentry,NULL );nfs_set_verifier (dentry,nfs_save_change_attribute (dir)); } +nfs_unblock_sillyrename (parent);return (struct dentry *)state; } res =3D d_add_unique(dentry, igrab(state->inode)); if (res !=3D NULL) path.dentry =3D res;nfs_set_verifier (path.dentry,nfs_save_change_attribute (dir)); +nfs_unblock_sillyrename (parent);nfs4_intent_set_file (nd, &path, state);return res; }fs/nfs/unlink.c +0
-0@@ -14,6 +14,7 @@
Quoted 6 lines
fs/nfs/unlink.c static int nfs_copy_dname(struct dentry *dentry, struc=
Quoted 6 lines
fs/nfs/unlink.c +1
-0struct nfs_unlinkdata { +struct hlist_node list;struct nfs_removeargs args;struct nfs_removeres res;struct inode *dir;@@ -52,6 +53,20 @@ static int nfs_copy_dname(struct dentry *dentry, struc=
t nfs_unlinkdata *data)
Quoted 13 lines
Quoted 13 lines
fs/nfs/unlink.c +10
-0return 0 ; } +static void nfs_free_dname (struct nfs_unlinkdata *data) +{ +kfree (data->args.name.name); + data->args.name.name =3D NULL; + data->args.name.len =3D 0; +} + +static void nfs_dec_sillycount (struct inode *dir) +{ + struct nfs_inode *nfsi =3D NFS_I(dir);
Quoted 8 lines
fs/nfs/unlink.c static void nfs_async_unlink_done(struct rpc_task *tas=
Quoted 8 lines
fs/nfs/unlink.c +4
-0+ if (atomic_dec_return(&nfsi->silly_count) =3D=3D 1) +wake_up (&nfsi->waitqueue); +} +/** * nfs_async_unlink_init - Initialize the RPC info * task: rpc_task of the sillydelete @@ -95,6 +110,8 @@ static void nfs_async_unlink_done(struct rpc_task *tas=
k, void *calldata)
Quoted 9 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops =
Quoted 9 lines
fs/nfs/unlink.c +2
-0static void nfs_async_unlink_release (void *calldata) { struct nfs_unlinkdata *data =3D calldata; + +nfs_dec_sillycount (data->dir);nfs_free_unlinkdata (data); }@@ -104,33 +121,100 @@ static const struct rpc_call_ops nfs_unlink_ops =
=3D {
Quoted 4 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = · line 107
Quoted 4 lines
fs/nfs/unlink.c +0
-1.rpc_release =3D nfs_async_unlink_release, }; -static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata =
*data)
Quoted 1 line
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = · line 124
Quoted 1 line
fs/nfs/unlink.c +1
-0+static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, =
struct nfs_unlinkdata *data)
Quoted 24 lines
Quoted 24 lines
fs/nfs/unlink.c +22
-0{struct rpc_task *task; +struct dentry *alias; + + alias =3D d_lookup(parent, &data->args.name); + if (alias !=3D NULL) { + int ret =3D 0; +/* +* Hey, we raced with lookup... See if we need to transfer +* the sillyrename information to the aliased dentry. +*/ +nfs_free_dname (data); +spin_lock (&alias->d_lock); +if (!(alias->d_flags &DCACHE_NFSFS_RENAMED )) { + alias->d_fsdata =3D data; + alias->d_flags ^=3D DCACHE_NFSFS_RENAMED; + ret =3D 1; + } +spin_unlock (&alias->d_lock); +nfs_dec_sillycount (dir); +dput (alias); +return ret; + } + data->dir =3D igrab(dir);
Quoted 8 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 8 lines
fs/nfs/unlink.c +8
-0+if (!data->dir) { +nfs_dec_sillycount (dir); +return 0 ; + } + data->args.fh =3D NFS_FH(dir); +nfs_fattr_init (&data->res.dir_attr); + + task =3D rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops,=
data);
Quoted 6 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 6 lines
fs/nfs/unlink.c +6
-0+if (!IS_ERR (task)) +rpc_put_task (task); +return 1 ; +} + +static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata =
*data)
Quoted 34 lines
Quoted 34 lines
fs/nfs/unlink.c +20
-5+{struct dentry *parent;struct inode *dir; + int ret =3D 0; -if (nfs_copy_dname (dentry, data) <0 ) - goto out_free; parent =3D dget_parent(dentry); if (parent =3D=3D NULL) goto out_free; - dir =3D igrab(parent->d_inode); + dir =3D parent->d_inode; + if (nfs_copy_dname(dentry, data) =3D=3D 0) + goto out_dput; +/* Non-exclusive lock protects against concurrent lookup() calls */ +spin_lock (&dir->i_lock); + if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) =3D=3D 0) { +/* Deferred delete */ +hlist_add_head (&data->list, &NFS_I (dir)->silly_list); +spin_unlock (&dir->i_lock); + ret =3D 1; + goto out_dput; + } +spin_unlock (&dir->i_lock); + ret =3D nfs_do_call_unlink(parent, dir, data); +out_dput:dput (parent); - if (dir =3D=3D NULL) - goto out_free; +out_free: +return ret; +}
Quoted 8 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 8 lines
fs/nfs/unlink.c +3
-4- data->dir =3D dir; - data->args.fh =3D NFS_FH(dir); -nfs_fattr_init (&data->res.dir_attr); +void nfs_block_sillyrename (struct dentry *dentry) +{ + struct nfs_inode *nfsi =3D NFS_I(dentry->d_inode); - task =3D rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops,=
data);
Quoted 6 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 6 lines
fs/nfs/unlink.c +1
-5-if (!IS_ERR (task)) -rpc_put_task (task); -return 1 ; -out_free: -return 0 ; + wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) =
=3D=3D 1);
Quoted 6 lines
Quoted 6 lines
fs/nfs/unlink.c +6
-0+} + +void nfs_unblock_sillyrename (struct dentry *dentry) +{ + struct inode *dir =3D dentry->d_inode; + struct nfs_inode *nfsi =3D NFS_I(dir);
Quoted 8 lines
fs/nfs/unlink.c static const struct rpc_call_ops nfs_unlink_ops = {
Quoted 8 lines
fs/nfs/unlink.c +8
-0+struct nfs_unlinkdata *data; + +atomic_inc (&nfsi->silly_count); +spin_lock (&dir->i_lock); + while (!hlist_empty(&nfsi->silly_list)) { + if (!atomic_inc_not_zero(&nfsi->silly_count)) + break; + data =3D hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, li=
st);
Quoted 39 lines
Quoted 39 lines
fs/nfs/unlink.c +7
-0+hlist_del (&data->list); +spin_unlock (&dir->i_lock); + if (nfs_do_call_unlink(dentry, dir, data) =3D=3D 0) +nfs_free_unlinkdata (data); +spin_lock (&dir->i_lock); + } +spin_unlock (&dir->i_lock); }/** include/linux/nfs_fs.h +8
-0@@ -160,6 +160,12 @@ struct nfs_inode {/* Open contexts for shared mmap writes */ struct list_head open_files; +/* Number of in-flight sillydelete RPC calls */ +atomic_t silly_count; +/* List of deferred sillydelete requests */ +struct hlist_head silly_list; +wait_queue_head_t waitqueue; +#ifdef CONFIG_NFS_V4 struct nfs4_cached_acl *nfs4_acl;/* NFSv4 state */ @@ -394,6 +400,8 @@ extern void nfs_release_automount_timer(void);*/ extern int nfs_async_unlink (struct inode *dir,struct dentry *dentry);extern void nfs_complete_unlink (struct dentry *dentry,struct inode *); +extern void nfs_block_sillyrename (struct dentry *dentry); +extern void nfs_unblock_sillyrename (struct dentry *dentry);/* * linux/fs/nfs/write.c =
Quoted 8 lines
Quoted 3 lines
==
-- =
-----------------------------------------------------------------
Company : Bull, Architect of an Open World TM (www.bull.com)
Name : Aime Le Rouzic =
Mail : Bull - BP 208 - 38432 Echirolles Cedex - France
E-Mail : [email protected]
Phone : 33 (4) 76.29.75.51
Fax : 33 (4) 76.29.75.18
----------------------------------------------------------------- =