Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6739ffb7 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

SUNRPC: Add a framework to clean up management of rpc_pipefs directories



The current system requires everyone to set up notifiers, manage directory
locking, etc.
What we really want to do is have the rpc_client create its directory,
and then create all the entries.

This patch will allow the RPCSEC_GSS and NFS code to register all the
objects that they want to have appear in the directory, and then have
the sunrpc code call them back to actually create/destroy their pipefs
dentries when the rpc_client creates/destroys the parent.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent d7631250
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/timer.h>
#include <linux/sunrpc/timer.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include <asm/signal.h>
#include <asm/signal.h>
#include <linux/path.h>
#include <linux/path.h>
#include <net/ipv6.h>
#include <net/ipv6.h>
@@ -55,6 +56,7 @@ struct rpc_clnt {


	int			cl_nodelen;	/* nodename length */
	int			cl_nodelen;	/* nodename length */
	char 			cl_nodename[UNX_MAXNODENAME];
	char 			cl_nodename[UNX_MAXNODENAME];
	struct rpc_pipe_dir_head cl_pipedir_objects;
	struct dentry *		cl_dentry;
	struct dentry *		cl_dentry;
	struct rpc_clnt *	cl_parent;	/* Points to parent of clones */
	struct rpc_clnt *	cl_parent;	/* Points to parent of clones */
	struct rpc_rtt		cl_rtt_default;
	struct rpc_rtt		cl_rtt_default;
+32 −1
Original line number Original line Diff line number Diff line
@@ -5,6 +5,26 @@


#include <linux/workqueue.h>
#include <linux/workqueue.h>


struct rpc_pipe_dir_head {
	struct list_head pdh_entries;
	struct dentry *pdh_dentry;
};

struct rpc_pipe_dir_object_ops;
struct rpc_pipe_dir_object {
	struct list_head pdo_head;
	const struct rpc_pipe_dir_object_ops *pdo_ops;

	void *pdo_data;
};

struct rpc_pipe_dir_object_ops {
	int (*create)(struct dentry *dir,
			struct rpc_pipe_dir_object *pdo);
	void (*destroy)(struct dentry *dir,
			struct rpc_pipe_dir_object *pdo);
};

struct rpc_pipe_msg {
struct rpc_pipe_msg {
	struct list_head list;
	struct list_head list;
	void *data;
	void *data;
@@ -74,7 +94,18 @@ extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);


struct rpc_clnt;
struct rpc_clnt;
extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
extern int rpc_remove_client_dir(struct dentry *);
extern int rpc_remove_client_dir(struct dentry *, struct rpc_clnt *);

extern void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh);
extern void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
		const struct rpc_pipe_dir_object_ops *pdo_ops,
		void *pdo_data);
extern int rpc_add_pipe_dir_object(struct net *net,
		struct rpc_pipe_dir_head *pdh,
		struct rpc_pipe_dir_object *pdo);
extern void rpc_remove_pipe_dir_object(struct net *net,
		struct rpc_pipe_dir_head *pdh,
		struct rpc_pipe_dir_object *pdo);


struct cache_detail;
struct cache_detail;
extern struct dentry *rpc_create_cache_dir(struct dentry *,
extern struct dentry *rpc_create_cache_dir(struct dentry *,
+2 −1
Original line number Original line Diff line number Diff line
@@ -105,7 +105,7 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
	if (clnt->cl_dentry) {
	if (clnt->cl_dentry) {
		if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
		if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
			clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
			clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
		rpc_remove_client_dir(clnt->cl_dentry);
		rpc_remove_client_dir(clnt->cl_dentry, clnt);
	}
	}
	clnt->cl_dentry = NULL;
	clnt->cl_dentry = NULL;
}
}
@@ -355,6 +355,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
	clnt->cl_vers     = version->number;
	clnt->cl_vers     = version->number;
	clnt->cl_stats    = program->stats;
	clnt->cl_stats    = program->stats;
	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
	rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
	err = -ENOMEM;
	err = -ENOMEM;
	if (clnt->cl_metrics == NULL)
	if (clnt->cl_metrics == NULL)
		goto out_no_stats;
		goto out_no_stats;
+132 −2
Original line number Original line Diff line number Diff line
@@ -884,6 +884,124 @@ rpc_unlink(struct dentry *dentry)
}
}
EXPORT_SYMBOL_GPL(rpc_unlink);
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);

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 {
enum {
	RPCAUTH_info,
	RPCAUTH_info,
	RPCAUTH_EOF
	RPCAUTH_EOF
@@ -924,16 +1042,28 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
				   const char *name,
				   const char *name,
				   struct rpc_clnt *rpc_client)
				   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);
			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()
 * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
 * @dentry: dentry for the pipe
 * @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 dentry *dentry, struct rpc_clnt *rpc_client)
{
{
	if (rpc_client->cl_pipedir_objects.pdh_dentry) {
		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);
	return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
}
}