[PATCH v5 0/8] bugfix of MD_CLOSING and clean up md_ioctl()

STALE936d

Revision v5 of 3 in this series.

16 messages, 2 authors, 2024-02-02 · open the first message on its own page

[PATCH v5 0/8] bugfix of MD_CLOSING and clean up md_ioctl()

From: <hidden>
Date: 2024-02-01 06:38:31

From: Li Nan <redacted>

Changes in v5:
 - add patches 1-4 to clean up md_ioct(), pathc 4 can help us clean up
   local variable 'clear_md_closing'.
 - in patches 5 and 7, clean up local variable 'clear_md_closing'.

By the way, md_ioctl() is not readable now, I wanna to re-write it later
to make it only have one 'switch' like other drivers.

Li Nan (8):
  md: merge the check of capabilities into md_ioctl_valid()
  md: changed the switch of RAID_VERSION to if
  md: clean up invalid BUG_ON in md_ioctl
  md: return directly before setting did_set_md_closing
  md: Don't clear MD_CLOSING when the raid is about to stop
  md: factor out a helper to sync mddev
  md: sync blockdev before stopping raid or setting readonly
  md: check mddev->pers before calling md_set_readonly()

 drivers/md/md.c | 149 ++++++++++++++++++++++++++----------------------
 1 file changed, 80 insertions(+), 69 deletions(-)

-- 
2.39.2

[PATCH v5 1/8] md: merge the check of capabilities into md_ioctl_valid()

From: <hidden>
Date: 2024-02-01 06:38:31

From: Li Nan <redacted>

There is no functional change. Just to make code cleaner.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e351e6c51cc7..1b509fb82040 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7545,16 +7545,17 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 	return 0;
 }
 
-static inline bool md_ioctl_valid(unsigned int cmd)
+static inline int md_ioctl_valid(unsigned int cmd)
 {
 	switch (cmd) {
-	case ADD_NEW_DISK:
 	case GET_ARRAY_INFO:
-	case GET_BITMAP_FILE:
 	case GET_DISK_INFO:
+	case RAID_VERSION:
+		return 0;
+	case ADD_NEW_DISK:
+	case GET_BITMAP_FILE:
 	case HOT_ADD_DISK:
 	case HOT_REMOVE_DISK:
-	case RAID_VERSION:
 	case RESTART_ARRAY_RW:
 	case RUN_ARRAY:
 	case SET_ARRAY_INFO:
@@ -7563,9 +7564,11 @@ static inline bool md_ioctl_valid(unsigned int cmd)
 	case STOP_ARRAY:
 	case STOP_ARRAY_RO:
 	case CLUSTERED_DISK_NACK:
-		return true;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return 0;
 	default:
-		return false;
+		return -ENOTTY;
 	}
 }
 
@@ -7625,18 +7628,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 	struct mddev *mddev = NULL;
 	bool did_set_md_closing = false;
 
-	if (!md_ioctl_valid(cmd))
-		return -ENOTTY;
-
-	switch (cmd) {
-	case RAID_VERSION:
-	case GET_ARRAY_INFO:
-	case GET_DISK_INFO:
-		break;
-	default:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-	}
+	err = md_ioctl_valid(cmd);
+	if (err)
+		return err;
 
 	/*
 	 * Commands dealing with the RAID driver but not any
-- 
2.39.2

[PATCH v5 2/8] md: changed the switch of RAID_VERSION to if

From: <hidden>
Date: 2024-02-01 06:38:32

From: Li Nan <redacted>

There is only one case of this 'switch'. Change it to 'if'.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 1b509fb82040..3b4e0ef49675 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7636,11 +7636,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 	 * Commands dealing with the RAID driver but not any
 	 * particular array:
 	 */
