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: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Trond Myklebust 2013-08-26 15:38:11 -04:00
parent d7631250b2
commit 6739ffb754
4 changed files with 168 additions and 4 deletions

View file

@ -884,6 +884,124 @@ 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);
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
@ -924,16 +1042,28 @@ 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 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);
}