Loading fs/nfs/idmap.c +34 −150 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ struct idmap_legacy_upcalldata { }; struct idmap { struct rpc_pipe_dir_object idmap_pdo; struct rpc_pipe *idmap_pipe; struct idmap_legacy_upcalldata *idmap_upcall_data; struct mutex idmap_mutex; Loading Loading @@ -402,18 +403,23 @@ static struct key_type key_type_id_resolver_legacy = { .request_key = nfs_idmap_legacy_upcall, }; static void __nfs_idmap_unregister(struct rpc_pipe *pipe) static void nfs_idmap_pipe_destroy(struct dentry *dir, struct rpc_pipe_dir_object *pdo) { struct idmap *idmap = pdo->pdo_data; struct rpc_pipe *pipe = idmap->idmap_pipe; if (pipe->dentry) { rpc_unlink(pipe->dentry); pipe->dentry = NULL; } } static int __nfs_idmap_register(struct dentry *dir, struct idmap *idmap, struct rpc_pipe *pipe) static int nfs_idmap_pipe_create(struct dentry *dir, struct rpc_pipe_dir_object *pdo) { struct idmap *idmap = pdo->pdo_data; struct rpc_pipe *pipe = idmap->idmap_pipe; struct dentry *dentry; dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); Loading @@ -423,36 +429,10 @@ static int __nfs_idmap_register(struct dentry *dir, return 0; } static void nfs_idmap_unregister(struct nfs_client *clp, struct rpc_pipe *pipe) { struct net *net = clp->cl_net; struct super_block *pipefs_sb; pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { __nfs_idmap_unregister(pipe); rpc_put_sb_net(net); } } static int nfs_idmap_register(struct nfs_client *clp, struct idmap *idmap, struct rpc_pipe *pipe) { struct net *net = clp->cl_net; struct super_block *pipefs_sb; int err = 0; pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { if (clp->cl_rpcclient->cl_dentry) err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, idmap, pipe); rpc_put_sb_net(net); } return err; } static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = { .create = nfs_idmap_pipe_create, .destroy = nfs_idmap_pipe_destroy, }; int nfs_idmap_new(struct nfs_client *clp) Loading @@ -465,23 +445,31 @@ nfs_idmap_new(struct nfs_client *clp) if (idmap == NULL) return -ENOMEM; rpc_init_pipe_dir_object(&idmap->idmap_pdo, &nfs_idmap_pipe_dir_object_ops, idmap); pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); if (IS_ERR(pipe)) { error = PTR_ERR(pipe); kfree(idmap); return error; } error = nfs_idmap_register(clp, idmap, pipe); if (error) { rpc_destroy_pipe_data(pipe); kfree(idmap); return error; goto err; } idmap->idmap_pipe = pipe; mutex_init(&idmap->idmap_mutex); error = rpc_add_pipe_dir_object(clp->cl_net, &clp->cl_rpcclient->cl_pipedir_objects, &idmap->idmap_pdo); if (error) goto err_destroy_pipe; clp->cl_idmap = idmap; return 0; err_destroy_pipe: rpc_destroy_pipe_data(idmap->idmap_pipe); err: kfree(idmap); return error; } void Loading @@ -491,130 +479,26 @@ nfs_idmap_delete(struct nfs_client *clp) if (!idmap) return; nfs_idmap_unregister(clp, idmap->idmap_pipe); rpc_destroy_pipe_data(idmap->idmap_pipe); clp->cl_idmap = NULL; rpc_remove_pipe_dir_object(clp->cl_net, &clp->cl_rpcclient->cl_pipedir_objects, &idmap->idmap_pdo); rpc_destroy_pipe_data(idmap->idmap_pipe); kfree(idmap); } static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, struct super_block *sb) { int err = 0; switch (event) { case RPC_PIPEFS_MOUNT: err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, clp->cl_idmap, clp->cl_idmap->idmap_pipe); break; case RPC_PIPEFS_UMOUNT: if (clp->cl_idmap->idmap_pipe) { struct dentry *parent; parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); /* * Note: This is a dirty hack. SUNRPC hook has been * called already but simple_rmdir() call for the * directory returned with error because of idmap pipe * inside. Thus now we have to remove this directory * here. */ if (rpc_rmdir(parent)) printk(KERN_ERR "NFS: %s: failed to remove " "clnt dir!\n", __func__); } break; default: printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__, event); return -ENOTSUPP; } return err; } 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_INITING) { atomic_inc(&clp->cl_count); spin_unlock(&nn->nfs_client_lock); err = nfs_wait_client_init_complete(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; smp_rmb(); if (clp->rpc_ops != &nfs_v4_clientops) continue; cl_dentry = clp->cl_idmap->idmap_pipe->dentry; if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) || ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry)) continue; atomic_inc(&clp->cl_count); spin_unlock(&nn->nfs_client_lock); return clp; } spin_unlock(&nn->nfs_client_lock); return NULL; } static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct super_block *sb = ptr; struct nfs_client *clp; int error = 0; if (!try_module_get(THIS_MODULE)) return 0; while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { error = __rpc_pipefs_event(clp, event, sb); nfs_put_client(clp); if (error) break; } module_put(THIS_MODULE); return error; } #define PIPEFS_NFS_PRIO 1 static struct notifier_block nfs_idmap_block = { .notifier_call = rpc_pipefs_event, .priority = SUNRPC_PIPEFS_NFS_PRIO, }; int nfs_idmap_init(void) { int ret; ret = nfs_idmap_init_keyring(); if (ret != 0) goto out; ret = rpc_pipefs_notifier_register(&nfs_idmap_block); if (ret != 0) nfs_idmap_quit_keyring(); out: return ret; } void nfs_idmap_quit(void) { rpc_pipefs_notifier_unregister(&nfs_idmap_block); nfs_idmap_quit_keyring(); } Loading Loading
fs/nfs/idmap.c +34 −150 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ struct idmap_legacy_upcalldata { }; struct idmap { struct rpc_pipe_dir_object idmap_pdo; struct rpc_pipe *idmap_pipe; struct idmap_legacy_upcalldata *idmap_upcall_data; struct mutex idmap_mutex; Loading Loading @@ -402,18 +403,23 @@ static struct key_type key_type_id_resolver_legacy = { .request_key = nfs_idmap_legacy_upcall, }; static void __nfs_idmap_unregister(struct rpc_pipe *pipe) static void nfs_idmap_pipe_destroy(struct dentry *dir, struct rpc_pipe_dir_object *pdo) { struct idmap *idmap = pdo->pdo_data; struct rpc_pipe *pipe = idmap->idmap_pipe; if (pipe->dentry) { rpc_unlink(pipe->dentry); pipe->dentry = NULL; } } static int __nfs_idmap_register(struct dentry *dir, struct idmap *idmap, struct rpc_pipe *pipe) static int nfs_idmap_pipe_create(struct dentry *dir, struct rpc_pipe_dir_object *pdo) { struct idmap *idmap = pdo->pdo_data; struct rpc_pipe *pipe = idmap->idmap_pipe; struct dentry *dentry; dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe); Loading @@ -423,36 +429,10 @@ static int __nfs_idmap_register(struct dentry *dir, return 0; } static void nfs_idmap_unregister(struct nfs_client *clp, struct rpc_pipe *pipe) { struct net *net = clp->cl_net; struct super_block *pipefs_sb; pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { __nfs_idmap_unregister(pipe); rpc_put_sb_net(net); } } static int nfs_idmap_register(struct nfs_client *clp, struct idmap *idmap, struct rpc_pipe *pipe) { struct net *net = clp->cl_net; struct super_block *pipefs_sb; int err = 0; pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { if (clp->cl_rpcclient->cl_dentry) err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, idmap, pipe); rpc_put_sb_net(net); } return err; } static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = { .create = nfs_idmap_pipe_create, .destroy = nfs_idmap_pipe_destroy, }; int nfs_idmap_new(struct nfs_client *clp) Loading @@ -465,23 +445,31 @@ nfs_idmap_new(struct nfs_client *clp) if (idmap == NULL) return -ENOMEM; rpc_init_pipe_dir_object(&idmap->idmap_pdo, &nfs_idmap_pipe_dir_object_ops, idmap); pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0); if (IS_ERR(pipe)) { error = PTR_ERR(pipe); kfree(idmap); return error; } error = nfs_idmap_register(clp, idmap, pipe); if (error) { rpc_destroy_pipe_data(pipe); kfree(idmap); return error; goto err; } idmap->idmap_pipe = pipe; mutex_init(&idmap->idmap_mutex); error = rpc_add_pipe_dir_object(clp->cl_net, &clp->cl_rpcclient->cl_pipedir_objects, &idmap->idmap_pdo); if (error) goto err_destroy_pipe; clp->cl_idmap = idmap; return 0; err_destroy_pipe: rpc_destroy_pipe_data(idmap->idmap_pipe); err: kfree(idmap); return error; } void Loading @@ -491,130 +479,26 @@ nfs_idmap_delete(struct nfs_client *clp) if (!idmap) return; nfs_idmap_unregister(clp, idmap->idmap_pipe); rpc_destroy_pipe_data(idmap->idmap_pipe); clp->cl_idmap = NULL; rpc_remove_pipe_dir_object(clp->cl_net, &clp->cl_rpcclient->cl_pipedir_objects, &idmap->idmap_pdo); rpc_destroy_pipe_data(idmap->idmap_pipe); kfree(idmap); } static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, struct super_block *sb) { int err = 0; switch (event) { case RPC_PIPEFS_MOUNT: err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, clp->cl_idmap, clp->cl_idmap->idmap_pipe); break; case RPC_PIPEFS_UMOUNT: if (clp->cl_idmap->idmap_pipe) { struct dentry *parent; parent = clp->cl_idmap->idmap_pipe->dentry->d_parent; __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe); /* * Note: This is a dirty hack. SUNRPC hook has been * called already but simple_rmdir() call for the * directory returned with error because of idmap pipe * inside. Thus now we have to remove this directory * here. */ if (rpc_rmdir(parent)) printk(KERN_ERR "NFS: %s: failed to remove " "clnt dir!\n", __func__); } break; default: printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__, event); return -ENOTSUPP; } return err; } 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_INITING) { atomic_inc(&clp->cl_count); spin_unlock(&nn->nfs_client_lock); err = nfs_wait_client_init_complete(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; smp_rmb(); if (clp->rpc_ops != &nfs_v4_clientops) continue; cl_dentry = clp->cl_idmap->idmap_pipe->dentry; if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) || ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry)) continue; atomic_inc(&clp->cl_count); spin_unlock(&nn->nfs_client_lock); return clp; } spin_unlock(&nn->nfs_client_lock); return NULL; } static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct super_block *sb = ptr; struct nfs_client *clp; int error = 0; if (!try_module_get(THIS_MODULE)) return 0; while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) { error = __rpc_pipefs_event(clp, event, sb); nfs_put_client(clp); if (error) break; } module_put(THIS_MODULE); return error; } #define PIPEFS_NFS_PRIO 1 static struct notifier_block nfs_idmap_block = { .notifier_call = rpc_pipefs_event, .priority = SUNRPC_PIPEFS_NFS_PRIO, }; int nfs_idmap_init(void) { int ret; ret = nfs_idmap_init_keyring(); if (ret != 0) goto out; ret = rpc_pipefs_notifier_register(&nfs_idmap_block); if (ret != 0) nfs_idmap_quit_keyring(); out: return ret; } void nfs_idmap_quit(void) { rpc_pipefs_notifier_unregister(&nfs_idmap_block); nfs_idmap_quit_keyring(); } Loading