From a4dff1bc492ee4a2184d384ae8b5bcab5859e150 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 20 Apr 2012 18:11:02 +0400 Subject: SUNRPC: skip dead but not buried clients on PipeFS events These clients can't be safely dereferenced if their counter in 0. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/sunrpc/clnt.c') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6797246..d10ebc4 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -218,7 +218,8 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) continue; - atomic_inc(&clnt->cl_count); + if (atomic_inc_not_zero(&clnt->cl_count) == 0) + continue; spin_unlock(&sn->rpc_client_lock); return clnt; } -- cgit v1.1 From 7aab449e5a2ebfa9c5116e87e16536bc4195e4de Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 20 Apr 2012 18:19:18 +0400 Subject: SUNRPC: skip clients with program without PipeFS entries 1) This is sane. 2) Otherwise there will be soft lockup: do { rpc_get_client_for_event (clnt->cl_dentry == NULL ==> choose) __rpc_pipefs_event (clnt->cl_program->pipe_dir_name == NULL ==> return) } while (1) Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sunrpc/clnt.c') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d10ebc4..8a19849 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -184,8 +184,6 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, switch (event) { case RPC_PIPEFS_MOUNT: - if (clnt->cl_program->pipe_dir_name == NULL) - break; dentry = rpc_setup_pipedir_sb(sb, clnt, clnt->cl_program->pipe_dir_name); BUG_ON(dentry == NULL); @@ -215,6 +213,8 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) spin_lock(&sn->rpc_client_lock); list_for_each_entry(clnt, &sn->all_clients, cl_clients) { + if (clnt->cl_program->pipe_dir_name == NULL) + break; if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) continue; -- cgit v1.1 From ea8cfa06795bb30d2ea61f503ef129284492c06a Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 27 Apr 2012 13:00:17 +0400 Subject: SUNRPC: traverse clients tree on PipeFS event v2: recursion was replaced by loop If client is a clone, then it's parent can not be in the list. But parent's Pipefs dentries have to be created and destroyed. Note: event skip helper for clients introduced Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'net/sunrpc/clnt.c') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 8a19849..d127bd7 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -176,8 +176,16 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) return 0; } -static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, - struct super_block *sb) +static inline int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) +{ + if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || + ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) + return 1; + return 0; +} + +static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, + struct super_block *sb) { struct dentry *dentry; int err = 0; @@ -206,6 +214,20 @@ static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, return err; } +static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event, + struct super_block *sb) +{ + int error = 0; + + for (;; clnt = clnt->cl_parent) { + if (!rpc_clnt_skip_event(clnt, event)) + error = __rpc_clnt_handle_event(clnt, event, sb); + if (error || clnt == clnt->cl_parent) + break; + } + return error; +} + static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); @@ -215,8 +237,7 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) list_for_each_entry(clnt, &sn->all_clients, cl_clients) { if (clnt->cl_program->pipe_dir_name == NULL) break; - if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || - ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) + if (rpc_clnt_skip_event(clnt, event)) continue; if (atomic_inc_not_zero(&clnt->cl_count) == 0) continue; -- cgit v1.1 From cbbb34498f8b2b26cbdc79532c8a2ee5cd1e756a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 30 Apr 2012 11:52:40 -0400 Subject: SUNRPC: RPC client must use the current utsname hostname string Now that the rpc client is namespace aware, it needs to use the utsname of the process that created it instead of using the init_utsname. Both rpc_new_client and rpc_clone_client need to be fixed. Signed-off-by: Trond Myklebust Cc: Stanislav Kinsbursky --- net/sunrpc/clnt.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'net/sunrpc/clnt.c') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d127bd7..adf2990 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -279,6 +279,14 @@ void rpc_clients_notifier_unregister(void) return rpc_pipefs_notifier_unregister(&rpc_clients_block); } +static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) +{ + clnt->cl_nodelen = strlen(nodename); + if (clnt->cl_nodelen > UNX_MAXNODENAME) + clnt->cl_nodelen = UNX_MAXNODENAME; + memcpy(clnt->cl_nodename, nodename, clnt->cl_nodelen); +} + static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) { const struct rpc_program *program = args->program; @@ -359,10 +367,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru } /* save the nodename */ - clnt->cl_nodelen = strlen(init_utsname()->nodename); - if (clnt->cl_nodelen > UNX_MAXNODENAME) - clnt->cl_nodelen = UNX_MAXNODENAME; - memcpy(clnt->cl_nodename, init_utsname()->nodename, clnt->cl_nodelen); + rpc_clnt_set_nodename(clnt, utsname()->nodename); rpc_register_client(clnt); return clnt; @@ -521,6 +526,7 @@ rpc_clone_client(struct rpc_clnt *clnt) err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); if (err != 0) goto out_no_path; + rpc_clnt_set_nodename(new, utsname()->nodename); if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); atomic_inc(&clnt->cl_count); -- cgit v1.1