linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] NFS: init client before declaration
@ 2012-05-22 12:40 Stanislav Kinsbursky
  2012-05-22 13:47 ` Chuck Lever
  2012-05-22 14:29 ` Myklebust, Trond
  0 siblings, 2 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-05-22 12:40 UTC (permalink / raw)
  To: Trond.Myklebust; +Cc: linux-nfs, linux-kernel, devel

Client have to be initialized prior to adding it to per-net clients list,
because otherwise there are races, shown below:

CPU#0					CPU#1
_____					_____

nfs_get_client
nfs_alloc_client
list_add(..., nfs_client_list)
					rpc_fill_super
					rpc_pipefs_event
					nfs_get_client_for_event
					__rpc_pipefs_event
					(clp->cl_rpcclient is uninitialized)
					BUG()
init_client
clp->cl_rpcclient = ...


Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
 fs/nfs/client.c |   22 ++++++++++++----------
 1 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ae29d4f..9bf4702 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -525,7 +525,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 		cl_init->hostname ?: "", cl_init->rpc_ops->version);
 
 	/* see if the client already exists */
-	do {
+	while (1) {
 		spin_lock(&nn->nfs_client_lock);
 
 		clp = nfs_match_client(cl_init);
@@ -537,10 +537,18 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
 		spin_unlock(&nn->nfs_client_lock);
 
 		new = nfs_alloc_client(cl_init);
-	} while (!IS_ERR(new));
+		if (IS_ERR(new)) {
+			dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
+			return new;
+		}
 
-	dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
-	return new;
+		error = cl_init->rpc_ops->init_client(new, timeparms, ip_addr,
+						      authflavour, noresvport);
+		if (error < 0) {
+			nfs_put_client(new);
+			return ERR_PTR(error);
+		}
+	}
 
 	/* install a new client and return with it unready */
 install_client:
@@ -548,12 +556,6 @@ install_client:
 	list_add(&clp->cl_share_link, &nn->nfs_client_list);
 	spin_unlock(&nn->nfs_client_lock);
 
-	error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
-					      authflavour, noresvport);
-	if (error < 0) {
-		nfs_put_client(clp);
-		return ERR_PTR(error);
-	}
 	dprintk("--> nfs_get_client() = %p [new]\n", clp);
 	return clp;
 


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 12:40 [PATCH] NFS: init client before declaration Stanislav Kinsbursky
@ 2012-05-22 13:47 ` Chuck Lever
  2012-05-22 14:29 ` Myklebust, Trond
  1 sibling, 0 replies; 13+ messages in thread
From: Chuck Lever @ 2012-05-22 13:47 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Stanislav Kinsbursky, Linux NFS Mailing List, LKML Kernel, devel


On May 22, 2012, at 8:40 AM, Stanislav Kinsbursky wrote:

> Client have to be initialized prior to adding it to per-net clients list,
> because otherwise there are races, shown below:
> 
> CPU#0					CPU#1
> _____					_____
> 
> nfs_get_client
> nfs_alloc_client
> list_add(..., nfs_client_list)
> 					rpc_fill_super
> 					rpc_pipefs_event
> 					nfs_get_client_for_event
> 					__rpc_pipefs_event
> 					(clp->cl_rpcclient is uninitialized)
> 					BUG()
> init_client
> clp->cl_rpcclient = ...
> 
> 
> Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>

This patch collides pretty hard with the server trunking detection work.  If you agree this needs to be fixed, the best thing we can do, I guess, is take this patch and drop patch 11, 12, and 13 from my recent patch set, and I'll try to rework for 3.6.

> ---
> fs/nfs/client.c |   22 ++++++++++++----------
> 1 files changed, 12 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index ae29d4f..9bf4702 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -525,7 +525,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
> 		cl_init->hostname ?: "", cl_init->rpc_ops->version);
> 
> 	/* see if the client already exists */
> -	do {
> +	while (1) {
> 		spin_lock(&nn->nfs_client_lock);
> 
> 		clp = nfs_match_client(cl_init);
> @@ -537,10 +537,18 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
> 		spin_unlock(&nn->nfs_client_lock);
> 
> 		new = nfs_alloc_client(cl_init);
> -	} while (!IS_ERR(new));
> +		if (IS_ERR(new)) {
> +			dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
> +			return new;
> +		}
> 
> -	dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
> -	return new;
> +		error = cl_init->rpc_ops->init_client(new, timeparms, ip_addr,
> +						      authflavour, noresvport);
> +		if (error < 0) {
> +			nfs_put_client(new);
> +			return ERR_PTR(error);
> +		}
> +	}
> 
> 	/* install a new client and return with it unready */
> install_client:
> @@ -548,12 +556,6 @@ install_client:
> 	list_add(&clp->cl_share_link, &nn->nfs_client_list);
> 	spin_unlock(&nn->nfs_client_lock);
> 
> -	error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
> -					      authflavour, noresvport);
> -	if (error < 0) {
> -		nfs_put_client(clp);
> -		return ERR_PTR(error);
> -	}
> 	dprintk("--> nfs_get_client() = %p [new]\n", clp);
> 	return clp;
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 12:40 [PATCH] NFS: init client before declaration Stanislav Kinsbursky
  2012-05-22 13:47 ` Chuck Lever
@ 2012-05-22 14:29 ` Myklebust, Trond
  2012-05-22 15:00   ` Myklebust, Trond
  2012-05-22 15:03   ` Stanislav Kinsbursky
  1 sibling, 2 replies; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-22 14:29 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1045 bytes --]