-	switch (cmd) {
-	case RAID_VERSION:
+	if (cmd == RAID_VERSION) {
 		err = get_version(argp);
 		goto out;
-	default:;
 	}
 
 	/*
-- 
2.39.2

[PATCH v5 3/8] md: clean up invalid BUG_ON in md_ioctl

From: <hidden>
Date: 2024-02-01 06:38:33

From: Li Nan <redacted>

'disk->private_data' is set to mddev in md_alloc() and never set to NULL,
and users need to open mddev before submitting ioctl. So mddev must not
have been freed during ioctl, and there is no need to check mddev here.
Clean up it.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 5 -----
 1 file changed, 5 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3b4e0ef49675..656080086052 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7647,11 +7647,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 
 	mddev = bdev->bd_disk->private_data;
 
-	if (!mddev) {
-		BUG();
-		goto out;
-	}
-
 	/* Some actions do not requires the mutex */
 	switch (cmd) {
 	case GET_ARRAY_INFO:
-- 
2.39.2

[PATCH v5 4/8] md: return directly before setting did_set_md_closing

From: <hidden>
Date: 2024-02-01 06:38:33

From: Li Nan <redacted>

There is nothing to do at 'out' before setting 'did_set_md_closing'
in md_ioctl(). Return directly, and it will help us to remove
'did_set_md_closing' later.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 656080086052..5442e8e3c161 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7636,10 +7636,8 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 	 * Commands dealing with the RAID driver but not any
 	 * particular array:
 	 */
-	if (cmd == RAID_VERSION) {
-		err = get_version(argp);
-		goto out;
-	}
+	if (cmd == RAID_VERSION)
+		return get_version(argp);
 
 	/*
 	 * Commands creating/starting a new array:
@@ -7654,23 +7652,20 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 			err = -ENODEV;
 		else
 			err = get_array_info(mddev, argp);
-		goto out;
+		return err;
 
 	case GET_DISK_INFO:
 		if (!mddev->raid_disks && !mddev->external)
 			err = -ENODEV;
 		else
 			err = get_disk_info(mddev, argp);
-		goto out;
+		return err;
 
 	case SET_DISK_FAULTY:
-		err = set_disk_faulty(mddev, new_decode_dev(arg));
-		goto out;
+		return set_disk_faulty(mddev, new_decode_dev(arg));
 
 	case GET_BITMAP_FILE:
-		err = get_bitmap_file(mddev, argp);
-		goto out;
-
+		return get_bitmap_file(mddev, argp);
 	}
 
 	if (cmd == HOT_REMOVE_DISK)
@@ -7686,13 +7681,11 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 		mutex_lock(&mddev->open_mutex);
 		if (mddev->pers && atomic_read(&mddev->openers) > 1) {
 			mutex_unlock(&mddev->open_mutex);
-			err = -EBUSY;
-			goto out;
+			return -EBUSY;
 		}
 		if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
 			mutex_unlock(&mddev->open_mutex);
-			err = -EBUSY;
-			goto out;
+			return -EBUSY;
 		}
 		did_set_md_closing = true;
 		mutex_unlock(&mddev->open_mutex);
-- 
2.39.2

[PATCH v5 6/8] md: factor out a helper to sync mddev

From: <hidden>
Date: 2024-02-01 06:38:33

From: Li Nan <redacted>

There are no functional changes, prepare to sync mddev in
array_state_store().

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index deee004b8f22..4c7a0225f77d 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -515,6 +515,24 @@ void mddev_resume(struct mddev *mddev)
 }
 EXPORT_SYMBOL_GPL(mddev_resume);
 
+/* sync bdev before setting device to readonly or stopping raid*/
+static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev)
+{
+	mutex_lock(&mddev->open_mutex);
+	if (mddev->pers && atomic_read(&mddev->openers) > 1) {
+		mutex_unlock(&mddev->open_mutex);
+		return -EBUSY;
+	}
+	if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
+		mutex_unlock(&mddev->open_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&mddev->open_mutex);
+
+	sync_blockdev(mddev->gendisk->part0);
+	return 0;
+}
+
 /*
  * Generic flush handling for md
  */
@@ -7685,17 +7703,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 		/* Need to flush page cache, and ensure no-one else opens
 		 * and writes
 		 */
-		mutex_lock(&mddev->open_mutex);
-		if (mddev->pers && atomic_read(&mddev->openers) > 1) {
-			mutex_unlock(&mddev->open_mutex);
-			return -EBUSY;
-		}
-		if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
-			mutex_unlock(&mddev->open_mutex);
-			return -EBUSY;
-		}
-		mutex_unlock(&mddev->open_mutex);
-		sync_blockdev(bdev);
+		err = mddev_set_closing_and_sync_blockdev(mddev);
+		if (err)
+			return err;
 	}
 
 	if (!md_is_rdwr(mddev))
