@@ -428,6 +428,7 @@ void xprt_release_write(struct rpc_xprt *, struct rpc_task *);
#define XPRT_BINDING (5)
#define XPRT_CLOSING (6)
#define XPRT_OFFLINE (7)
+#define XPRT_REMOVE (8)
#define XPRT_CONGESTED (9)
#define XPRT_CWND_WAIT (10)
#define XPRT_WRITE_SPACE (11)
@@ -2106,6 +2106,26 @@ call_connect_status(struct rpc_task *task)
case -ENOTCONN:
case -EAGAIN:
case -ETIMEDOUT:
+ if (!(task->tk_flags & RPC_TASK_NO_ROUND_ROBIN) &&
+ (task->tk_flags & RPC_TASK_MOVEABLE) &&
+ test_bit(XPRT_REMOVE, &xprt->state)) {
+ struct rpc_xprt *saved = task->tk_xprt;
+ struct rpc_xprt_switch *xps;
+
+ rcu_read_lock();
+ xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
+ rcu_read_unlock();
+ if (xps->xps_nactive > 1) {
+ xprt_release(task);
+ xprt_put(saved);
+ rpc_xprt_switch_remove_xprt(xps, saved);
+ task->tk_xprt = NULL;
+ task->tk_action = call_start;
+ }
+ xprt_switch_put(xps);
+ if (!task->tk_xprt)
+ return;
+ }
goto out_retry;
case -ENOBUFS:
rpc_delay(task, HZ >> 2);
@@ -118,7 +118,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, offline;
+ closing, congested, cwnd_wait, write_space, offline, remove;
if (!xprt)
return 0;
@@ -137,8 +137,9 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
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);
+ remove = test_bit(XPRT_REMOVE, &xprt->state);
- ret = sprintf(buf, "state=%s %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 %s\n",
locked ? "LOCKED" : "",
connected ? "CONNECTED" : "",
connecting ? "CONNECTING" : "",
@@ -149,7 +150,8 @@ static ssize_t rpc_sysfs_xprt_state_show(struct kobject *kobj,
congested ? "CONGESTED" : "",
cwnd_wait ? "CWND_WAIT" : "",
write_space ? "WRITE_SPACE" : "",
- offline ? "OFFLINE" : "");
+ offline ? "OFFLINE" : "",
+ remove ? "REMOVE" : "");
}
xprt_put(xprt);
@@ -230,13 +232,15 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
const char *buf, size_t count)
{
struct rpc_xprt *xprt = rpc_sysfs_xprt_kobj_get_xprt(kobj);
- int offline = 0;
+ int offline = 0, remove = 0;
if (!xprt)
return 0;
if (!strncmp(buf, "offline", 7))
offline = 1;
+ else if (!strncmp(buf, "remove", 6))
+ remove = 1;
else
return -EINVAL;
@@ -249,6 +253,12 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
count = -EINVAL;
else
set_bit(XPRT_OFFLINE, &xprt->state);
+ } else if (remove) {
+ if (!test_bit(XPRT_CONNECTED, &xprt->state) &&
+ test_bit(XPRT_OFFLINE, &xprt->state))
+ set_bit(XPRT_REMOVE, &xprt->state);
+ else
+ count = -EINVAL;
}
xprt_release_write(xprt, NULL);