On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
> Client have to be initialized prior to adding it to per-net clients list,
> because otherwise there are races, shown below:
> 
> CPU#0					CPU#1
> _____					_____
> 
> nfs_get_client
> nfs_alloc_client
> list_add(..., nfs_client_list)
> 					rpc_fill_super
> 					rpc_pipefs_event
> 					nfs_get_client_for_event
> 					__rpc_pipefs_event
> 					(clp->cl_rpcclient is uninitialized)
> 					BUG()
> init_client
> clp->cl_rpcclient = ...
> 

Why not simply change nfs_get_client_for_event() so that it doesn't
touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?

That should ensure that it doesn't touch nfs_clients that failed to
initialise and/or are still in the process of being initialised.

Cheers
  Trond

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 14:29 ` Myklebust, Trond
@ 2012-05-22 15:00   ` Myklebust, Trond
  2012-05-22 15:29     ` Stanislav Kinsbursky
  2012-05-22 15:03   ` Stanislav Kinsbursky
  1 sibling, 1 reply; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-22 15:00 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1436 bytes --]

On Tue, 2012-05-22 at 10:29 -0400, Trond Myklebust wrote:
> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
> > Client have to be initialized prior to adding it to per-net clients list,
> > because otherwise there are races, shown below:
> > 
> > CPU#0					CPU#1
> > _____					_____
> > 
> > nfs_get_client
> > nfs_alloc_client
> > list_add(..., nfs_client_list)
> > 					rpc_fill_super
> > 					rpc_pipefs_event
> > 					nfs_get_client_for_event
> > 					__rpc_pipefs_event
> > 					(clp->cl_rpcclient is uninitialized)
> > 					BUG()
> > init_client
> > clp->cl_rpcclient = ...
> > 
> 
> Why not simply change nfs_get_client_for_event() so that it doesn't
> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
> 
> That should ensure that it doesn't touch nfs_clients that failed to
> initialise and/or are still in the process of being initialised.

...actually, come to think of it. Why not just add a helper function
"bool nfs_client_active(const struct nfs_client *clp)" to
fs/nfs/client.c that does a call to
	wait_event_killable(nfs_client_active_wq, clp->cl_cons_state < NFS_CS_INITING);
and checks the resulting value of clp->cl_cons_state?

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 14:29 ` Myklebust, Trond
  2012-05-22 15:00   ` Myklebust, Trond
@ 2012-05-22 15:03   ` Stanislav Kinsbursky
  1 sibling, 0 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-05-22 15:03 UTC (permalink / raw)
  To: Myklebust, Trond; +Cc: linux-nfs, linux-kernel, devel

On 22.05.2012 18:29, Myklebust, Trond wrote:
> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
>> Client have to be initialized prior to adding it to per-net clients list,
>> because otherwise there are races, shown below:
>>
>> CPU#0					CPU#1
>> _____					_____
>>
>> nfs_get_client
>> nfs_alloc_client
>> list_add(..., nfs_client_list)
>> 					rpc_fill_super
>> 					rpc_pipefs_event
>> 					nfs_get_client_for_event
>> 					__rpc_pipefs_event
>> 					(clp->cl_rpcclient is uninitialized)
>> 					BUG()
>> init_client
>> clp->cl_rpcclient = ...
>>
>
> Why not simply change nfs_get_client_for_event() so that it doesn't
> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
>
> That should ensure that it doesn't touch nfs_clients that failed to
> initialise and/or are still in the process of being initialised.
>

It looks like in this case we will have another races:

CPU#0						CPU#1
_____						_____

nfs4_init_client
nfs_idmap_new
nfs_idmap_register
rpc_get_sb_net (fail - no pipefs)
  					rpc_fill_super
  					rpc_pipefs_event
  					nfs_get_client_for_event
					(skip client - NFS_CS_READY is not set)
nfs_mark_client_ready(NFS_CS_READY)


And we are having client without idmap pipe...


> Cheers
>    Trond
>


-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 15:00   ` Myklebust, Trond
@ 2012-05-22 15:29     ` Stanislav Kinsbursky
  2012-05-22 15:51       ` Myklebust, Trond
  0 siblings, 1 reply; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-05-22 15:29 UTC (permalink / raw)
  To: Myklebust, Trond; +Cc: linux-nfs, linux-kernel, devel

On 22.05.2012 19:00, Myklebust, Trond wrote:
> On Tue, 2012-05-22 at 10:29 -0400, Trond Myklebust wrote:
>> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
>>> Client have to be initialized prior to adding it to per-net clients list,
>>> because otherwise there are races, shown below:
>>>
>>> CPU#0					CPU#1
>>> _____					_____
>>>
>>> nfs_get_client
>>> nfs_alloc_client
>>> list_add(..., nfs_client_list)
>>> 					rpc_fill_super
>>> 					rpc_pipefs_event
>>> 					nfs_get_client_for_event
>>> 					__rpc_pipefs_event
>>> 					(clp->cl_rpcclient is uninitialized)
>>> 					BUG()
>>> init_client
>>> clp->cl_rpcclient = ...
>>>
>>
>> Why not simply change nfs_get_client_for_event() so that it doesn't
>> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
>>
>> That should ensure that it doesn't touch nfs_clients that failed to
>> initialise and/or are still in the process of being initialised.
>
> ...actually, come to think of it. Why not just add a helper function
> "bool nfs_client_active(const struct nfs_client *clp)" to
> fs/nfs/client.c that does a call to
> 	wait_event_killable(nfs_client_active_wq, clp->cl_cons_state<  NFS_CS_INITING);
> and checks the resulting value of clp->cl_cons_state?
>

