@@ -24,6 +24,8 @@ struct rpc_xprt_switch {
const struct rpc_xprt_iter_ops *xps_iter_ops;
+ void *xps_sysfs; /* /sys/kernel/sunrpc/multipath/<id> */
+
struct rcu_head xps_rcu;
};
@@ -10,6 +10,7 @@
struct kobject *rpc_client_kobj;
struct kobject *rpc_xprt_kobj;
+struct kobject *rpc_xps_kobj;
static struct kset *rpc_sunrpc_kset;
static void rpc_netns_object_release(struct kobject *kobj)
@@ -58,8 +59,15 @@ int rpc_sysfs_init(void)
if (!rpc_xprt_kobj)
goto err_client;
+ rpc_xps_kobj = rpc_netns_object_alloc("multipath", rpc_sunrpc_kset, NULL);
+ if (!rpc_xps_kobj)
+ goto err_xprt;
+
return 0;
+err_xprt:
+ kobject_put(rpc_xprt_kobj);
+ rpc_xprt_kobj = NULL;
err_client:
kobject_put(rpc_client_kobj);
rpc_client_kobj = NULL;
@@ -95,6 +103,7 @@ static struct kobj_type rpc_netns_client_type = {
void rpc_sysfs_exit(void)
{
+ kobject_put(rpc_xps_kobj);
kobject_put(rpc_xprt_kobj);
kobject_put(rpc_client_kobj);
kset_unregister(rpc_sunrpc_kset);
@@ -122,17 +131,29 @@ void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net)
struct rpc_netns_client *rpc_client;
struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
struct rpc_netns_xprt *rpc_xprt;
+ struct rpc_netns_multipath *rpc_multipath;
+ struct rpc_xprt_switch *xps;
int ret;
+ xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+
rpc_client = rpc_netns_client_alloc(rpc_client_kobj, net, clnt->cl_clid);
if (rpc_client) {
rpc_xprt = xprt->sysfs;
ret = sysfs_create_link_nowarn(&rpc_client->kobject,
&rpc_xprt->kobject, "transport");
+ if (xps) {
+ rpc_multipath = xps->xps_sysfs;
+ ret = sysfs_create_link_nowarn(&rpc_client->kobject,
+ &rpc_multipath->kobject,
+ "multipath");
+ }
clnt->cl_sysfs = rpc_client;
rpc_client->clnt = clnt;
kobject_uevent(&rpc_client->kobject, KOBJ_ADD);
}
+
+ xprt_switch_put(xps);
}
void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
@@ -141,6 +162,7 @@ void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt)
if (rpc_client) {
sysfs_remove_link(&rpc_client->kobject, "transport");
+ sysfs_remove_link(&rpc_client->kobject, "multipath");
kobject_uevent(&rpc_client->kobject, KOBJ_REMOVE);
kobject_del(&rpc_client->kobject);
kobject_put(&rpc_client->kobject);
@@ -255,3 +277,103 @@ void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt)
xprt->sysfs = NULL;
}
}
+
+static void rpc_netns_multipath_release(struct kobject *kobj)
+{
+ struct rpc_netns_multipath *c;
+
+ c = container_of(kobj, struct rpc_netns_multipath, kobject);
+ kfree(c);
+}
+
+static const void *rpc_netns_multipath_namespace(struct kobject *kobj)
+{
+ return container_of(kobj, struct rpc_netns_multipath, kobject)->net;
+}
+
+static ssize_t rpc_netns_multipath_list_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct rpc_netns_multipath *c =
+ container_of(kobj, struct rpc_netns_multipath, kobject);
+ struct rpc_xprt_switch *xps = c->xps;
+ struct rpc_xprt_iter xpi;
+ int pos = 0;
+
+ xprt_iter_init_listall(&xpi, xps);
+ for (;;) {
+ struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
+ if (!xprt)
+ break;
+
+ snprintf(&buf[pos], PAGE_SIZE - pos, "%d\n", xprt->id);
+ pos += strlen(&buf[pos]);
+ xprt_put(xprt);
+ }
+ xprt_iter_destroy(&xpi);
+
+ return pos;
+}
+
+static ssize_t rpc_netns_multipath_list_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ return -EINVAL;
+}
+
+static struct kobj_attribute rpc_netns_multipath_list = __ATTR(list,
+ 0644, rpc_netns_multipath_list_show, rpc_netns_multipath_list_store);
+
+
+static struct attribute *rpc_netns_multipath_attrs[] = {
+ &rpc_netns_multipath_list.attr,
+ NULL,
+};
+
+static struct kobj_type rpc_netns_multipath_type = {
+ .release = rpc_netns_multipath_release,
+ .default_attrs = rpc_netns_multipath_attrs,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .namespace = rpc_netns_multipath_namespace,
+};
+
+static struct rpc_netns_multipath *rpc_netns_multipath_alloc(struct kobject *parent,
+ struct net *net, int id)
+{
+ struct rpc_netns_multipath *p;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (p) {
+ p->net = net;
+ p->kobject.kset = rpc_sunrpc_kset;
+ if (kobject_init_and_add(&p->kobject, &rpc_netns_multipath_type,
+ parent, "%d", id) == 0)
+ return p;
+ kobject_put(&p->kobject);
+ }
+ return NULL;
+}
+
+void rpc_netns_multipath_sysfs_setup(struct rpc_xprt_switch *xps, struct net *net)
+{
+ struct rpc_netns_multipath *rpc_multipath;
+
+ rpc_multipath = rpc_netns_multipath_alloc(rpc_xps_kobj, net, xps->xps_id);
+ if (rpc_multipath) {
+ xps->xps_sysfs = rpc_multipath;
+ rpc_multipath->xps = xps;
+ kobject_uevent(&rpc_multipath->kobject, KOBJ_ADD);
+ }
+}
+
+void rpc_netns_multipath_sysfs_destroy(struct rpc_xprt_switch *xps)
+{
+ struct rpc_netns_multipath *rpc_multipath = xps->xps_sysfs;
+
+ if (rpc_multipath) {
+ kobject_uevent(&rpc_multipath->kobject, KOBJ_REMOVE);
+ kobject_del(&rpc_multipath->kobject);
+ kobject_put(&rpc_multipath->kobject);
+ xps->xps_sysfs = NULL;
+ }
+}
@@ -17,6 +17,12 @@ struct rpc_netns_xprt {
struct rpc_xprt *xprt;
};
+struct rpc_netns_multipath {
+ struct kobject kobject;
+ struct net *net;
+ struct rpc_xprt_switch *xps;
+};
+
extern struct kobject *rpc_client_kobj;
extern struct kobject *rpc_xprt_kobj;
@@ -27,5 +33,7 @@ void rpc_netns_client_sysfs_setup(struct rpc_clnt *clnt, struct net *net);
void rpc_netns_client_sysfs_destroy(struct rpc_clnt *clnt);
void rpc_netns_xprt_sysfs_setup(struct rpc_xprt *xprt, struct net *net);
void rpc_netns_xprt_sysfs_destroy(struct rpc_xprt *xprt);
+void rpc_netns_multipath_sysfs_setup(struct rpc_xprt_switch *xps, struct net *net);
+void rpc_netns_multipath_sysfs_destroy(struct rpc_xprt_switch *xps);
#endif
@@ -19,6 +19,8 @@
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/xprtmultipath.h>
+#include "sysfs.h"
+
typedef struct rpc_xprt *(*xprt_switch_find_xprt_t)(struct rpc_xprt_switch *xps,
const struct rpc_xprt *cur);
@@ -83,6 +85,9 @@ void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps,
spin_lock(&xps->xps_lock);
xprt_switch_remove_xprt_locked(xps, xprt);
spin_unlock(&xps->xps_lock);
+
+ if (!xps->xps_net)
+ rpc_netns_multipath_sysfs_destroy(xps);
xprt_put(xprt);
}
@@ -135,6 +140,10 @@ struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt,
INIT_LIST_HEAD(&xps->xps_xprt_list);
xps->xps_iter_ops = &rpc_xprt_iter_singular;
xprt_switch_add_xprt_locked(xps, xprt);
+ xps->xps_sysfs = NULL;
+
+ if (xprt->xprt_net != NULL)
+ rpc_netns_multipath_sysfs_setup(xps, xprt->xprt_net);
}
return xps;
@@ -162,6 +171,7 @@ static void xprt_switch_free(struct kref *kref)
struct rpc_xprt_switch, xps_kref);
xprt_switch_free_entries(xps);
+ rpc_netns_multipath_sysfs_destroy(xps);
xprt_switch_free_id(xps);
kfree_rcu(xps, xps_rcu);
}
This also adds a `list` attribute to multipath directory that provides the transport IDs of the transports contained in the multipath object. Signed-off-by: Dan Aloni <dan@kernelim.com> --- include/linux/sunrpc/xprtmultipath.h | 2 + net/sunrpc/sysfs.c | 122 +++++++++++++++++++++++++++ net/sunrpc/sysfs.h | 8 ++ net/sunrpc/xprtmultipath.c | 10 +++ 4 files changed, 142 insertions(+)