Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SUNRPC: handle RPC client pipefs dentries by network namespace aware routines

v2:
1) "Over-put" of PipeFS mount point fixed. Fix is ugly, but allows to bisect
the patch set. And it will be removed later in the series.

This patch makes RPC clients PipeFs dentries allocations in it's owner network
namespace context.
RPC client pipefs dentries creation logic has been changed:
1) Pipefs dentries creation by sb was moved to separated function, which will
be used for handling PipeFS mount notification.
2) Initial value of RPC client PipeFS dir dentry is set no NULL now.

RPC client pipefs dentries cleanup logic has been changed:
1) Cleanup is done now in separated rpc_remove_pipedir() function, which takes
care about pipefs superblock locking.

Also this patch removes slashes from cb_program.pipe_dir_name and from
NFS_PIPE_DIRNAME to make rpc_d_lookup_sb() work. This doesn't affect
vfs_path_lookup() results in nfs4blocklayout_init() since this slash is cutted
off anyway in link_path_walk().

Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Stanislav Kinsbursky and committed by
Trond Myklebust
0157d021 c239d83b

+69 -38
+1 -1
fs/nfsd/nfs4callback.c
··· 622 622 .nrvers = ARRAY_SIZE(nfs_cb_version), 623 623 .version = nfs_cb_version, 624 624 .stats = &cb_stats, 625 - .pipe_dir_name = "/nfsd4_cb", 625 + .pipe_dir_name = "nfsd4_cb", 626 626 }; 627 627 628 628 static int max_cb_time(void)
+1 -1
include/linux/nfs.h
··· 29 29 #define NFS_MNT_VERSION 1 30 30 #define NFS_MNT3_VERSION 3 31 31 32 - #define NFS_PIPE_DIRNAME "/nfs" 32 + #define NFS_PIPE_DIRNAME "nfs" 33 33 34 34 /* 35 35 * NFS stats. The good thing with these values is that NFSv3 errors are
+67 -36
net/sunrpc/clnt.c
··· 93 93 spin_unlock(&rpc_client_lock); 94 94 } 95 95 96 - static int 97 - rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) 96 + static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) 97 + { 98 + if (clnt->cl_path.dentry) 99 + rpc_remove_client_dir(clnt->cl_path.dentry); 100 + clnt->cl_path.dentry = NULL; 101 + } 102 + 103 + static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) 104 + { 105 + struct super_block *pipefs_sb; 106 + int put_mnt = 0; 107 + 108 + pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); 109 + if (pipefs_sb) { 110 + if (clnt->cl_path.dentry) 111 + put_mnt = 1; 112 + __rpc_clnt_remove_pipedir(clnt); 113 + rpc_put_sb_net(clnt->cl_xprt->xprt_net); 114 + } 115 + if (put_mnt) 116 + rpc_put_mount(); 117 + } 118 + 119 + static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, 120 + struct rpc_clnt *clnt, char *dir_name) 98 121 { 99 122 static uint32_t clntid; 100 - struct path path, dir; 101 123 char name[15]; 102 124 struct qstr q = { 103 125 .name = name, 104 126 }; 127 + struct dentry *dir, *dentry; 105 128 int error; 106 129 130 + dir = rpc_d_lookup_sb(sb, dir_name); 131 + if (dir == NULL) 132 + return dir; 133 + for (;;) { 134 + q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); 135 + name[sizeof(name) - 1] = '\0'; 136 + q.hash = full_name_hash(q.name, q.len); 137 + dentry = rpc_create_client_dir(dir, &q, clnt); 138 + if (!IS_ERR(dentry)) 139 + break; 140 + error = PTR_ERR(dentry); 141 + if (error != -EEXIST) { 142 + printk(KERN_INFO "RPC: Couldn't create pipefs entry" 143 + " %s/%s, error %d\n", 144 + dir_name, name, error); 145 + break; 146 + } 147 + } 148 + dput(dir); 149 + return dentry; 150 + } 151 + 152 + static int 153 + rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) 154 + { 155 + struct super_block *pipefs_sb; 156 + struct path path; 157 + 107 158 clnt->cl_path.mnt = ERR_PTR(-ENOENT); 108 - clnt->cl_path.dentry = ERR_PTR(-ENOENT); 159 + clnt->cl_path.dentry = NULL; 109 160 if (dir_name == NULL) 110 161 return 0; 111 162 112 163 path.mnt = rpc_get_mount(); 113 164 if (IS_ERR(path.mnt)) 114 165 return PTR_ERR(path.mnt); 115 - error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir); 116 - if (error) 117 - goto err; 118 - 119 - for (;;) { 120 - q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++); 121 - name[sizeof(name) - 1] = '\0'; 122 - q.hash = full_name_hash(q.name, q.len); 123 - path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt); 124 - if (!IS_ERR(path.dentry)) 125 - break; 126 - error = PTR_ERR(path.dentry); 127 - if (error != -EEXIST) { 128 - printk(KERN_INFO "RPC: Couldn't create pipefs entry" 129 - " %s/%s, error %d\n", 130 - dir_name, name, error); 131 - goto err_path_put; 132 - } 166 + pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); 167 + if (!pipefs_sb) { 168 + rpc_put_mount(); 169 + return -ENOENT; 133 170 } 134 - path_put(&dir); 171 + path.dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); 172 + rpc_put_sb_net(clnt->cl_xprt->xprt_net); 173 + if (IS_ERR(path.dentry)) { 174 + rpc_put_mount(); 175 + return PTR_ERR(path.dentry); 176 + } 135 177 clnt->cl_path = path; 136 178 return 0; 137 - err_path_put: 138 - path_put(&dir); 139 - err: 140 - rpc_put_mount(); 141 - return error; 142 179 } 143 180 144 181 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) ··· 283 246 return clnt; 284 247 285 248 out_no_auth: 286 - if (!IS_ERR(clnt->cl_path.dentry)) { 287 - rpc_remove_client_dir(clnt->cl_path.dentry); 288 - rpc_put_mount(); 289 - } 249 + rpc_clnt_remove_pipedir(clnt); 290 250 out_no_path: 291 251 kfree(clnt->cl_principal); 292 252 out_no_principal: ··· 508 474 { 509 475 dprintk("RPC: destroying %s client for %s\n", 510 476 clnt->cl_protname, clnt->cl_server); 511 - if (!IS_ERR(clnt->cl_path.dentry)) { 512 - rpc_remove_client_dir(clnt->cl_path.dentry); 513 - rpc_put_mount(); 514 - } 477 + rpc_clnt_remove_pipedir(clnt); 515 478 if (clnt->cl_parent != clnt) { 516 479 rpc_release_client(clnt->cl_parent); 517 480 goto out_free;