Sorry, but I don't understand the idea...
Where are you proposing to call this function?
In __rpc_pipefs_event() prior to dentries creatios?


-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 15:29     ` Stanislav Kinsbursky
@ 2012-05-22 15:51       ` Myklebust, Trond
  2012-05-22 16:18         ` Stanislav Kinsbursky
  0 siblings, 1 reply; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-22 15:51 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4457 bytes --]

On Tue, 2012-05-22 at 19:29 +0400, Stanislav Kinsbursky wrote:
> On 22.05.2012 19:00, Myklebust, Trond wrote:
> > On Tue, 2012-05-22 at 10:29 -0400, Trond Myklebust wrote:
> >> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
> >>> Client have to be initialized prior to adding it to per-net clients list,
> >>> because otherwise there are races, shown below:
> >>>
> >>> CPU#0					CPU#1
> >>> _____					_____
> >>>
> >>> nfs_get_client
> >>> nfs_alloc_client
> >>> list_add(..., nfs_client_list)
> >>> 					rpc_fill_super
> >>> 					rpc_pipefs_event
> >>> 					nfs_get_client_for_event
> >>> 					__rpc_pipefs_event
> >>> 					(clp->cl_rpcclient is uninitialized)
> >>> 					BUG()
> >>> init_client
> >>> clp->cl_rpcclient = ...
> >>>
> >>
> >> Why not simply change nfs_get_client_for_event() so that it doesn't
> >> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
> >>
> >> That should ensure that it doesn't touch nfs_clients that failed to
> >> initialise and/or are still in the process of being initialised.
> >
> > ...actually, come to think of it. Why not just add a helper function
> > "bool nfs_client_active(const struct nfs_client *clp)" to
> > fs/nfs/client.c that does a call to
> > 	wait_event_killable(nfs_client_active_wq, clp->cl_cons_state<  NFS_CS_INITING);
> > and checks the resulting value of clp->cl_cons_state?
> >
> 
> Sorry, but I don't understand the idea...
> Where are you proposing to call this function?
> In __rpc_pipefs_event() prior to dentries creatios?

See below:

8<----------------------------------------------------------------------------------
>From f5b90df6381a20395d9f88a199e9e52f44267457 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <Trond.Myklebust@netapp.com>
Date: Tue, 22 May 2012 11:49:55 -0400
Subject: [PATCH] NFSv4: Fix a race in the net namespace mount notification

Since the struct nfs_client gets added to the global nfs_client_list
before it is initialised, it is possible that rpc_pipefs_event can
end up trying to create idmapper entries for such a thing.

The solution is to have the mount notification wait for the
nfs_client initialisation to complete.

Reported-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
 fs/nfs/client.c   |   14 ++++++++++++++
 fs/nfs/idmap.c    |    3 ++-
 fs/nfs/internal.h |    1 +
 3 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 60f7e4e..3fa44ef 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -592,6 +592,20 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state)
 	wake_up_all(&nfs_client_active_wq);
 }
 
+static bool nfs_client_ready(struct nfs_client *clp)
+{
+	return clp->cl_cons_state <= NFS_CS_READY;
+}
+
+int nfs_wait_client_ready(struct nfs_client *clp)
+{
+	if (wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp)) < 0)
+		return -ERESTARTSYS;
+	if (clp->cl_cons_state < 0)
+		return clp->cl_cons_state;
+	return 0;
+}
+
 /*
  * With sessions, the client is not marked ready until after a
  * successful EXCHANGE_ID and CREATE_SESSION.
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 3e8edbe..67962c8 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -558,7 +558,8 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 		return 0;
 
 	while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
-		error = __rpc_pipefs_event(clp, event, sb);
+		if (nfs_wait_client_ready(clp) == 0)
+			error = __rpc_pipefs_event(clp, event, sb);
 		nfs_put_client(clp);
 		if (error)
 			break;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index b777bda..3be00a0 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -168,6 +168,7 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
 					   struct nfs_fattr *,
 					   rpc_authflavor_t);
 extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
+extern int nfs_wait_client_ready(struct nfs_client *clp);
 extern int nfs4_check_client_ready(struct nfs_client *clp);
 extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
 					     const struct sockaddr *ds_addr,
-- 
1.7.7.6


-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 15:51       ` Myklebust, Trond
@ 2012-05-22 16:18         ` Stanislav Kinsbursky
  2012-05-22 16:43           ` Myklebust, Trond
  0 siblings, 1 reply; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-05-22 16:18 UTC (permalink / raw)
  To: Myklebust, Trond; +Cc: linux-nfs, linux-kernel, devel

