From 76fa66657900071016f2bae61de28f059f3f2abf Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 2 Jul 2013 13:00:52 -0400 Subject: rpc_pipe: set dentry operations at d_alloc time Currently the way these get set is a little convoluted. If the dentry is allocated via lookup from userland, then it gets set by simple_lookup. If it gets allocated when the kernel is populating the directory, then it gets set via __rpc_lookup_create_exclusive, which has to check whether they might already be set. Between both of these, this ensures that all dentries have their d_op pointer set. Instead of doing that, just have them set at d_alloc time by pointing sb->s_d_op at them. With that change, we no longer want the lookup op to set them, so we must move to using our own lookup routine. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'net/sunrpc') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 4679df5a6d50..c5f6812ca06a 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -480,6 +480,23 @@ static const struct dentry_operations rpc_dentry_operations = { .d_delete = rpc_delete_dentry, }; +/* + * Lookup the data. This is trivial - if the dentry didn't already + * exist, we know it is negative. + */ +static struct dentry * +rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) +{ + if (dentry->d_name.len > NAME_MAX) + return ERR_PTR(-ENAMETOOLONG); + d_add(dentry, NULL); + return NULL; +} + +const struct inode_operations rpc_dir_inode_operations = { + .lookup = rpc_lookup, +}; + static struct inode * rpc_get_inode(struct super_block *sb, umode_t mode) { @@ -492,7 +509,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode) switch (mode & S_IFMT) { case S_IFDIR: inode->i_fop = &simple_dir_operations; - inode->i_op = &simple_dir_inode_operations; + inode->i_op = &rpc_dir_inode_operations; inc_nlink(inode); default: break; @@ -666,11 +683,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, if (!dentry) return ERR_PTR(-ENOMEM); } - if (dentry->d_inode == NULL) { - if (!dentry->d_op) - d_set_d_op(dentry, &rpc_dentry_operations); + if (dentry->d_inode == NULL) return dentry; - } dput(dentry); return ERR_PTR(-EEXIST); } @@ -1117,6 +1131,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = RPCAUTH_GSSMAGIC; sb->s_op = &s_ops; + sb->s_d_op = &rpc_dentry_operations; sb->s_time_gran = 1; inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); -- cgit v1.2.3 From 4f8568cb5290295c384d5c1328c52790e33a8a0d Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 10 Jul 2013 09:17:14 +0800 Subject: rpc_pipe: rpc_dir_inode_operations can be static Hi Jeff, FYI, there are new sparse warnings show up in tree: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git nfs-for-next head: 296afe1f58d55fd56ed85daaafafcfee39f59ece commit: 76fa66657900071016f2bae61de28f059f3f2abf [2/5] rpc_pipe: set dentry operations at d_alloc time >> net/sunrpc/rpc_pipe.c:496:31: sparse: symbol 'rpc_dir_inode_operations' was not declared. Should it be static? Please consider folding the attached diff :-) Signed-off-by: Fengguang Wu Signed-off-by: Trond Myklebust --- net/sunrpc/rpc_pipe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sunrpc') diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index c5f6812ca06a..61239a2cb786 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -493,7 +493,7 @@ rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) return NULL; } -const struct inode_operations rpc_dir_inode_operations = { +static const struct inode_operations rpc_dir_inode_operations = { .lookup = rpc_lookup, }; -- cgit v1.2.3 From eeee245268c951262b861bc1be4e9dc812352499 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 10 Jul 2013 15:33:01 -0400 Subject: SUNRPC: Fix a deadlock in rpc_client_register() Commit 384816051ca9125cd54750e59c780c2a2655fa4f (SUNRPC: fix races on PipeFS MOUNT notifications) introduces a regression when we call rpc_setup_pipedir() with RPCSEC_GSS as the auth flavour. By calling rpcauth_create() while holding the sn->pipefs_sb_lock, we end up deadlocking in gss_pipes_dentries_create_net(). Fix is to register the client and release the mutex before calling rpcauth_create(). Reported-by: Weston Andros Adamson Tested-by: Weston Andros Adamson Cc: Stanislav Kinsbursky Cc: # : 3848160: SUNRPC: fix races on PipeFS MOUNT Cc: # : e73f4cc: SUNRPC: split client creation Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'net/sunrpc') diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f0339ae9bf37..aa401560777b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -290,7 +290,7 @@ static int rpc_client_register(const struct rpc_create_args *args, struct rpc_auth *auth; struct net *net = rpc_net_ns(clnt); struct super_block *pipefs_sb; - int err = 0; + int err; pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { @@ -299,6 +299,10 @@ static int rpc_client_register(const struct rpc_create_args *args, goto out; } + rpc_register_client(clnt); + if (pipefs_sb) + rpc_put_sb_net(net); + auth = rpcauth_create(args->authflavor, clnt); if (IS_ERR(auth)) { dprintk("RPC: Couldn't create auth handle (flavor %u)\n", @@ -306,16 +310,14 @@ static int rpc_client_register(const struct rpc_create_args *args, err = PTR_ERR(auth); goto err_auth; } - - rpc_register_client(clnt); + return 0; +err_auth: + pipefs_sb = rpc_get_sb_net(net); + __rpc_clnt_remove_pipedir(clnt); out: if (pipefs_sb) rpc_put_sb_net(net); return err; - -err_auth: - __rpc_clnt_remove_pipedir(clnt); - goto out; } static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) -- cgit v1.2.3