Thread (10 messages) 10 messages, 4 authors, 2024-02-06

Re: [PATCH 2/2] md: create symlink with disk holder after mddev resume

From: Linux regression tracking (Thorsten Leemhuis) <hidden>
Date: 2024-02-06 14:46:40
Also in: lkml, regressions

Hi, Thorsten here, the Linux kernel's regression tracker.

On 21.12.23 09:49, Yu Kuai wrote:
在 2023/12/21 15:11, linan666@huaweicloud.com 写道:
quoted
From: Li Nan <redacted>

There is a risk of deadlock when a process gets disk->open_mutex after
suspending mddev, because other processes may hold open_mutex while
submitting io. For example:
[...]
Nice catch! This patch looks good except that the new flag
'SymlinkCreated' doesn't look accurate, perhaps 'HolderLinked'
will make more sense.
quoted
Fix it by getting disk->open_mutex after mddev resume, iterating each
mddev->disk to create symlink for rdev which has not been created yet.
and moving bd_unlink_disk_holder() to mddev_unlock(), rdev has been
deleted from mddev->disks here, which can avoid concurrent bind and
unbind,

Fixes: 1b0a2d950ee2 ("md: use new apis to suspend array for ioctls
involed array reconfiguration")
Hey, what happened to that patch? It looks a lot like things stalled
here. I'm asking, because there is a regression report that claims
1b0a2d950ee2 to be the culprit that might or might not be causes by the
problem this patch tries to fix:
https://bugzilla.kernel.org/show_bug.cgi?id=218459

Ciao, Thorsten
quoted
Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 39 +++++++++++++++++++++++++++++----------
  1 file changed, 29 insertions(+), 10 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d6612b922c76..c128570f2a5d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -521,6 +521,20 @@ void mddev_resume(struct mddev *mddev)
  }
  EXPORT_SYMBOL_GPL(mddev_resume);
  +static void md_link_disk_holder(struct mddev *mddev)
+{
+    struct md_rdev *rdev;
+
+    rcu_read_lock();
+    rdev_for_each_rcu(rdev, mddev) {
+        if (test_bit(SymlinkCreated, &rdev->flags))
+            continue;
+        if (!bd_link_disk_holder(rdev->bdev, mddev->gendisk))
+            set_bit(SymlinkCreated, &rdev->flags);
+    }
+    rcu_read_unlock();
+}
+
  /*
   * Generic flush handling for md
   */
@@ -902,6 +916,11 @@ void mddev_unlock(struct mddev *mddev)
        list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
          list_del_init(&rdev->same_set);
+        if (test_bit(SymlinkCreated, &rdev->flags)) {
+            bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
+            clear_bit(SymlinkCreated, &rdev->flags);
+        }
+        rdev->mddev = NULL;
          kobject_del(&rdev->kobj);
          export_rdev(rdev, mddev);
      }
@@ -2526,8 +2545,6 @@ static int bind_rdev_to_array(struct md_rdev
*rdev, struct mddev *mddev)
          sysfs_get_dirent_safe(rdev->kobj.sd, "bad_blocks");
        list_add_rcu(&rdev->same_set, &mddev->disks);
-    if (!bd_link_disk_holder(rdev->bdev, mddev->gendisk))
-        set_bit(SymlinkCreated, &rdev->flags);
        /* May as well allow recovery to be retried once */
      mddev->recovery_disabled++;
@@ -2562,14 +2579,9 @@ static void md_kick_rdev_from_array(struct
md_rdev *rdev)
  {
      struct mddev *mddev = rdev->mddev;
  -    if (test_bit(SymlinkCreated, &rdev->flags)) {
-        bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
-        clear_bit(SymlinkCreated, &rdev->flags);
-    }
      list_del_rcu(&rdev->same_set);
      pr_debug("md: unbind<%pg>\n", rdev->bdev);
      mddev_destroy_serial_pool(rdev->mddev, rdev);
-    rdev->mddev = NULL;
      sysfs_remove_link(&rdev->kobj, "block");
      sysfs_put(rdev->sysfs_state);
      sysfs_put(rdev->sysfs_unack_badblocks);
@@ -4667,8 +4679,10 @@ new_dev_store(struct mddev *mddev, const char
*buf, size_t len)
      if (err)
          export_rdev(rdev, mddev);
      mddev_unlock_and_resume(mddev);
-    if (!err)
+    if (!err) {
+        md_link_disk_holder(mddev);
          md_new_event();
+    }
      return err ? err : len;
  }
  @@ -6606,6 +6620,7 @@ static void autorun_devices(int part)
              }
              autorun_array(mddev);
              mddev_unlock_and_resume(mddev);
+            md_link_disk_holder(mddev);
          }
          /* on success, candidates will be empty, on error
           * it won't...
@@ -7832,8 +7847,12 @@ static int md_ioctl(struct block_device *bdev,
blk_mode_t mode,
          err != -EINVAL)
          mddev->hold_active = 0;
  -    md_ioctl_need_suspend(cmd) ? mddev_unlock_and_resume(mddev) :
-                     mddev_unlock(mddev);
+    if (md_ioctl_need_suspend(cmd)) {
+        mddev_unlock_and_resume(mddev);
+        md_link_disk_holder(mddev);
+    } else {
+        mddev_unlock(mddev);
+    }
    out:
      if(did_set_md_closing)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help