On 22.05.2012 19:51, Myklebust, Trond wrote:
> On Tue, 2012-05-22 at 19:29 +0400, Stanislav Kinsbursky wrote:
>> On 22.05.2012 19:00, Myklebust, Trond wrote:
>>> On Tue, 2012-05-22 at 10:29 -0400, Trond Myklebust wrote:
>>>> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
>>>>> Client have to be initialized prior to adding it to per-net clients list,
>>>>> because otherwise there are races, shown below:
>>>>>
>>>>> CPU#0					CPU#1
>>>>> _____					_____
>>>>>
>>>>> nfs_get_client
>>>>> nfs_alloc_client
>>>>> list_add(..., nfs_client_list)
>>>>> 					rpc_fill_super
>>>>> 					rpc_pipefs_event
>>>>> 					nfs_get_client_for_event
>>>>> 					__rpc_pipefs_event
>>>>> 					(clp->cl_rpcclient is uninitialized)
>>>>> 					BUG()
>>>>> init_client
>>>>> clp->cl_rpcclient = ...
>>>>>
>>>>
>>>> Why not simply change nfs_get_client_for_event() so that it doesn't
>>>> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
>>>>
>>>> That should ensure that it doesn't touch nfs_clients that failed to
>>>> initialise and/or are still in the process of being initialised.
>>>
>>> ...actually, come to think of it. Why not just add a helper function
>>> "bool nfs_client_active(const struct nfs_client *clp)" to
>>> fs/nfs/client.c that does a call to
>>> 	wait_event_killable(nfs_client_active_wq, clp->cl_cons_state<   NFS_CS_INITING);
>>> and checks the resulting value of clp->cl_cons_state?
>>>
>>
>> Sorry, but I don't understand the idea...
>> Where are you proposing to call this function?
>> In __rpc_pipefs_event() prior to dentries creatios?
>
> See below:
>
> 8<----------------------------------------------------------------------------------
>  From f5b90df6381a20395d9f88a199e9e52f44267457 Mon Sep 17 00:00:00 2001
> From: Trond Myklebust<Trond.Myklebust@netapp.com>
> Date: Tue, 22 May 2012 11:49:55 -0400
> Subject: [PATCH] NFSv4: Fix a race in the net namespace mount notification
>
> Since the struct nfs_client gets added to the global nfs_client_list
> before it is initialised, it is possible that rpc_pipefs_event can
> end up trying to create idmapper entries for such a thing.
>
> The solution is to have the mount notification wait for the
> nfs_client initialisation to complete.
>
> Reported-by: Stanislav Kinsbursky<skinsbursky@parallels.com>
> Signed-off-by: Trond Myklebust<Trond.Myklebust@netapp.com>
> ---
>   fs/nfs/client.c   |   14 ++++++++++++++
>   fs/nfs/idmap.c    |    3 ++-
>   fs/nfs/internal.h |    1 +
>   3 files changed, 17 insertions(+), 1 deletions(-)
>
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index 60f7e4e..3fa44ef 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -592,6 +592,20 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state)
>   	wake_up_all(&nfs_client_active_wq);
>   }
>
> +static bool nfs_client_ready(struct nfs_client *clp)
> +{
> +	return clp->cl_cons_state<= NFS_CS_READY;
> +}
> +
> +int nfs_wait_client_ready(struct nfs_client *clp)
> +{
> +	if (wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp))<  0)
> +		return -ERESTARTSYS;

Ok, I see...
BTW, caller of this function is pipefs mount operation call... And when this 
mount call waits for NFS clients - it look a bit odd to me...


> +	if (clp->cl_cons_state<  0)
> +		return clp->cl_cons_state;
> +	return 0;
> +}
> +
>   /*
>    * With sessions, the client is not marked ready until after a
>    * successful EXCHANGE_ID and CREATE_SESSION.
> diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
> index 3e8edbe..67962c8 100644
> --- a/fs/nfs/idmap.c
> +++ b/fs/nfs/idmap.c
> @@ -558,7 +558,8 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
>   		return 0;
>
>   	while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
> -		error = __rpc_pipefs_event(clp, event, sb);
> +		if (nfs_wait_client_ready(clp) == 0)
> +			error = __rpc_pipefs_event(clp, event, sb);


We have another problem here.
nfs4_init_client() will try to create pipe dentries prior to set of NFS_CS_READY 
to the client. And dentries will be created since semaphore is dropped and 
per-net superblock variable is initialized already.
But __rpc_pipefs_event() relays on the fact, that no dentries present.
Looks like the problem was introduced by me in aad9487c...
So maybe we should not call "continue" instead "__rpc_pipefs_event()", when 
client becomes ready?
Looks like this will allow us to handle such races.


>   		nfs_put_client(clp);
>   		if (error)
>   			break;
> diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
> index b777bda..3be00a0 100644
> --- a/fs/nfs/internal.h
> +++ b/fs/nfs/internal.h
> @@ -168,6 +168,7 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
>   					   struct nfs_fattr *,
>   					   rpc_authflavor_t);
>   extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
> +extern int nfs_wait_client_ready(struct nfs_client *clp);
>   extern int nfs4_check_client_ready(struct nfs_client *clp);
>   extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
>   					     const struct sockaddr *ds_addr,


-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 16:18         ` Stanislav Kinsbursky
@ 2012-05-22 16:43           ` Myklebust, Trond
  2012-05-22 20:32             ` Myklebust, Trond
  0 siblings, 1 reply; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-22 16:43 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4997 bytes --]

On Tue, 2012-05-22 at 20:18 +0400, Stanislav Kinsbursky wrote:
> On 22.05.2012 19:51, Myklebust, Trond wrote:
> > On Tue, 2012-05-22 at 19:29 +0400, Stanislav Kinsbursky wrote:
> >> On 22.05.2012 19:00, Myklebust, Trond wrote:
> >>> On Tue, 2012-05-22 at 10:29 -0400, Trond Myklebust wrote:
> >>>> On Tue, 2012-05-22 at 16:40 +0400, Stanislav Kinsbursky wrote:
> >>>>> Client have to be initialized prior to adding it to per-net clients list,
> >>>>> because otherwise there are races, shown below:
> >>>>>
> >>>>> CPU#0					CPU#1
> >>>>> _____					_____
> >>>>>
> >>>>> nfs_get_client
> >>>>> nfs_alloc_client
> >>>>> list_add(..., nfs_client_list)
> >>>>> 					rpc_fill_super
> >>>>> 					rpc_pipefs_event
> >>>>> 					nfs_get_client_for_event
> >>>>> 					__rpc_pipefs_event
> >>>>> 					(clp->cl_rpcclient is uninitialized)
> >>>>> 					BUG()
> >>>>> init_client
> >>>>> clp->cl_rpcclient = ...
> >>>>>
> >>>>
> >>>> Why not simply change nfs_get_client_for_event() so that it doesn't
> >>>> touch nfs_clients that have clp->cl_cons_state!=NFS_CS_READY?
> >>>>
> >>>> That should ensure that it doesn't touch nfs_clients that failed to
> >>>> initialise and/or are still in the process of being initialised.
> >>>
> >>> ...actually, come to think of it. Why not just add a helper function
> >>> "bool nfs_client_active(const struct nfs_client *clp)" to
> >>> fs/nfs/client.c that does a call to
> >>> 	wait_event_killable(nfs_client_active_wq, clp->cl_cons_state<   NFS_CS_INITING);
> >>> and checks the resulting value of clp->cl_cons_state?
> >>>
> >>
> >> Sorry, but I don't understand the idea...
> >> Where are you proposing to call this function?
> >> In __rpc_pipefs_event() prior to dentries creatios?
> >
> > See below:
> >
> > 8<----------------------------------------------------------------------------------
> >  From f5b90df6381a20395d9f88a199e9e52f44267457 Mon Sep 17 00:00:00 2001
> > From: Trond Myklebust<Trond.Myklebust@netapp.com>
> > Date: Tue, 22 May 2012 11:49:55 -0400
> > Subject: [PATCH] NFSv4: Fix a race in the net namespace mount notification
> >
> > Since the struct nfs_client gets added to the global nfs_client_list
> > before it is initialised, it is possible that rpc_pipefs_event can
> > end up trying to create idmapper entries for such a thing.
> >
> > The solution is to have the mount notification wait for the
> > nfs_client initialisation to complete.
> >
> > Reported-by: Stanislav Kinsbursky<skinsbursky@parallels.com>
> > Signed-off-by: Trond Myklebust<Trond.Myklebust@netapp.com>
> > ---
> >   fs/nfs/client.c   |   14 ++++++++++++++
> >   fs/nfs/idmap.c    |    3 ++-
> >   fs/nfs/internal.h |    1 +
> >   3 files changed, 17 insertions(+), 1 deletions(-)
> >
> > diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> > index 60f7e4e..3fa44ef 100644
> > --- a/fs/nfs/client.c
> > +++ b/fs/nfs/client.c
> > @@ -592,6 +592,20 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state)
> >   	wake_up_all(&nfs_client_active_wq);
> >   }
> >
> > +static bool nfs_client_ready(struct nfs_client *clp)
> > +{
> > +	return clp->cl_cons_state<= NFS_CS_READY;
> > +}
> > +
> > +int nfs_wait_client_ready(struct nfs_client *clp)
> > +{
> > +	if (wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp))<  0)
> > +		return -ERESTARTSYS;
> 
> Ok, I see...
> BTW, caller of this function is pipefs mount operation call... And when this 
> mount call waits for NFS clients - it look a bit odd to me...
> 
> 
> > +	if (clp->cl_cons_state<  0)
> > +		return clp->cl_cons_state;
> > +	return 0;
> > +}
> > +
> >   /*
> >    * With sessions, the client is not marked ready until after a
> >    * successful EXCHANGE_ID and CREATE_SESSION.
> > diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
> > index 3e8edbe..67962c8 100644
> > --- a/fs/nfs/idmap.c
> > +++ b/fs/nfs/idmap.c
> > @@ -558,7 +558,8 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
> >   		return 0;
> >
> >   	while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
> > -		error = __rpc_pipefs_event(clp, event, sb);
> > +		if (nfs_wait_client_ready(clp) == 0)
> > +			error = __rpc_pipefs_event(clp, event, sb);
> 
> 
> We have another problem here.
> nfs4_init_client() will try to create pipe dentries prior to set of NFS_CS_READY 
> to the client. And dentries will be created since semaphore is dropped and 
> per-net superblock variable is initialized already.
> But __rpc_pipefs_event() relays on the fact, that no dentries present.
> Looks like the problem was introduced by me in aad9487c...
> So maybe we should not call "continue" instead "__rpc_pipefs_event()", when 
> client becomes ready?
> Looks like this will allow us to handle such races.

Let me rework this patch a bit...

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 16:43           ` Myklebust, Trond
@ 2012-05-22 20:32             ` Myklebust, Trond
  2012-05-23 11:30               ` Stanislav Kinsbursky
  0 siblings, 1 reply; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-22 20:32 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4095 bytes --]

On Tue, 2012-05-22 at 12:43 -0400, Trond Myklebust wrote:
> On Tue, 2012-05-22 at 20:18 +0400, Stanislav Kinsbursky wrote:
> > We have another problem here.
> > nfs4_init_client() will try to create pipe dentries prior to set of NFS_CS_READY 
> > to the client. And dentries will be created since semaphore is dropped and 
> > per-net superblock variable is initialized already.
> > But __rpc_pipefs_event() relays on the fact, that no dentries present.
> > Looks like the problem was introduced by me in aad9487c...
> > So maybe we should not call "continue" instead "__rpc_pipefs_event()", when 
> > client becomes ready?
> > Looks like this will allow us to handle such races.
> 
> Let me rework this patch a bit...

The following is ugly, but it should be demonstrably correct, and will
ensure that __rpc_pipefs_event() will only be called for fully
initialised nfs_clients...

8<---------------------------------------------------------------------
>From 90c3b9fe9faeae32c8f629e8b6cbf5f50bb9b295 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <Trond.Myklebust@netapp.com>
Date: Tue, 22 May 2012 16:22:50 -0400
Subject: [PATCH 1/2] NFSv4: Fix a race in the net namespace mount
 notification

Since the struct nfs_client gets added to the global nfs_client_list
before it is initialised, it is possible that rpc_pipefs_event can
end up trying to create idmapper entries on such a thing.

The solution is to have the mount notification wait for the
initialisation of each nfs_client to complete, and then to
skip any entries for which the it failed.

Reported-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
 fs/nfs/client.c   |   10 ++++++++++
 fs/nfs/idmap.c    |   15 +++++++++++++++
 fs/nfs/internal.h |    1 +
 3 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 60f7e4e..d3c8553 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -583,6 +583,16 @@ found_client:
 	return clp;
 }
 
+static bool nfs_client_ready(const struct nfs_client *clp)
+{
+	return clp->cl_cons_state <= NFS_CS_READY;
+}
+
+int nfs_wait_client_ready(const struct nfs_client *clp)
+{
+	return wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp));
+}
+
 /*
  * Mark a server as ready or failed
  */
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 3e8edbe..c0753c5 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -530,9 +530,24 @@ static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
 	struct nfs_net *nn = net_generic(net, nfs_net_id);
 	struct dentry *cl_dentry;
 	struct nfs_client *clp;
