@@ -58,11 +58,13 @@ struct rpc_clnt {
int cl_nodelen; /* nodename length */
char cl_nodename[UNX_MAXNODENAME];
- struct rpc_pipe_dir_head cl_pipedir_objects;
+ struct dentry *cl_dentry;
struct rpc_clnt * cl_parent; /* Points to parent of clones */
struct rpc_rtt cl_rtt_default;
struct rpc_timeout cl_timeout_default;
const struct rpc_program *cl_program;
+ struct list_head cl_gss_pipes;
+ struct mutex cl_gss_pipe_mutex;
};
/*
@@ -5,26 +5,6 @@
#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 list_head list;
void *data;
@@ -77,23 +57,6 @@ struct rpc_clnt;
extern int rpc_create_client_dir(struct rpc_clnt *);
extern int rpc_remove_client_dir(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);
-extern 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 cache_detail;
extern struct dentry *rpc_create_cache_dir(struct net *n, const char *,
const char *, umode_t umode, struct cache_detail *);
@@ -79,7 +79,7 @@ static DEFINE_HASHTABLE(gss_auth_hash_table, 4);
static DEFINE_SPINLOCK(gss_auth_hash_lock);
struct gss_pipe {
- struct rpc_pipe_dir_object pdo;
+ struct list_head list;
struct rpc_pipe *pipe;
struct rpc_clnt *clnt;
const char *name;
@@ -826,141 +826,71 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
}
}
-static void gss_pipe_dentry_destroy(struct dentry *dir,
- struct rpc_pipe_dir_object *pdo)
+static struct gss_pipe *
+__gss_pipe_find(struct rpc_clnt *clnt, const char *name)
{
- struct gss_pipe *gss_pipe = pdo->pdo_data;
- struct rpc_pipe *pipe = gss_pipe->pipe;
+ struct gss_pipe *p;
- if (pipe->dentry != NULL) {
- rpc_unlink(pipe->dentry);
- pipe->dentry = NULL;
+ list_for_each_entry(p, &clnt->cl_gss_pipes, list) {
+ if (strcmp(p->name, name) != 0)
+ continue;
+ if (!kref_get_unless_zero(&p->kref))
+ continue;
+ return p;
}
-}
-
-static int gss_pipe_dentry_create(struct dentry *dir,
- struct rpc_pipe_dir_object *pdo)
-{
- struct gss_pipe *p = pdo->pdo_data;
- struct dentry *dentry;
- dentry = rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
- p->pipe->dentry = dentry;
- return 0;
+ return NULL;
}
-static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops = {
- .create = gss_pipe_dentry_create,
- .destroy = gss_pipe_dentry_destroy,
-};
-
-static struct gss_pipe *gss_pipe_alloc(struct rpc_clnt *clnt,
+static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt,
const char *name,
const struct rpc_pipe_ops *upcall_ops)
{
struct gss_pipe *p;
- int err = -ENOMEM;
+
+ mutex_lock(&clnt->cl_gss_pipe_mutex);
+ p = __gss_pipe_find(clnt, name);
+ if (p)
+ goto out;
p = kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL)
- goto err;
- p->pipe = rpc_mkpipe_data(upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
- if (IS_ERR(p->pipe)) {
- err = PTR_ERR(p->pipe);
- goto err_free_gss_pipe;
+ if (p == NULL) {
+ p = ERR_PTR(-ENOMEM);
+ goto out;
}
+
p->name = name;
p->clnt = clnt;
kref_init(&p->kref);
- rpc_init_pipe_dir_object(&p->pdo,
- &gss_pipe_dir_object_ops,
- p);
- return p;
-err_free_gss_pipe:
- kfree(p);
-err:
- return ERR_PTR(err);
-}
-
-struct gss_alloc_pdo {
- struct rpc_clnt *clnt;
- const char *name;
- const struct rpc_pipe_ops *upcall_ops;
-};
-
-static int gss_pipe_match_pdo(struct rpc_pipe_dir_object *pdo, void *data)
-{
- struct gss_pipe *gss_pipe;
- struct gss_alloc_pdo *args = data;
-
- if (pdo->pdo_ops != &gss_pipe_dir_object_ops)
- return 0;
- gss_pipe = container_of(pdo, struct gss_pipe, pdo);
- if (strcmp(gss_pipe->name, args->name) != 0)
- return 0;
- if (!kref_get_unless_zero(&gss_pipe->kref))
- return 0;
- return 1;
-}
-
-static struct rpc_pipe_dir_object *gss_pipe_alloc_pdo(void *data)
-{
- struct gss_pipe *gss_pipe;
- struct gss_alloc_pdo *args = data;
-
- gss_pipe = gss_pipe_alloc(args->clnt, args->name, args->upcall_ops);
- if (!IS_ERR(gss_pipe))
- return &gss_pipe->pdo;
- return NULL;
-}
-
-static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt,
- const char *name,
- const struct rpc_pipe_ops *upcall_ops)
-{
- struct net *net = rpc_net_ns(clnt);
- struct rpc_pipe_dir_object *pdo;
- struct gss_alloc_pdo args = {
- .clnt = clnt,
- .name = name,
- .upcall_ops = upcall_ops,
- };
-
- pdo = rpc_find_or_alloc_pipe_dir_object(net,
- &clnt->cl_pipedir_objects,
- gss_pipe_match_pdo,
- gss_pipe_alloc_pdo,
- &args);
- if (pdo != NULL)
- return container_of(pdo, struct gss_pipe, pdo);
- return ERR_PTR(-ENOMEM);
-}
+ p->pipe = rpc_mkpipe_clnt(clnt, name, upcall_ops, clnt,
+ RPC_PIPE_WAIT_FOR_OPEN);
+ if (IS_ERR(p->pipe)) {
+ kfree(p);
+ return ERR_CAST(p->pipe);
+ }
-static void __gss_pipe_free(struct gss_pipe *p)
-{
- struct rpc_clnt *clnt = p->clnt;
- struct net *net = rpc_net_ns(clnt);
+ list_add_tail(&p->list, &clnt->cl_gss_pipes);
- rpc_remove_pipe_dir_object(net,
- &clnt->cl_pipedir_objects,
- &p->pdo);
- rpc_destroy_pipe_data(p->pipe);
- kfree(p);
+out:
+ mutex_unlock(&clnt->cl_gss_pipe_mutex);
+ return p;
}
-static void __gss_pipe_release(struct kref *kref)
+static void __gss_pipe_free(struct kref *kref)
{
struct gss_pipe *p = container_of(kref, struct gss_pipe, kref);
- __gss_pipe_free(p);
+ mutex_lock(&p->clnt->cl_gss_pipe_mutex);
+ list_del(&p->list);
+ mutex_unlock(&p->clnt->cl_gss_pipe_mutex);
+ rpc_rmpipe(p->pipe);
+ kfree(p);
}
static void gss_pipe_free(struct gss_pipe *p)
{
if (p != NULL)
- kref_put(&p->kref, __gss_pipe_release);
+ kref_put(&p->kref, __gss_pipe_free);
}
/*
@@ -221,7 +221,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
clnt->cl_vers = version->number;
clnt->cl_stats = program->stats;
clnt->cl_metrics = rpc_alloc_iostats(clnt);
- rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
err = -ENOMEM;
if (clnt->cl_metrics == NULL)
goto out_no_stats;
@@ -229,6 +228,9 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
INIT_LIST_HEAD(&clnt->cl_tasks);
spin_lock_init(&clnt->cl_lock);
+ INIT_LIST_HEAD(&clnt->cl_gss_pipes);
+ mutex_init(&clnt->cl_gss_pipe_mutex);
+
timeout = xprt->timeout;
if (args->timeout != NULL) {
memcpy(&clnt->cl_timeout_default, args->timeout,
@@ -15,7 +15,6 @@ struct sunrpc_net {
struct vfsmount *pipefs_mnt;
struct super_block *pipefs_sb;
- struct mutex pipefs_sb_lock;
struct list_head all_clients;
spinlock_t rpc_client_lock;
@@ -889,8 +889,7 @@ struct rpc_pipe *
rpc_mkpipe_clnt(struct rpc_clnt *clnt, const char *name,
const struct rpc_pipe_ops *ops, void *private, int flags)
{
- return __rpc_mkpipe(clnt->cl_pipedir_objects.pdh_dentry, name,
- ops, private, flags);
+ return __rpc_mkpipe(clnt->cl_dentry, name, ops, private, flags);
}
EXPORT_SYMBOL_GPL(rpc_mkpipe_clnt);
@@ -927,159 +926,6 @@ void rpc_rmpipe(struct rpc_pipe *pipe)
}
EXPORT_SYMBOL_GPL(rpc_rmpipe);
-/**
- * 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
@@ -1138,8 +984,7 @@ retry:
goto out;
}
- clnt->cl_pipedir_objects.pdh_dentry = dentry;
- rpc_create_pipe_dir_objects(&clnt->cl_pipedir_objects);
+ clnt->cl_dentry = dentry;
out:
return ret;
}
@@ -1150,12 +995,12 @@ out:
*/
int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
{
- struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
+ struct dentry *dentry = rpc_client->cl_dentry;
if (dentry == NULL)
return 0;
- rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
- rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
+
+ rpc_client->cl_dentry = NULL;
return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
}
@@ -1266,7 +1111,6 @@ int rpc_pipefs_init_net(struct net *net)
{
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
- mutex_init(&sn->pipefs_sb_lock);
sn->gssd_running = 1;
sn->pipe_version = -1;
@@ -1306,10 +1150,8 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
return -ENOMEM;
dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n",
net, NET_NAME(net));
- mutex_lock(&sn->pipefs_sb_lock);
sn->pipefs_sb = sb;
sb->s_fs_info = get_net(net);
- mutex_unlock(&sn->pipefs_sb_lock);
return 0;
}
@@ -1323,19 +1165,10 @@ rpc_mount(struct file_system_type *fs_type,
static void rpc_kill_sb(struct super_block *sb)
{
struct net *net = sb->s_fs_info;
- struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
- mutex_lock(&sn->pipefs_sb_lock);
- if (sn->pipefs_sb != sb) {
- mutex_unlock(&sn->pipefs_sb_lock);
- goto out;
- }
- sn->pipefs_sb = NULL;
dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n",
net, NET_NAME(net));
- mutex_unlock(&sn->pipefs_sb_lock);
put_net(net);
-out:
kill_litter_super(sb);
}
This is a bit more elaborate as auth_gcc offloaded it's own little list of pipes to rpc_pipes. Fixed by rewriting the ovely generic code into self-contained variants and removing the superflous infrastructure. Signed-off-by: Christoph Hellwig <hch@lst.de> --- include/linux/sunrpc/clnt.h | 4 +- include/linux/sunrpc/rpc_pipe_fs.h | 37 -------- net/sunrpc/auth_gss/auth_gss.c | 146 ++++++++--------------------- net/sunrpc/clnt.c | 4 +- net/sunrpc/netns.h | 1 - net/sunrpc/rpc_pipe.c | 177 +----------------------------------- 6 files changed, 49 insertions(+), 320 deletions(-)