md/cluster: block reshape with remote resync job
authorZhao Heming <heming.zhao@suse.com>
Thu, 19 Nov 2020 11:41:33 +0000 (19:41 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 Dec 2020 10:54:25 +0000 (11:54 +0100)
commit a8da01f79c89755fad55ed0ea96e8d2103242a72 upstream.

Reshape request should be blocked with ongoing resync job. In cluster
env, a node can start resync job even if the resync cmd isn't executed
on it, e.g., user executes "mdadm --grow" on node A, sometimes node B
will start resync job. However, current update_raid_disks() only check
local recovery status, which is incomplete. As a result, we see user will
execute "mdadm --grow" successfully on local, while the remote node deny
to do reshape job when it doing resync job. The inconsistent handling
cause array enter unexpected status. If user doesn't observe this issue
and continue executing mdadm cmd, the array doesn't work at last.

Fix this issue by blocking reshape request. When node executes "--grow"
and detects ongoing resync, it should stop and report error to user.

The following script reproduces the issue with ~100% probability.
(two nodes share 3 iSCSI luns: sdg/sdh/sdi. Each lun size is 1GB)
```
 # on node1, node2 is the remote node.
ssh root@node2 "mdadm -S --scan"
mdadm -S --scan
for i in {g,h,i};do dd if=/dev/zero of=/dev/sd$i oflag=direct bs=1M \
count=20; done

mdadm -C /dev/md0 -b clustered -e 1.2 -n 2 -l mirror /dev/sdg /dev/sdh
ssh root@node2 "mdadm -A /dev/md0 /dev/sdg /dev/sdh"

sleep 5

mdadm --manage --add /dev/md0 /dev/sdi
mdadm --wait /dev/md0
mdadm --grow --raid-devices=3 /dev/md0

mdadm /dev/md0 --fail /dev/sdg
mdadm /dev/md0 --remove /dev/sdg
mdadm --grow --raid-devices=2 /dev/md0
```

Cc: stable@vger.kernel.org
Signed-off-by: Zhao Heming <heming.zhao@suse.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/md/md.c

index 4136bd8..55f9ddf 100644 (file)
@@ -7278,6 +7278,7 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
                return -EINVAL;
        if (mddev->sync_thread ||
            test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+           test_bit(MD_RESYNCING_REMOTE, &mddev->recovery) ||
            mddev->reshape_position != MaxSector)
                return -EBUSY;
 
@@ -9645,8 +9646,11 @@ static void check_sb_changes(struct mddev *mddev, struct md_rdev *rdev)
                }
        }
 
-       if (mddev->raid_disks != le32_to_cpu(sb->raid_disks))
-               update_raid_disks(mddev, le32_to_cpu(sb->raid_disks));
+       if (mddev->raid_disks != le32_to_cpu(sb->raid_disks)) {
+               ret = update_raid_disks(mddev, le32_to_cpu(sb->raid_disks));
+               if (ret)
+                       pr_warn("md: updating array disks failed. %d\n", ret);
+       }
 
        /*
         * Since mddev->delta_disks has already updated in update_raid_disks,