-- 
2.39.2

[PATCH v5 5/8] md: Don't clear MD_CLOSING when the raid is about to stop

From: <hidden>
Date: 2024-02-01 06:38:33

From: Li Nan <redacted>

The raid should not be opened anymore when it is about to be stopped.
However, other processes can open it again if the flag MD_CLOSING is
cleared before exiting. From now on, this flag will not be cleared when
the raid will be stopped.

Fixes: 065e519e71b2 ("md: MD_CLOSING needs to be cleared after called md_set_readonly or do_md_stop")
Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5442e8e3c161..deee004b8f22 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6247,7 +6247,15 @@ static void md_clean(struct mddev *mddev)
 	mddev->persistent = 0;
 	mddev->level = LEVEL_NONE;
 	mddev->clevel[0] = 0;
-	mddev->flags = 0;
+	/*
+	 * Don't clear MD_CLOSING, or mddev can be opened again.
+	 * 'hold_active != 0' means mddev is still in the creation
+	 * process and will be used later.
+	 */
+	if (mddev->hold_active)
+		mddev->flags = 0;
+	else
+		mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
 	mddev->sb_flags = 0;
 	mddev->ro = MD_RDWR;
 	mddev->metadata_type[0] = 0;
@@ -7626,7 +7634,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 	int err = 0;
 	void __user *argp = (void __user *)arg;
 	struct mddev *mddev = NULL;
-	bool did_set_md_closing = false;
 
 	err = md_ioctl_valid(cmd);
 	if (err)
@@ -7687,7 +7694,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 			mutex_unlock(&mddev->open_mutex);
 			return -EBUSY;
 		}
-		did_set_md_closing = true;
 		mutex_unlock(&mddev->open_mutex);
 		sync_blockdev(bdev);
 	}
@@ -7829,7 +7835,7 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 				     mddev_unlock(mddev);
 
 out:
-	if(did_set_md_closing)
+	if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
 		clear_bit(MD_CLOSING, &mddev->flags);
 	return err;
 }
-- 
2.39.2

[PATCH v5 7/8] md: sync blockdev before stopping raid or setting readonly

From: <hidden>
Date: 2024-02-01 06:38:34

From: Li Nan <redacted>

Commit a05b7ea03d72 ("md: avoid crash when stopping md array races
with closing other open fds.") added sync_block before stopping raid and
setting readonly. Later in commit 260fa034ef7a ("md: avoid deadlock when
dirty buffers during md_stop.") it is moved to ioctl. array_state_store()
was ignored. Add sync blockdev to array_state_store() now.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4c7a0225f77d..86becf0015f5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -4493,6 +4493,16 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
 	case broken:		/* cannot be set */
 	case bad_word:
 		return -EINVAL;
+	case clear:
+	case readonly:
+	case inactive:
+	case read_auto:
+		if (!mddev->pers || !md_is_rdwr(mddev))
+			break;
+		err = mddev_set_closing_and_sync_blockdev(mddev);
+		if (err)
+			return err;
+		break;
 	default:
 		break;
 	}
@@ -4518,6 +4528,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
 		spin_unlock(&mddev->lock);
 		return err ?: len;
 	}
+
 	err = mddev_lock(mddev);
 	if (err)
 		return err;
@@ -4592,6 +4603,11 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
 		sysfs_notify_dirent_safe(mddev->sysfs_state);
 	}
 	mddev_unlock(mddev);