+	int err;
 
+restart:
 	spin_lock(&nn->nfs_client_lock);
 	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
+		/* Wait for initialisation to finish */
+		if (clp->cl_cons_state > NFS_CS_READY) {
+			atomic_inc(&clp->cl_count);
+			spin_unlock(&nn->nfs_client_lock);
+			err = nfs_wait_client_ready(clp);
+			nfs_put_client(clp);
+			if (err)
+				return NULL;
+			goto restart;
+		}
+		/* Skip nfs_clients that failed to initialise */
+		if (clp->cl_cons_state < 0)
+			continue;
 		if (clp->rpc_ops != &nfs_v4_clientops)
 			continue;
 		cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index b777bda..3ee4040 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -168,6 +168,7 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
 					   struct nfs_fattr *,
 					   rpc_authflavor_t);
 extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
+extern int nfs_wait_client_ready(const struct nfs_client *clp);
 extern int nfs4_check_client_ready(struct nfs_client *clp);
 extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
 					     const struct sockaddr *ds_addr,
-- 
1.7.7.6


-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-22 20:32             ` Myklebust, Trond
@ 2012-05-23 11:30               ` Stanislav Kinsbursky
  2012-05-23 12:09                 ` Kinsbursky Stanislav
  2012-05-23 13:57                 ` Myklebust, Trond
  0 siblings, 2 replies; 13+ messages in thread
From: Stanislav Kinsbursky @ 2012-05-23 11:30 UTC (permalink / raw)
  To: Myklebust, Trond; +Cc: linux-nfs, linux-kernel, devel

