]> Pileus Git - ~andy/linux/blobdiff - fs/nfs/idmap.c
Linux 3.14
[~andy/linux] / fs / nfs / idmap.c
index c2c4163d56832fd94193c2865faeb64df11e8b74..567983d2c0ebada3105f5c1ef42bc0c4595c2ca6 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "internal.h"
 #include "netns.h"
+#include "nfs4trace.h"
 
 #define NFS_UINT_MAXLEN 11
 
@@ -63,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;
@@ -310,7 +312,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
        if (ret < 0)
                goto out_up;
 
-       payload = rcu_dereference(rkey->payload.data);
+       payload = rcu_dereference(rkey->payload.rcudata);
        if (IS_ERR_OR_NULL(payload)) {
                ret = PTR_ERR(payload);
                goto out_up;
@@ -401,16 +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)
 {
-       if (pipe->dentry)
+       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);
@@ -420,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)
@@ -462,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
@@ -488,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();
 }
 
@@ -849,6 +736,7 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
                if (!uid_valid(*uid))
                        ret = -ERANGE;
        }
+       trace_nfs4_map_name_to_uid(name, namelen, id, ret);
        return ret;
 }
 
@@ -865,6 +753,7 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
                if (!gid_valid(*gid))
                        ret = -ERANGE;
        }
+       trace_nfs4_map_group_to_gid(name, namelen, id, ret);
        return ret;
 }
 
@@ -879,6 +768,7 @@ int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf,
                ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(id, buf, buflen);
+       trace_nfs4_map_uid_to_name(buf, ret, id, ret);
        return ret;
 }
 int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)
@@ -892,5 +782,6 @@ int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf,
                ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(id, buf, buflen);
+       trace_nfs4_map_gid_to_group(buf, ret, id, ret);
        return ret;
 }