Commit 5b7eb784 authored by Olga Kornievskaia's avatar Olga Kornievskaia Committed by Trond Myklebust
Browse files

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: default avatarOlga Kornievskaia <kolga@netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent c1830a63
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
+62 −4
Original line number Diff line number Diff line
@@ -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 @@ 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);
@@ -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);
	}
}
+1 −0
Original line number Diff line number Diff line
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ static void xprt_switch_remove_xprt_locked(struct rpc_xprt_switch *xps,
{
	if (unlikely(xprt == NULL))
		return;
	if (!test_bit(XPRT_OFFLINE, &xprt->state))
		xps->xps_nactive--;
	xps->xps_nxprts--;
	if (xps->xps_nxprts == 0)
@@ -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