]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
SUNRPC: subscribe RPC clients to pipefs notifications
authorStanislav Kinsbursky <skinsbursky@parallels.com>
Wed, 11 Jan 2012 15:18:17 +0000 (19:18 +0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 31 Jan 2012 23:20:25 +0000 (18:20 -0500)
This patch subscribes RPC clients to RPC pipefs notifications. RPC clients
notifier block is registering with pipefs initialization during SUNRPC module
init.
This notifier callback is responsible for RPC client PipeFS directory and GSS
pipes creation. For pipes creation and destruction two additional callbacks
were added to struct rpc_authops.
Note that no locking required in notifier callback because PipeFS superblock
pointer is passed as an argument from it's creation or destruction routine and
thus we can be sure about it's validity.

Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/auth.h
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sunrpc.h

index 7874a8a566386a02165ebc0bff474d8bf160f0c0..492a36d72829939c21f6c4ff3f5bd412956b2a95 100644 (file)
@@ -99,6 +99,8 @@ struct rpc_authops {
 
        struct rpc_cred *       (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
        struct rpc_cred *       (*crcreate)(struct rpc_auth*, struct auth_cred *, int);
+       int                     (*pipes_create)(struct rpc_auth *);
+       void                    (*pipes_destroy)(struct rpc_auth *);
 };
 
 struct rpc_credops {
index 1a6fa91735193bdf5d581dc15a3e55f14a7befb5..9da2d837b512eeecb28d803f55fd0db7de4a19be 100644 (file)
@@ -762,8 +762,10 @@ static void gss_pipes_dentries_destroy(struct rpc_auth *auth)
        struct gss_auth *gss_auth;
 
        gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-       rpc_unlink(gss_auth->pipe[0]->dentry);
-       rpc_unlink(gss_auth->pipe[1]->dentry);
+       if (gss_auth->pipe[0]->dentry)
+               rpc_unlink(gss_auth->pipe[0]->dentry);
+       if (gss_auth->pipe[1]->dentry)
+               rpc_unlink(gss_auth->pipe[1]->dentry);
 }
 
 static int gss_pipes_dentries_create(struct rpc_auth *auth)
@@ -1614,7 +1616,9 @@ static const struct rpc_authops authgss_ops = {
        .create         = gss_create,
        .destroy        = gss_destroy,
        .lookup_cred    = gss_lookup_cred,
-       .crcreate       = gss_create_cred
+       .crcreate       = gss_create_cred,
+       .pipes_create   = gss_pipes_dentries_create,
+       .pipes_destroy  = gss_pipes_dentries_destroy,
 };
 
 static const struct rpc_credops gss_credops = {
index 90e82c5daeb6fecda5998a6d2b5f785e2db9731c..41707450059273c55129312c0e18e20c42586a5a 100644 (file)
@@ -98,8 +98,11 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)
 
 static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
 {
-       if (clnt->cl_path.dentry)
+       if (clnt->cl_path.dentry) {
+               if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
+                       clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
                rpc_remove_client_dir(clnt->cl_path.dentry);
+       }
        clnt->cl_path.dentry = NULL;
 }
 
@@ -181,6 +184,70 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
        return 0;
 }
 
+static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
+                               struct super_block *sb)
+{
+       struct dentry *dentry;
+       int err = 0;
+
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               if (clnt->cl_program->pipe_dir_name == NULL)
+                       break;
+               dentry = rpc_setup_pipedir_sb(sb, clnt,
+                                             clnt->cl_program->pipe_dir_name);
+               BUG_ON(dentry == NULL);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+               clnt->cl_path.dentry = dentry;
+               if (clnt->cl_auth->au_ops->pipes_create) {
+                       err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth);
+                       if (err)
+                               __rpc_clnt_remove_pipedir(clnt);
+               }
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               __rpc_clnt_remove_pipedir(clnt);
+               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 rpc_clnt *clnt;
+       int error = 0;
+       struct sunrpc_net *sn = net_generic(sb->s_fs_info, sunrpc_net_id);
+
+       spin_lock(&sn->rpc_client_lock);
+       list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
+               error = __rpc_pipefs_event(clnt, event, sb);
+               if (error)
+                       break;
+       }
+       spin_unlock(&sn->rpc_client_lock);
+       return error;
+}
+
+static struct notifier_block rpc_clients_block = {
+       .notifier_call  = rpc_pipefs_event,
+};
+
+int rpc_clients_notifier_register(void)
+{
+       return rpc_pipefs_notifier_register(&rpc_clients_block);
+}
+
+void rpc_clients_notifier_unregister(void)
+{
+       return rpc_pipefs_notifier_unregister(&rpc_clients_block);
+}
+
 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
 {
        struct rpc_program      *program = args->program;
index 6dd8b96e8df75e7c75c9571c017b22e15507d513..910de4169a8db066581234ff8617b03168af175f 100644 (file)
@@ -937,7 +937,7 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
 
 /**
  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
- * @dentry: directory to remove
+ * @clnt: rpc client
  */
 int rpc_remove_client_dir(struct dentry *dentry)
 {
@@ -1188,17 +1188,24 @@ int register_rpc_pipefs(void)
                                init_once);
        if (!rpc_inode_cachep)
                return -ENOMEM;
+       err = rpc_clients_notifier_register();
+       if (err)
+               goto err_notifier;
        err = register_filesystem(&rpc_pipe_fs_type);
-       if (err) {
-               kmem_cache_destroy(rpc_inode_cachep);
-               return err;
-       }
-
+       if (err)
+               goto err_register;
        return 0;
+
+err_register:
+       rpc_clients_notifier_unregister();
+err_notifier:
+       kmem_cache_destroy(rpc_inode_cachep);
+       return err;
 }
 
 void unregister_rpc_pipefs(void)
 {
+       rpc_clients_notifier_unregister();
        kmem_cache_destroy(rpc_inode_cachep);
        unregister_filesystem(&rpc_pipe_fs_type);
 }
index 90c292e2738b5f7248db0f267aa63c1b88f7d8b2..14c9f6d1c5ff22987e6dfdbf2ce9a95508ee4696 100644 (file)
@@ -47,5 +47,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
                    struct page *headpage, unsigned long headoffset,
                    struct page *tailpage, unsigned long tailoffset);
 
+int rpc_clients_notifier_register(void);
+void rpc_clients_notifier_unregister(void);
 #endif /* _NET_SUNRPC_SUNRPC_H */