SUNRPC: take a xprt offline using sysfs
authorOlga Kornievskaia <kolga@netapp.com>
Thu, 24 Jun 2021 03:28:50 +0000 (23:28 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Thu, 8 Jul 2021 18:03:24 +0000 (14:03 -0400)
Using sysfs's xprt_state attribute, mark a particular transport offline.
It will not be picked during the round-robin selection. It's not allowed
to take the main (1st created transport associated with the rpc_client)
offline. Also bring a transport back online via sysfs by writing "online"
and that would allow for this transport to be picked during the round-
robin selection.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/xprt.h
net/sunrpc/sysfs.c
net/sunrpc/sysfs.h
net/sunrpc/xprtmultipath.c

index 692e594..b8ed7fa 100644 (file)
@@ -427,6 +427,7 @@ void                        xprt_release_write(struct rpc_xprt *, struct rpc_task *);
 #define XPRT_BOUND             (4)
 #define XPRT_BINDING           (5)
 #define XPRT_CLOSING           (6)
+#define XPRT_OFFLINE           (7)
 #define XPRT_CONGESTED         (9)
 #define XPRT_CWND_WAIT         (10)
 #define XPRT_WRITE_SPACE       (11)
index 08aa503..a30ad18 100644 (file)
@@ -69,6 +69,15 @@ rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
 }
 
 static inline struct rpc_xprt_switch *
+rpc_sysfs_xprt_kobj_get_xprt_switch(struct kobject *kobj)
+{
+       struct rpc_sysfs_xprt *x = container_of(kobj,
+               struct rpc_sysfs_xprt, kobject);
+
+       return xprt_switch_get(x->xprt_switch);
+}
+
+static inline struct rpc_xprt_switch *
 rpc_sysfs_xprt_switch_kobj_get_xprt(struct kobject *kobj)
 {
        struct rpc_sysfs_xprt_switch *x = container_of(kobj,
@@ -122,7 +131,7 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
        struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
        ssize_t ret;
        int locked, connected, connecting, close_wait, bound, binding,
-           closing, congested, cwnd_wait, write_space;
+           closing, congested, cwnd_wait, write_space, offline;
 
        if (!xprt)
                return 0;
@@ -140,8 +149,9 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
                congested = test_bit(XPRT_CONGESTED, &xprt->state);
                cwnd_wait = test_bit(XPRT_CWND_WAIT, &xprt->state);
                write_space = test_bit(XPRT_WRITE_SPACE, &xprt->state);
+               offline = test_bit(XPRT_OFFLINE, &xprt->state);
 
-               ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s\n",
+               ret = sprintf(buf, "state=%s %s %s %s %s %s %s %s %s %s %s\n",
                              locked ? "LOCKED" : "",
                              connected ? "CONNECTED" : "",
                              connecting ? "CONNECTING" : "",
@@ -151,7 +161,8 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
                              closing ? "CLOSING" : "",
                              congested ? "CONGESTED" : "",
                              cwnd_wait ? "CWND_WAIT" : "",
-                             write_space ? "WRITE_SPACE" : "");
+                             write_space ? "WRITE_SPACE" : "",
+                             offline ? "OFFLINE" : "");
        }
 
        xprt_put(xprt);
@@ -233,6 +244,52 @@ out_err:
        goto out;
 }
 
+static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
+                                          struct kobj_attribute *attr,
+                                          const char *buf, size_t count)
+{
+       struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
+       int offline = 0, online = 0;
+       struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
+
+       if (!xprt)
+               return 0;
+
+       if (!strncmp(buf, "offline", 7))
+               offline = 1;
+       else if (!strncmp(buf, "online", 6))
+               online = 1;
+       else
+               return -EINVAL;
+
+       if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
+               count = -EINTR;
+               goto out_put;
+       }
+       if (xprt->main) {
+               count = -EINVAL;
+               goto release_tasks;
+       }
+       if (offline) {
+               set_bit(XPRT_OFFLINE, &xprt->state);
+               spin_lock(&xps->xps_lock);
+               xps->xps_nactive--;
+               spin_unlock(&xps->xps_lock);
+       } else if (online) {
+               clear_bit(XPRT_OFFLINE, &xprt->state);
+               spin_lock(&xps->xps_lock);
+               xps->xps_nactive++;
+               spin_unlock(&xps->xps_lock);
+       }
+
+release_tasks:
+       xprt_release_write(xprt, NULL);
+out_put:
+       xprt_put(xprt);
+       xprt_switch_put(xps);
+       return count;
+}
+
 int rpc_sysfs_init(void)
 {
        rpc_sunrpc_kset = kset_create_and_add("sunrpc", NULL, kernel_kobj);
@@ -303,7 +360,7 @@ static struct kobj_attribute rpc_sysfs_xprt_info = __ATTR(xprt_info,
        0444, rpc_sysfs_xprt_info_show, NULL);
 
 static struct kobj_attribute rpc_sysfs_xprt_change_state = __ATTR(xprt_state,
-       0644, rpc_sysfs_xprt_state_show, NULL);
+       0644, rpc_sysfs_xprt_state_show, rpc_sysfs_xprt_state_change);
 
 static struct attribute *rpc_sysfs_xprt_attrs[] = {
        &rpc_sysfs_xprt_dstaddr.attr,
@@ -466,6 +523,7 @@ void rpc_sysfs_xprt_setup(struct rpc_xprt_switch *xprt_switch,
        if (rpc_xprt) {
                xprt->xprt_sysfs = rpc_xprt;
                rpc_xprt->xprt = xprt;
+               rpc_xprt->xprt_switch = xprt_switch;
                kobject_uevent(&rpc_xprt->kobject, KOBJ_ADD);
        }
 }
index ff10451..6620ceb 100644 (file)
@@ -22,6 +22,7 @@ struct rpc_sysfs_xprt_switch {
 struct rpc_sysfs_xprt {
        struct kobject kobject;
        struct rpc_xprt *xprt;
+       struct rpc_xprt_switch *xprt_switch;
 };
 
 int rpc_sysfs_init(void);
index 07e76ae..5f4845d 100644 (file)
@@ -65,7 +65,8 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
 {
        if (unlikely(xprt == NULL))
                return;
-       xps->xps_nactive--;
+       if (!test_bit(XPRT_OFFLINE, &xprt->state))
+               xps->xps_nactive--;
        xps->xps_nxprts--;
        if (xps->xps_nxprts == 0)
                xps->xps_net = NULL;
@@ -230,7 +231,8 @@ void xprt_iter_default_rewind(struct rpc_xprt_iter *xpi)
 static
 bool xprt_is_active(const struct rpc_xprt *xprt)
 {
-       return kref_read(&xprt->kref) != 0;
+       return (kref_read(&xprt->kref) != 0 &&
+               !test_bit(XPRT_OFFLINE, &xprt->state));
 }
 
 static