On 23.05.2012 00:32, Myklebust, Trond wrote:
> On Tue, 2012-05-22 at 12:43 -0400, Trond Myklebust wrote:
>> On Tue, 2012-05-22 at 20:18 +0400, Stanislav Kinsbursky wrote:
>>> We have another problem here.
>>> nfs4_init_client() will try to create pipe dentries prior to set of NFS_CS_READY
>>> to the client. And dentries will be created since semaphore is dropped and
>>> per-net superblock variable is initialized already.
>>> But __rpc_pipefs_event() relays on the fact, that no dentries present.
>>> Looks like the problem was introduced by me in aad9487c...
>>> So maybe we should not call "continue" instead "__rpc_pipefs_event()", when
>>> client becomes ready?
>>> Looks like this will allow us to handle such races.
>>
>> Let me rework this patch a bit...
>
> The following is ugly, but it should be demonstrably correct, and will
> ensure that __rpc_pipefs_event() will only be called for fully
> initialised nfs_clients...
>
> 8<---------------------------------------------------------------------
>  From 90c3b9fe9faeae32c8f629e8b6cbf5f50bb9b295 Mon Sep 17 00:00:00 2001
> From: Trond Myklebust<Trond.Myklebust@netapp.com>
> Date: Tue, 22 May 2012 16:22:50 -0400
> Subject: [PATCH 1/2] NFSv4: Fix a race in the net namespace mount
>   notification
>
> Since the struct nfs_client gets added to the global nfs_client_list
> before it is initialised, it is possible that rpc_pipefs_event can
> end up trying to create idmapper entries on such a thing.
>
> The solution is to have the mount notification wait for the
> initialisation of each nfs_client to complete, and then to
> skip any entries for which the it failed.
>
> Reported-by: Stanislav Kinsbursky<skinsbursky@parallels.com>
> Signed-off-by: Trond Myklebust<Trond.Myklebust@netapp.com>
> ---
>   fs/nfs/client.c   |   10 ++++++++++
>   fs/nfs/idmap.c    |   15 +++++++++++++++
>   fs/nfs/internal.h |    1 +
>   3 files changed, 26 insertions(+), 0 deletions(-)
>
> diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> index 60f7e4e..d3c8553 100644
> --- a/fs/nfs/client.c
> +++ b/fs/nfs/client.c
> @@ -583,6 +583,16 @@ found_client:
>   	return clp;
>   }
>
> +static bool nfs_client_ready(const struct nfs_client *clp)
> +{
> +	return clp->cl_cons_state<= NFS_CS_READY;
> +}
> +
> +int nfs_wait_client_ready(const struct nfs_client *clp)
> +{
> +	return wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp));
> +}
> +
>   /*
>    * Mark a server as ready or failed
>    */
> diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
> index 3e8edbe..c0753c5 100644
> --- a/fs/nfs/idmap.c
> +++ b/fs/nfs/idmap.c
> @@ -530,9 +530,24 @@ static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
>   	struct nfs_net *nn = net_generic(net, nfs_net_id);
>   	struct dentry *cl_dentry;
>   	struct nfs_client *clp;
> +	int err;
>
> +restart:
>   	spin_lock(&nn->nfs_client_lock);
>   	list_for_each_entry(clp,&nn->nfs_client_list, cl_share_link) {
> +		/* Wait for initialisation to finish */
> +		if (clp->cl_cons_state>  NFS_CS_READY) {
> +			atomic_inc(&clp->cl_count);
> +			spin_unlock(&nn->nfs_client_lock);
> +			err = nfs_wait_client_ready(clp);


What about NFSv4.1 ?
It's clients NFS_CS_READY status depends on session establishing RPC calls...
Which in turn can hung up pipefs mount call...

Moreover, looks like pipefs dentries creation have to be synchronized by 
nfs_client_lock somehow... Otherwise because of races we can get a client 
without pipe dentry....

> +			nfs_put_client(clp);
> +			if (err)
> +				return NULL;
> +			goto restart;
> +		}
> +		/* Skip nfs_clients that failed to initialise */
> +		if (clp->cl_cons_state<  0)
> +			continue;
>   		if (clp->rpc_ops !=&nfs_v4_clientops)
>   			continue;
>   		cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
> diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
> index b777bda..3ee4040 100644
> --- a/fs/nfs/internal.h
> +++ b/fs/nfs/internal.h
> @@ -168,6 +168,7 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
>   					   struct nfs_fattr *,
>   					   rpc_authflavor_t);
>   extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
> +extern int nfs_wait_client_ready(const struct nfs_client *clp);
>   extern int nfs4_check_client_ready(struct nfs_client *clp);
>   extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
>   					     const struct sockaddr *ds_addr,


-- 
Best regards,
Stanislav Kinsbursky

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-23 11:30               ` Stanislav Kinsbursky
@ 2012-05-23 12:09                 ` Kinsbursky Stanislav
  2012-05-23 13:57                 ` Myklebust, Trond
  1 sibling, 0 replies; 13+ messages in thread
From: Kinsbursky Stanislav @ 2012-05-23 12:09 UTC (permalink / raw)
  To: Myklebust, Trond; +Cc: linux-nfs, linux-kernel, devel

On 23.05.2012 15:30, Stanislav Kinsbursky wrote:
> Moreover, looks like pipefs dentries creation have to be synchronized by
> nfs_client_lock somehow... Otherwise because of races we can get a client
> without pipe dentry....

Taking this back.

-- 
Best regards,
Stanislav Kinsbursky


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] NFS: init client before declaration
  2012-05-23 11:30               ` Stanislav Kinsbursky
  2012-05-23 12:09                 ` Kinsbursky Stanislav
@ 2012-05-23 13:57                 ` Myklebust, Trond
  1 sibling, 0 replies; 13+ messages in thread
From: Myklebust, Trond @ 2012-05-23 13:57 UTC (permalink / raw)
  To: Stanislav Kinsbursky; +Cc: linux-nfs, linux-kernel, devel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3923 bytes --]

