Merge git://git.kvack.org/~bcrl/aio-next
[firefly-linux-kernel-4.4.55.git] / net / sunrpc / rpc_pipe.c
index 406859cc68aa90073ef237e91e0aa67116adcf33..f94567b45bb3eb9f4f8b0ec82db4ee08a304c48b 100644 (file)
@@ -409,7 +409,7 @@ rpc_show_info(struct seq_file *m, void *v)
        rcu_read_lock();
        seq_printf(m, "RPC server: %s\n",
                        rcu_dereference(clnt->cl_xprt)->servername);
-       seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
+       seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name,
                        clnt->cl_prog, clnt->cl_vers);
        seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
        seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
@@ -480,23 +480,6 @@ static const struct dentry_operations rpc_dentry_operations = {
        .d_delete = rpc_delete_dentry,
 };
 
-/*
- * Lookup the data. This is trivial - if the dentry didn't already
- * exist, we know it is negative.
- */
-static struct dentry *
-rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
-{
-       if (dentry->d_name.len > NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
-       d_add(dentry, NULL);
-       return NULL;
-}
-
-static const struct inode_operations rpc_dir_inode_operations = {
-       .lookup         = rpc_lookup,
-};
-
 static struct inode *
 rpc_get_inode(struct super_block *sb, umode_t mode)
 {
@@ -509,7 +492,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
        switch (mode & S_IFMT) {
        case S_IFDIR:
                inode->i_fop = &simple_dir_operations;
-               inode->i_op = &rpc_dir_inode_operations;
+               inode->i_op = &simple_dir_inode_operations;
                inc_nlink(inode);
        default:
                break;
@@ -901,6 +884,159 @@ rpc_unlink(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(rpc_unlink);
 
+/**
+ * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ */
+void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh)
+{
+       INIT_LIST_HEAD(&pdh->pdh_entries);
+       pdh->pdh_dentry = NULL;
+}
+EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head);
+
+/**
+ * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops
+ * @pdo_data: pointer to caller-defined data
+ */
+void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
+               const struct rpc_pipe_dir_object_ops *pdo_ops,
+               void *pdo_data)
+{
+       INIT_LIST_HEAD(&pdo->pdo_head);
+       pdo->pdo_ops = pdo_ops;
+       pdo->pdo_data = pdo_data;
+}
+EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
+
+static int
+rpc_add_pipe_dir_object_locked(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       int ret = 0;
+
+       if (pdh->pdh_dentry)
+               ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo);
+       if (ret == 0)
+               list_add_tail(&pdo->pdo_head, &pdh->pdh_entries);
+       return ret;
+}
+
+static void
+rpc_remove_pipe_dir_object_locked(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       if (pdh->pdh_dentry)
+               pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
+       list_del_init(&pdo->pdo_head);
+}
+
+/**
+ * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ *
+ */
+int
+rpc_add_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       int ret = 0;
+
+       if (list_empty(&pdo->pdo_head)) {
+               struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+               mutex_lock(&sn->pipefs_sb_lock);
+               ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo);
+               mutex_unlock(&sn->pipefs_sb_lock);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object);
+
+/**
+ * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ *
+ */
+void
+rpc_remove_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       if (!list_empty(&pdo->pdo_head)) {
+               struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+               mutex_lock(&sn->pipefs_sb_lock);
+               rpc_remove_pipe_dir_object_locked(net, pdh, pdo);
+               mutex_unlock(&sn->pipefs_sb_lock);
+       }
+}
+EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object);
+
+/**
+ * rpc_find_or_alloc_pipe_dir_object
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @match: match struct rpc_pipe_dir_object to data
+ * @alloc: allocate a new struct rpc_pipe_dir_object
+ * @data: user defined data for match() and alloc()
+ *
+ */
+struct rpc_pipe_dir_object *
+rpc_find_or_alloc_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               int (*match)(struct rpc_pipe_dir_object *, void *),
+               struct rpc_pipe_dir_object *(*alloc)(void *),
+               void *data)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_pipe_dir_object *pdo;
+
+       mutex_lock(&sn->pipefs_sb_lock);
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) {
+               if (!match(pdo, data))
+                       continue;
+               goto out;
+       }
+       pdo = alloc(data);
+       if (!pdo)
+               goto out;
+       rpc_add_pipe_dir_object_locked(net, pdh, pdo);
+out:
+       mutex_unlock(&sn->pipefs_sb_lock);
+       return pdo;
+}
+EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object);
+
+static void
+rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
+{
+       struct rpc_pipe_dir_object *pdo;
+       struct dentry *dir = pdh->pdh_dentry;
+
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
+               pdo->pdo_ops->create(dir, pdo);
+}
+
+static void
+rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
+{
+       struct rpc_pipe_dir_object *pdo;
+       struct dentry *dir = pdh->pdh_dentry;
+
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
+               pdo->pdo_ops->destroy(dir, pdo);
+}
+
 enum {
        RPCAUTH_info,
        RPCAUTH_EOF
@@ -941,16 +1077,29 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
                                   const char *name,
                                   struct rpc_clnt *rpc_client)
 {
-       return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
+       struct dentry *ret;
+
+       ret = rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
                        rpc_clntdir_populate, rpc_client);
+       if (!IS_ERR(ret)) {
+               rpc_client->cl_pipedir_objects.pdh_dentry = ret;
+               rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
+       }
+       return ret;
 }
 
 /**
  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
- * @dentry: dentry for the pipe
+ * @rpc_client: rpc_client for the pipe
  */
-int rpc_remove_client_dir(struct dentry *dentry)
+int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
 {
+       struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
+
+       if (dentry == NULL)
+               return 0;
+       rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
+       rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
        return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
 }