+
+	if (st == readonly || st == read_auto || st == inactive ||
+	    (err && st == clear))
+		clear_bit(MD_CLOSING, &mddev->flags);
+
 	return err ?: len;
 }
 static struct md_sysfs_entry md_array_state =
-- 
2.39.2

[PATCH v5 8/8] md: check mddev->pers before calling md_set_readonly()

From: <hidden>
Date: 2024-02-01 06:38:34

From: Li Nan <redacted>

If 'mddev->pers' is NULL, there is nothing to do in md_set_readonly().
Except for md_ioctl(), the other two callers of md_set_readonly() have
already checked 'mddev->pers'. To simplify the code, move the check of
'mddev->pers' to the caller.

Signed-off-by: Li Nan <redacted>
---
 drivers/md/md.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 86becf0015f5..2976cf778df3 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6412,6 +6412,7 @@ void md_stop(struct mddev *mddev)
 
 EXPORT_SYMBOL_GPL(md_stop);
 
+/* ensure 'mddev->pers' exist before calling md_set_readonly() */
 static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
 {
 	int err = 0;
@@ -6441,8 +6442,7 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
 	mddev_lock_nointr(mddev);
 
 	mutex_lock(&mddev->open_mutex);
-	if ((mddev->pers && atomic_read(&mddev->openers) > !!bdev) ||
-	    mddev->sync_thread ||
+	if (atomic_read(&mddev->openers) > !!bdev || mddev->sync_thread ||
 	    test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) {
 		pr_warn("md: %s still in use.\n",mdname(mddev));
 		if (did_freeze) {
@@ -6453,20 +6453,18 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
 		err = -EBUSY;
 		goto out;
 	}
-	if (mddev->pers) {
-		__md_stop_writes(mddev);
+	__md_stop_writes(mddev);
 
-		err  = -ENXIO;
-		if (mddev->ro == MD_RDONLY)
-			goto out;
-		mddev->ro = MD_RDONLY;
-		set_disk_ro(mddev->gendisk, 1);
-		clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
-		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
-		md_wakeup_thread(mddev->thread);
-		sysfs_notify_dirent_safe(mddev->sysfs_state);
-		err = 0;
-	}
+	err  = -ENXIO;
+	if (mddev->ro == MD_RDONLY)
+		goto out;
+	mddev->ro = MD_RDONLY;
+	set_disk_ro(mddev->gendisk, 1);
+	clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+	md_wakeup_thread(mddev->thread);
+	sysfs_notify_dirent_safe(mddev->sysfs_state);
+	err = 0;
 out:
 	mutex_unlock(&mddev->open_mutex);
 	return err;
@@ -7766,7 +7764,8 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
 		goto unlock;
 
 	case STOP_ARRAY_RO:
-		err = md_set_readonly(mddev, bdev);
+		if (mddev->pers)
+			err = md_set_readonly(mddev, bdev);
 		goto unlock;
 
 	case HOT_REMOVE_DISK:
-- 
2.39.2

Re: [PATCH v5 1/8] md: merge the check of capabilities into md_ioctl_valid()

From: Yu Kuai <hidden>
Date: 2024-02-02 01:17:17

在 2024/02/01 14:33, linan666@huaweicloud.com 写道:
From: Li Nan <redacted>

There is no functional change. Just to make code cleaner.

Signed-off-by: Li Nan <redacted>
LGTM
Reviewed-by: Yu Kuai <redacted>
quoted hunk
---
  drivers/md/md.c | 30 ++++++++++++------------------
  1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e351e6c51cc7..1b509fb82040 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7545,16 +7545,17 @@ static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  	return 0;
  }
  
-static inline bool md_ioctl_valid(unsigned int cmd)
+static inline int md_ioctl_valid(unsigned int cmd)
  {
  	switch (cmd) {
-	case ADD_NEW_DISK:
  	case GET_ARRAY_INFO:
-	case GET_BITMAP_FILE:
  	case GET_DISK_INFO:
+	case RAID_VERSION:
+		return 0;
+	case ADD_NEW_DISK:
+	case GET_BITMAP_FILE:
  	case HOT_ADD_DISK:
  	case HOT_REMOVE_DISK:
-	case RAID_VERSION:
  	case RESTART_ARRAY_RW:
  	case RUN_ARRAY:
  	case SET_ARRAY_INFO:
@@ -7563,9 +7564,11 @@ static inline bool md_ioctl_valid(unsigned int cmd)
  	case STOP_ARRAY:
  	case STOP_ARRAY_RO:
  	case CLUSTERED_DISK_NACK:
-		return true;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return 0;
  	default:
-		return false;
+		return -ENOTTY;
  	}
  }
  
@@ -7625,18 +7628,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  	struct mddev *mddev = NULL;
  	bool did_set_md_closing = false;
  
-	if (!md_ioctl_valid(cmd))
-		return -ENOTTY;
-
-	switch (cmd) {
-	case RAID_VERSION:
-	case GET_ARRAY_INFO:
-	case GET_DISK_INFO:
-		break;
-	default:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-	}
+	err = md_ioctl_valid(cmd);
+	if (err)
+		return err;
  
  	/*
  	 * Commands dealing with the RAID driver but not any

Re: [PATCH v5 2/8] md: changed the switch of RAID_VERSION to if

From: Yu Kuai <hidden>
Date: 2024-02-02 01:19:38

Hi,

在 2024/02/01 14:33, linan666@huaweicloud.com 写道:
quoted hunk
From: Li Nan <redacted>

There is only one case of this 'switch'. Change it to 'if'.

Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 4 +---
  1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 1b509fb82040..3b4e0ef49675 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7636,11 +7636,9 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  	 * Commands dealing with the RAID driver but not any
  	 * particular array:
  	 */
-	switch (cmd) {
-	case RAID_VERSION:
+	if (cmd == RAID_VERSION) {
  		err = get_version(argp);
  		goto out;
you can just return here;

if (cmd == RAID_VERSION)
	return get_version(argp);

Thanks,
Kuai
-	default:;
  	}
  
  	/*

Re: [PATCH v5 3/8] md: clean up invalid BUG_ON in md_ioctl

From: Yu Kuai <hidden>
Date: 2024-02-02 01:20:50

在 2024/02/01 14:33, linan666@huaweicloud.com 写道:
quoted hunk
From: Li Nan <redacted>

'disk->private_data' is set to mddev in md_alloc() and never set to NULL,
and users need to open mddev before submitting ioctl. So mddev must not
have been freed during ioctl, and there is no need to check mddev here.
Clean up it.

Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 5 -----
  1 file changed, 5 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3b4e0ef49675..656080086052 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7647,11 +7647,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  
  	mddev = bdev->bd_disk->private_data;
  
-	if (!mddev) {
-		BUG();
Given that this BUG() never triggered before.

Reviewed-by: Yu Kuai <redacted>
-		goto out;
-	}
-
  	/* Some actions do not requires the mutex */
  	switch (cmd) {
  	case GET_ARRAY_INFO:

Re: [PATCH v5 4/8] md: return directly before setting did_set_md_closing

From: Yu Kuai <hidden>
Date: 2024-02-02 01:24:54

Hi,

在 2024/02/01 14:34, linan666@huaweicloud.com 写道:
quoted hunk
From: Li Nan <redacted>

There is nothing to do at 'out' before setting 'did_set_md_closing'
in md_ioctl(). Return directly, and it will help us to remove
'did_set_md_closing' later.

Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 23 ++++++++---------------
  1 file changed, 8 insertions(+), 15 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 656080086052..5442e8e3c161 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7636,10 +7636,8 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  	 * Commands dealing with the RAID driver but not any
  	 * particular array:
  	 */
-	if (cmd == RAID_VERSION) {
-		err = get_version(argp);
-		goto out;
-	}
+	if (cmd == RAID_VERSION)
+		return get_version(argp);
Please merge this into patch 2.
quoted hunk
  
  	/*
  	 * Commands creating/starting a new array:
@@ -7654,23 +7652,20 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  			err = -ENODEV;
  		else
  			err = get_array_info(mddev, argp);
You can also remove 'err' here:

if (...)
	return -ENODEV;
return get_array_info(mddev, argp);
-		goto out;
+		return err;
  
  	case GET_DISK_INFO:
  		if (!mddev->raid_disks && !mddev->external)
  			err = -ENODEV;
  		else
  			err = get_disk_info(mddev, argp);
Same here.

Thanks,
Kuai
quoted hunk
-		goto out;
+		return err;
  
  	case SET_DISK_FAULTY:
-		err = set_disk_faulty(mddev, new_decode_dev(arg));
-		goto out;
+		return set_disk_faulty(mddev, new_decode_dev(arg));
  
  	case GET_BITMAP_FILE:
-		err = get_bitmap_file(mddev, argp);
-		goto out;
-
+		return get_bitmap_file(mddev, argp);
  	}
  
  	if (cmd == HOT_REMOVE_DISK)
@@ -7686,13 +7681,11 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  		mutex_lock(&mddev->open_mutex);
  		if (mddev->pers && atomic_read(&mddev->openers) > 1) {
  			mutex_unlock(&mddev->open_mutex);
-			err = -EBUSY;
-			goto out;
+			return -EBUSY;
  		}
  		if (test_and_set_bit(MD_CLOSING, &mddev->flags)) {
  			mutex_unlock(&mddev->open_mutex);
-			err = -EBUSY;
-			goto out;
+			return -EBUSY;
  		}
  		did_set_md_closing = true;
  		mutex_unlock(&mddev->open_mutex);

Re: [PATCH v5 5/8] md: Don't clear MD_CLOSING when the raid is about to stop

From: Yu Kuai <hidden>
Date: 2024-02-02 01:26:34

在 2024/02/01 14:34, linan666@huaweicloud.com 写道:
From: Li Nan <redacted>

The raid should not be opened anymore when it is about to be stopped.
However, other processes can open it again if the flag MD_CLOSING is
cleared before exiting. From now on, this flag will not be cleared when
the raid will be stopped.

Fixes: 065e519e71b2 ("md: MD_CLOSING needs to be cleared after called md_set_readonly or do_md_stop")
Signed-off-by: Li Nan <redacted>
LGTM
Reviewed-by: Yu Kuai <redacted>
quoted hunk
---
  drivers/md/md.c | 14 ++++++++++----
  1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5442e8e3c161..deee004b8f22 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6247,7 +6247,15 @@ static void md_clean(struct mddev *mddev)
  	mddev->persistent = 0;
  	mddev->level = LEVEL_NONE;
  	mddev->clevel[0] = 0;
-	mddev->flags = 0;
+	/*
+	 * Don't clear MD_CLOSING, or mddev can be opened again.
+	 * 'hold_active != 0' means mddev is still in the creation
+	 * process and will be used later.
+	 */
+	if (mddev->hold_active)
+		mddev->flags = 0;
+	else
+		mddev->flags &= BIT_ULL_MASK(MD_CLOSING);
  	mddev->sb_flags = 0;
  	mddev->ro = MD_RDWR;
  	mddev->metadata_type[0] = 0;
@@ -7626,7 +7634,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  	int err = 0;
  	void __user *argp = (void __user *)arg;
  	struct mddev *mddev = NULL;
-	bool did_set_md_closing = false;
  
  	err = md_ioctl_valid(cmd);
  	if (err)
@@ -7687,7 +7694,6 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  			mutex_unlock(&mddev->open_mutex);
  			return -EBUSY;
  		}
-		did_set_md_closing = true;
  		mutex_unlock(&mddev->open_mutex);
  		sync_blockdev(bdev);
  	}
@@ -7829,7 +7835,7 @@ static int md_ioctl(struct block_device *bdev, blk_mode_t mode,
  				     mddev_unlock(mddev);
  
  out:
-	if(did_set_md_closing)
+	if (cmd == STOP_ARRAY_RO || (err && cmd == STOP_ARRAY))
  		clear_bit(MD_CLOSING, &mddev->flags);
  	return err;
  }

Re: [PATCH v5 7/8] md: sync blockdev before stopping raid or setting readonly

From: Yu Kuai <hidden>
Date: 2024-02-02 02:12:20

Hi,

在 2024/02/01 14:34, linan666@huaweicloud.com 写道:
From: Li Nan <redacted>

Commit a05b7ea03d72 ("md: avoid crash when stopping md array races
with closing other open fds.") added sync_block before stopping raid and
setting readonly. Later in commit 260fa034ef7a ("md: avoid deadlock when
dirty buffers during md_stop.") it is moved to ioctl. array_state_store()
was ignored. Add sync blockdev to array_state_store() now.
You're not just adding sync_blockdev() here. Please rewrite the tittle
and commit message.
quoted hunk
Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 16 ++++++++++++++++
  1 file changed, 16 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4c7a0225f77d..86becf0015f5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -4493,6 +4493,16 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
  	case broken:		/* cannot be set */
  	case bad_word:
  		return -EINVAL;
+	case clear:
+	case readonly:
+	case inactive:
+	case read_auto:
+		if (!mddev->pers || !md_is_rdwr(mddev))
+			break;
+		err = mddev_set_closing_and_sync_blockdev(mddev);
In this context, mddev->openers should be zero, and such check is in
do_md_stop() and md_set_readonly():

if (atomic_read(&mddev->openers) > !!bdev).

Thanks,
Kuai
quoted hunk
+		if (err)
+			return err;
+		break;
  	default:
  		break;
  	}
@@ -4518,6 +4528,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
  		spin_unlock(&mddev->lock);
  		return err ?: len;
  	}
+
  	err = mddev_lock(mddev);
  	if (err)
  		return err;
@@ -4592,6 +4603,11 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
  	}
  	mddev_unlock(mddev);
+
+	if (st == readonly || st == read_auto || st == inactive ||
+	    (err && st == clear))
+		clear_bit(MD_CLOSING, &mddev->flags);
+
  	return err ?: len;
  }
  static struct md_sysfs_entry md_array_state =

