Skip to content

Commit

Permalink
SUNRPC: take a xprt offline using sysfs
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Olga Kornievskaia authored and Trond Myklebust committed Jul 8, 2021
1 parent c1830a6 commit 5b7eb78
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/linux/sunrpc/xprt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
66 changes: 62 additions & 4 deletions net/sunrpc/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ rpc_sysfs_xprt_kobj_get_xprt(struct kobject *kobj)
return xprt_get(x->xprt);
}

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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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" : "",
Expand All @@ -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);
Expand Down Expand Up @@ -233,6 +244,52 @@ static ssize_t rpc_sysfs_xprt_dstaddr_store(struct kobject *kobj,
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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
Expand Down
1 change: 1 addition & 0 deletions net/sunrpc/sysfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions net/sunrpc/xprtmultipath.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5b7eb78

Please sign in to comment.