NFS: printks in fs/nfs/ should start with NFS:
[deliverable/linux.git] / fs / nfs / idmap.c
index 2c05f1991e1e1c3664c8ffb9f0159687b53b8449..91b1e2a82146b5a8aa5f221d42179820d3d8720f 100644 (file)
@@ -175,7 +175,8 @@ int nfs_idmap_init(void)
        struct key *keyring;
        int ret = 0;
 
-       printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
+       printk(KERN_NOTICE "NFS: Registering the %s key type\n",
+               key_type_id_resolver.name);
 
        cred = prepare_kernel_cred(NULL);
        if (!cred)
@@ -377,6 +378,7 @@ int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf,
 #include <linux/nfs_fs.h>
 
 #include "nfs4_fs.h"
+#include "internal.h"
 
 #define IDMAP_HASH_SZ          128
 
@@ -410,7 +412,7 @@ struct idmap_hashtable {
 };
 
 struct idmap {
-       struct dentry           *idmap_dentry;
+       struct rpc_pipe         *idmap_pipe;
        wait_queue_head_t       idmap_wq;
        struct idmap_msg        idmap_im;
        struct mutex            idmap_lock;     /* Serializes upcalls */
@@ -431,10 +433,61 @@ static const struct rpc_pipe_ops idmap_upcall_ops = {
        .destroy_msg    = idmap_pipe_destroy_msg,
 };
 
+static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
+{
+       if (pipe->dentry)
+               rpc_unlink(pipe->dentry);
+}
+
+static int __nfs_idmap_register(struct dentry *dir,
+                                    struct idmap *idmap,
+                                    struct rpc_pipe *pipe)
+{
+       struct dentry *dentry;
+
+       dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       pipe->dentry = dentry;
+       return 0;
+}
+
+static void nfs_idmap_unregister(struct nfs_client *clp,
+                                     struct rpc_pipe *pipe)
+{
+       struct net *net = clp->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->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;
+}
+
 int
 nfs_idmap_new(struct nfs_client *clp)
 {
        struct idmap *idmap;
+       struct rpc_pipe *pipe;
        int error;
 
        BUG_ON(clp->cl_idmap != NULL);
@@ -443,14 +496,19 @@ nfs_idmap_new(struct nfs_client *clp)
        if (idmap == NULL)
                return -ENOMEM;
 
-       idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
-                       "idmap", idmap, &idmap_upcall_ops, 0);
-       if (IS_ERR(idmap->idmap_dentry)) {
-               error = PTR_ERR(idmap->idmap_dentry);
+       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;
+       }
+       idmap->idmap_pipe = pipe;
        mutex_init(&idmap->idmap_lock);
        mutex_init(&idmap->idmap_im_lock);
        init_waitqueue_head(&idmap->idmap_wq);
@@ -468,11 +526,86 @@ nfs_idmap_delete(struct nfs_client *clp)
 
        if (!idmap)
                return;
-       rpc_unlink(idmap->idmap_dentry);
+       nfs_idmap_unregister(clp, idmap->idmap_pipe);
+       rpc_destroy_pipe_data(idmap->idmap_pipe);
        clp->cl_idmap = NULL;
        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:
+               BUG_ON(clp->cl_rpcclient->cl_dentry == NULL);
+               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 "%s: failed to remove clnt dir!\n", __func__);
+               }
+               break;
+       default:
+               printk(KERN_ERR "%s: unknown event: %ld\n", __func__, event);
+               return -ENOTSUPP;
+       }
+       return err;
+}
+
+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;
+
+       spin_lock(&nfs_client_lock);
+       list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+               if (clp->net != sb->s_fs_info)
+                       continue;
+               if (clp->rpc_ops != &nfs_v4_clientops)
+                       continue;
+               error = __rpc_pipefs_event(clp, event, sb);
+               if (error)
+                       break;
+       }
+       spin_unlock(&nfs_client_lock);
+       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)
+{
+       return rpc_pipefs_notifier_register(&nfs_idmap_block);
+}
+
+void nfs_idmap_quit(void)
+{
+       rpc_pipefs_notifier_unregister(&nfs_idmap_block);
+}
+
 /*
  * Helper routines for manipulating the hashtable
  */
@@ -589,7 +722,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
        msg.len = sizeof(*im);
 
        add_wait_queue(&idmap->idmap_wq, &wq);
-       if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
+       if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) {
                remove_wait_queue(&idmap->idmap_wq, &wq);
                goto out;
        }
@@ -650,7 +783,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
 
        add_wait_queue(&idmap->idmap_wq, &wq);
 
-       if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
+       if (rpc_queue_upcall(idmap->idmap_pipe, &msg) < 0) {
                remove_wait_queue(&idmap->idmap_wq, &wq);
                goto out;
        }
This page took 0.027372 seconds and 5 git commands to generate.