SUNRPC: take a xprt offline using sysfs

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>
This commit is contained in:
Olga Kornievskaia 2021-06-23 23:28:50 -04:00 committed by Trond Myklebust
parent c1830a63c7
commit 5b7eb78486
4 changed files with 68 additions and 6 deletions

View 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)

View File

@ -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)
{
@ -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);
}
}

View 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);

View 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