btrfs: fix processing of delayed tree block refs during backref walking
[platform/kernel/linux-rpi.git] / net / sunrpc / sysfs.c
index 9a6f17e..a7020b1 100644 (file)
@@ -282,8 +282,10 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
        int offline = 0, online = 0, remove = 0;
        struct rpc_xprt_switch *xps = rpc_sysfs_xprt_kobj_get_xprt_switch(kobj);
 
-       if (!xprt)
-               return 0;
+       if (!xprt || !xps) {
+               count = 0;
+               goto out_put;
+       }
 
        if (!strncmp(buf, "offline", 7))
                offline = 1;
@@ -291,8 +293,10 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                online = 1;
        else if (!strncmp(buf, "remove", 6))
                remove = 1;
-       else
-               return -EINVAL;
+       else {
+               count = -EINVAL;
+               goto out_put;
+       }
 
        if (wait_on_bit_lock(&xprt->state, XPRT_LOCKED, TASK_KILLABLE)) {
                count = -EINTR;
@@ -303,25 +307,28 @@ static ssize_t rpc_sysfs_xprt_state_change(struct kobject *kobj,
                goto release_tasks;
        }
        if (offline) {
-               set_bit(XPRT_OFFLINE, &xprt->state);
-               spin_lock(&xps->xps_lock);
-               xps->xps_nactive--;
-               spin_unlock(&xps->xps_lock);
+               if (!test_and_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);
+               if (test_and_clear_bit(XPRT_OFFLINE, &xprt->state)) {
+                       spin_lock(&xps->xps_lock);
+                       xps->xps_nactive++;
+                       spin_unlock(&xps->xps_lock);
+               }
        } else if (remove) {
                if (test_bit(XPRT_OFFLINE, &xprt->state)) {
-                       set_bit(XPRT_REMOVE, &xprt->state);
-                       xprt_force_disconnect(xprt);
-                       if (test_bit(XPRT_CONNECTED, &xprt->state)) {
-                               if (!xprt->sending.qlen &&
-                                   !xprt->pending.qlen &&
-                                   !xprt->backlog.qlen &&
-                                   !atomic_long_read(&xprt->queuelen))
-                                       rpc_xprt_switch_remove_xprt(xps, xprt);
+                       if (!test_and_set_bit(XPRT_REMOVE, &xprt->state)) {
+                               xprt_force_disconnect(xprt);
+                               if (test_bit(XPRT_CONNECTED, &xprt->state)) {
+                                       if (!xprt->sending.qlen &&
+                                           !xprt->pending.qlen &&
+                                           !xprt->backlog.qlen &&
+                                           !atomic_long_read(&xprt->queuelen))
+                                               rpc_xprt_switch_remove_xprt(xps, xprt);
+                               }
                        }
                } else {
                        count = -EINVAL;