Re: [PATCH v5 7/8] md: sync blockdev before stopping raid or setting readonly

From: Li Nan <hidden>
Date: 2024-02-02 09:26:43


在 2024/2/2 10:12, Yu Kuai 写道:
Hi,

在 2024/02/01 14:34, linan666@huaweicloud.com 写道:
quoted
From: Li Nan <redacted>

Commit a05b7ea03d72 ("md: avoid crash when stopping md array races
with closing other open fds.") added sync_block before stopping raid and
setting readonly. Later in commit 260fa034ef7a ("md: avoid deadlock when
dirty buffers during md_stop.") it is moved to ioctl. array_state_store()
was ignored. Add sync blockdev to array_state_store() now.
You're not just adding sync_blockdev() here. Please rewrite the tittle
and commit message.
quoted
Signed-off-by: Li Nan <redacted>
---
  drivers/md/md.c | 16 ++++++++++++++++
  1 file changed, 16 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4c7a0225f77d..86becf0015f5 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -4493,6 +4493,16 @@ array_state_store(struct mddev *mddev, const char 
*buf, size_t len)
      case broken:        /* cannot be set */
      case bad_word:
          return -EINVAL;
+    case clear:
+    case readonly:
+    case inactive:
+    case read_auto:
+        if (!mddev->pers || !md_is_rdwr(mddev))
+            break;
+        err = mddev_set_closing_and_sync_blockdev(mddev);
In this context, mddev->openers should be zero, and such check is in
do_md_stop() and md_set_readonly():
Yeah, the checks in do_md_stop() and md_set_readonly() can be removed after
this patch. However, 'mddev->open_metux' is used to protect MD_CLOSING and
'mddev->openers', it can be removed in these functions, too.

I will fix it later. Thanks for your review.
if (atomic_read(&mddev->openers) > !!bdev).

Thanks,
Kuai


-- 
Thanks,
Nan
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help