On Wed, 2012-05-23 at 15:30 +0400, Stanislav Kinsbursky wrote:
> On 23.05.2012 00:32, Myklebust, Trond wrote:
> > On Tue, 2012-05-22 at 12:43 -0400, Trond Myklebust wrote:
> >> On Tue, 2012-05-22 at 20:18 +0400, Stanislav Kinsbursky wrote:
> >>> We have another problem here.
> >>> nfs4_init_client() will try to create pipe dentries prior to set of NFS_CS_READY
> >>> to the client. And dentries will be created since semaphore is dropped and
> >>> per-net superblock variable is initialized already.
> >>> But __rpc_pipefs_event() relays on the fact, that no dentries present.
> >>> Looks like the problem was introduced by me in aad9487c...
> >>> So maybe we should not call "continue" instead "__rpc_pipefs_event()", when
> >>> client becomes ready?
> >>> Looks like this will allow us to handle such races.
> >>
> >> Let me rework this patch a bit...
> >
> > The following is ugly, but it should be demonstrably correct, and will
> > ensure that __rpc_pipefs_event() will only be called for fully
> > initialised nfs_clients...
> >
> > 8<---------------------------------------------------------------------
> >  From 90c3b9fe9faeae32c8f629e8b6cbf5f50bb9b295 Mon Sep 17 00:00:00 2001
> > From: Trond Myklebust<Trond.Myklebust@netapp.com>
> > Date: Tue, 22 May 2012 16:22:50 -0400
> > Subject: [PATCH 1/2] NFSv4: Fix a race in the net namespace mount
> >   notification
> >
> > Since the struct nfs_client gets added to the global nfs_client_list
> > before it is initialised, it is possible that rpc_pipefs_event can
> > end up trying to create idmapper entries on such a thing.
> >
> > The solution is to have the mount notification wait for the
> > initialisation of each nfs_client to complete, and then to
> > skip any entries for which the it failed.
> >
> > Reported-by: Stanislav Kinsbursky<skinsbursky@parallels.com>
> > Signed-off-by: Trond Myklebust<Trond.Myklebust@netapp.com>
> > ---
> >   fs/nfs/client.c   |   10 ++++++++++
> >   fs/nfs/idmap.c    |   15 +++++++++++++++
> >   fs/nfs/internal.h |    1 +
> >   3 files changed, 26 insertions(+), 0 deletions(-)
> >
> > diff --git a/fs/nfs/client.c b/fs/nfs/client.c
> > index 60f7e4e..d3c8553 100644
> > --- a/fs/nfs/client.c
> > +++ b/fs/nfs/client.c
> > @@ -583,6 +583,16 @@ found_client:
> >   	return clp;
> >   }
> >
> > +static bool nfs_client_ready(const struct nfs_client *clp)
> > +{
> > +	return clp->cl_cons_state<= NFS_CS_READY;
> > +}
> > +
> > +int nfs_wait_client_ready(const struct nfs_client *clp)
> > +{
> > +	return wait_event_killable(nfs_client_active_wq, nfs_client_ready(clp));
> > +}
> > +
> >   /*
> >    * Mark a server as ready or failed
> >    */
> > diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
> > index 3e8edbe..c0753c5 100644
> > --- a/fs/nfs/idmap.c
> > +++ b/fs/nfs/idmap.c
> > @@ -530,9 +530,24 @@ static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
> >   	struct nfs_net *nn = net_generic(net, nfs_net_id);
> >   	struct dentry *cl_dentry;
> >   	struct nfs_client *clp;
> > +	int err;
> >
> > +restart:
> >   	spin_lock(&nn->nfs_client_lock);
> >   	list_for_each_entry(clp,&nn->nfs_client_list, cl_share_link) {
> > +		/* Wait for initialisation to finish */
> > +		if (clp->cl_cons_state>  NFS_CS_READY) {
> > +			atomic_inc(&clp->cl_count);
> > +			spin_unlock(&nn->nfs_client_lock);
> > +			err = nfs_wait_client_ready(clp);
> 
> 
> What about NFSv4.1 ?
> It's clients NFS_CS_READY status depends on session establishing RPC calls...
> Which in turn can hung up pipefs mount call...

The alternative then is to wait for cl_cons_state != NFS_CS_INITING.
That shouldn't require any upcalls, and so shouldn't be able to
deadlock.

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2012-05-23 13:57 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-22 12:40 [PATCH] NFS: init client before declaration Stanislav Kinsbursky
2012-05-22 13:47 ` Chuck Lever
2012-05-22 14:29 ` Myklebust, Trond
2012-05-22 15:00   ` Myklebust, Trond
2012-05-22 15:29     ` Stanislav Kinsbursky
2012-05-22 15:51       ` Myklebust, Trond
2012-05-22 16:18         ` Stanislav Kinsbursky
2012-05-22 16:43           ` Myklebust, Trond
2012-05-22 20:32             ` Myklebust, Trond
2012-05-23 11:30               ` Stanislav Kinsbursky
2012-05-23 12:09                 ` Kinsbursky Stanislav
2012-05-23 13:57                 ` Myklebust, Trond
2012-05-22 15:03   ` Stanislav Kinsbursky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).