Commit 1a48db3f authored by Anna Schumaker's avatar Anna Schumaker

sunrpc: Fix potential race conditions in rpc_sysfs_xprt_state_change()

We need to use test_and_set_bit() when changing xprt state flags to
avoid potentially getting xps->xps_nactive out of sync.
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 776d794f
...@@ -309,25 +309,28 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj, ...@@ -309,25 +309,28 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
goto release_tasks; goto release_tasks;
} }
if (offline) { if (offline) {
set_bit(XPRT_OFFLINE, &xprt->state); if (!test_and_set_bit(XPRT_OFFLINE, &xprt->state)) {
spin_lock(&xps->xps_lock); spin_lock(&xps->xps_lock);
xps->xps_nactive--; xps->xps_nactive--;
spin_unlock(&xps->xps_lock); spin_unlock(&xps->xps_lock);
}
} else if (online) { } else if (online) {
clear_bit(XPRT_OFFLINE, &xprt->state); if (test_and_clear_bit(XPRT_OFFLINE, &xprt->state)) {
spin_lock(&xps->xps_lock); spin_lock(&xps->xps_lock);
xps->xps_nactive++; xps->xps_nactive++;
spin_unlock(&xps->xps_lock); spin_unlock(&xps->xps_lock);
}
} else if (remove) { } else if (remove) {
if (test_bit(XPRT_OFFLINE, &xprt->state)) { if (test_bit(XPRT_OFFLINE, &xprt->state)) {
set_bit(XPRT_REMOVE, &xprt->state); if (!test_and_set_bit(XPRT_REMOVE, &xprt->state)) {
xprt_force_disconnect(xprt); xprt_force_disconnect(xprt);
if (test_bit(XPRT_CONNECTED, &xprt->state)) { if (test_bit(XPRT_CONNECTED, &xprt->state)) {
if (!xprt->sending.qlen && if (!xprt->sending.qlen &&
!xprt->pending.qlen && !xprt->pending.qlen &&
!xprt->backlog.qlen && !xprt->backlog.qlen &&
!atomic_long_read(&xprt->queuelen)) !atomic_long_read(&xprt->queuelen))
rpc_xprt_switch_remove_xprt(xps, xprt); rpc_xprt_switch_remove_xprt(xps, xprt);
}
} }
} else { } else {
count = -EINVAL; count = -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment