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:
parent
d7631250b2
commit
6739ffb754
|
@ -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;
|
||||||
|
|
|
@ -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 *,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue