summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2026-04-28 08:36:26 -0600
committerJens Axboe <axboe@kernel.dk>2026-04-28 08:36:26 -0600
commit7e36e03d192a5547757bd8f9d9052a60f64e6d17 (patch)
tree00b761d8b4b86bb734e392a4aa310106f437e4ce
parent0898a817621a2f0cddca8122d9b974003fe5036d (diff)
parent3b2f70eab5a2cd15e27b1447e66e45302b28ff2c (diff)
Merge tag 'md-7.1-20260428' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux into block-7.1
Pull MD fixes from Yu Kuai: "Bug Fixes: - Fix a raid5 UAF on IO across the reshape position. - Avoid failing RAID1/RAID10 devices for invalid IO errors. - Fix RAID10 divide-by-zero when far_copies is zero. - Restore bitmap grow through sysfs. Cleanups: - Use mddev_is_dm() instead of open-coding gendisk checks. - Use ATTRIBUTE_GROUPS() for md default sysfs attributes. - Replace open-coded wait loops with wait_event helpers." * tag 'md-7.1-20260428' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux: md: use ATTRIBUTE_GROUPS() for md default sysfs attributes md: use mddev_is_dm() instead of open-coding gendisk checks md/raid1: replace wait loop with wait_event_idle() in raid1_write_request() md/md-bitmap: add a none backend for bitmap grow md/md-bitmap: split bitmap sysfs groups md: factor bitmap creation away from sysfs handling md: use mddev_lock_nointr() in mddev_suspend_and_lock_nointr() md: replace wait loop with wait_event() in md_handle_request() md/raid10: fix divide-by-zero in setup_geo() with zero far_copies md/raid1,raid10: don't fail devices for invalid IO errors MAINTAINERS: Add Xiao Ni as md/raid reviewer md/raid5: Fix UAF on IO across the reshape position
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/md/md-bitmap.c131
-rw-r--r--drivers/md/md-bitmap.h2
-rw-r--r--drivers/md/md-llbitmap.c7
-rw-r--r--drivers/md/md.c182
-rw-r--r--drivers/md/md.h6
-rw-r--r--drivers/md/raid1-10.c7
-rw-r--r--drivers/md/raid1.c15
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/md/raid5.c7
10 files changed, 251 insertions, 109 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..06c00e40999f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24764,6 +24764,7 @@ SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
M: Yu Kuai <yukuai@fnnas.com>
R: Li Nan <linan122@huawei.com>
+R: Xiao Ni <xiao@kernel.org>
L: linux-raid@vger.kernel.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-raid/list/
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 83378c033c72..028b9ca8ce52 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -216,6 +216,7 @@ struct bitmap {
};
static struct workqueue_struct *md_bitmap_wq;
+static struct attribute_group md_bitmap_internal_group;
static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
int chunksize, bool init);
@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
return __bitmap_resize(bitmap, blocks, chunksize, false);
}
+static bool bitmap_none_enabled(void *data, bool flush)
+{
+ return false;
+}
+
+static int bitmap_none_create(struct mddev *mddev)
+{
+ return 0;
+}
+
+static int bitmap_none_load(struct mddev *mddev)
+{
+ return 0;
+}
+
+static void bitmap_none_destroy(struct mddev *mddev)
+{
+}
+
+static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats)
+{
+ return -ENOENT;
+}
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
goto out;
}
- bitmap_destroy(mddev);
+ sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto none_err;
mddev->bitmap_info.offset = 0;
if (mddev->bitmap_info.file) {
struct file *f = mddev->bitmap_info.file;
@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
}
mddev->bitmap_info.offset = offset;
- rv = bitmap_create(mddev);
+ md_bitmap_destroy_nosysfs(mddev);
+ mddev->bitmap_id = ID_BITMAP;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ goto bitmap_err;
+
+ rv = md_bitmap_create_nosysfs(mddev);
if (rv)
- goto out;
+ goto create_err;
- rv = bitmap_load(mddev);
+ rv = mddev->bitmap_ops->load(mddev);
if (rv) {
mddev->bitmap_info.offset = 0;
- bitmap_destroy(mddev);
- goto out;
+ goto load_err;
}
+
+ rv = sysfs_merge_group(&mddev->kobj,
+ &md_bitmap_internal_group);
+ if (rv)
+ goto merge_err;
}
}
if (!mddev->external) {
@@ -2679,6 +2717,22 @@ out:
if (rv)
return rv;
return len;
+
+merge_err:
+ mddev->bitmap_info.offset = 0;
+load_err:
+ md_bitmap_destroy_nosysfs(mddev);
+create_err:
+ mddev->bitmap_info.offset = 0;
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ rv = -ENOENT;
+ goto out;
+bitmap_err:
+ rv = -ENOENT;
+none_err:
+ mddev->bitmap_info.offset = 0;
+ goto out;
}
static struct md_sysfs_entry bitmap_location =
@@ -2955,8 +3009,12 @@ static struct md_sysfs_entry max_backlog_used =
__ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
behind_writes_used_show, behind_writes_used_reset);
-static struct attribute *md_bitmap_attrs[] = {
+static struct attribute *md_bitmap_common_attrs[] = {
&bitmap_location.attr,
+ NULL
+};
+
+static struct attribute *md_bitmap_internal_attrs[] = {
&bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
@@ -2967,9 +3025,41 @@ static struct attribute *md_bitmap_attrs[] = {
NULL
};
-static struct attribute_group md_bitmap_group = {
+static struct attribute_group md_bitmap_common_group = {
.name = "bitmap",
- .attrs = md_bitmap_attrs,
+ .attrs = md_bitmap_common_attrs,
+};
+
+static struct attribute_group md_bitmap_internal_group = {
+ .name = "bitmap",
+ .attrs = md_bitmap_internal_attrs,
+};
+
+static const struct attribute_group *bitmap_groups[] = {
+ &md_bitmap_common_group,
+ &md_bitmap_internal_group,
+ NULL,
+};
+
+static const struct attribute_group *bitmap_none_groups[] = {
+ &md_bitmap_common_group,
+ NULL,
+};
+
+static struct bitmap_operations bitmap_none_ops = {
+ .head = {
+ .type = MD_BITMAP,
+ .id = ID_BITMAP_NONE,
+ .name = "none",
+ },
+
+ .enabled = bitmap_none_enabled,
+ .create = bitmap_none_create,
+ .load = bitmap_none_load,
+ .destroy = bitmap_none_destroy,
+ .get_stats = bitmap_none_get_stats,
+
+ .groups = bitmap_none_groups,
};
static struct bitmap_operations bitmap_ops = {
@@ -3013,21 +3103,38 @@ static struct bitmap_operations bitmap_ops = {
.set_pages = bitmap_set_pages,
.free = md_bitmap_free,
- .group = &md_bitmap_group,
+ .groups = bitmap_groups,
};
int md_bitmap_init(void)
{
+ int err;
+
md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND,
0);
if (!md_bitmap_wq)
return -ENOMEM;
- return register_md_submodule(&bitmap_ops.head);
+ err = register_md_submodule(&bitmap_none_ops.head);
+ if (err)
+ goto err_wq;
+
+ err = register_md_submodule(&bitmap_ops.head);
+ if (err)
+ goto err_none;
+
+ return 0;
+
+err_none:
+ unregister_md_submodule(&bitmap_none_ops.head);
+err_wq:
+ destroy_workqueue(md_bitmap_wq);
+ return err;
}
void md_bitmap_exit(void)
{
- destroy_workqueue(md_bitmap_wq);
unregister_md_submodule(&bitmap_ops.head);
+ unregister_md_submodule(&bitmap_none_ops.head);
+ destroy_workqueue(md_bitmap_wq);
}
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
index b42a28fa83a0..214f623c7e79 100644
--- a/drivers/md/md-bitmap.h
+++ b/drivers/md/md-bitmap.h
@@ -125,7 +125,7 @@ struct bitmap_operations {
void (*set_pages)(void *data, unsigned long pages);
void (*free)(void *data);
- struct attribute_group *group;
+ const struct attribute_group **groups;
};
/* the bitmap API */
diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
index 9e7e6b1a6f15..1adc5b117821 100644
--- a/drivers/md/md-llbitmap.c
+++ b/drivers/md/md-llbitmap.c
@@ -1738,6 +1738,11 @@ static struct attribute_group md_llbitmap_group = {
.attrs = md_llbitmap_attrs,
};
+static const struct attribute_group *md_llbitmap_groups[] = {
+ &md_llbitmap_group,
+ NULL,
+};
+
static struct bitmap_operations llbitmap_ops = {
.head = {
.type = MD_BITMAP,
@@ -1774,7 +1779,7 @@ static struct bitmap_operations llbitmap_ops = {
.dirty_bits = llbitmap_dirty_bits,
.write_all = llbitmap_write_all,
- .group = &md_llbitmap_group,
+ .groups = md_llbitmap_groups,
};
int md_llbitmap_init(void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5fb5ae8368ba..8b568eee8743 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -396,27 +396,19 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
if (is_suspended(mddev, bio)) {
- DEFINE_WAIT(__wait);
/* Bail out if REQ_NOWAIT is set for the bio */
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
return true;
}
- for (;;) {
- prepare_to_wait(&mddev->sb_wait, &__wait,
- TASK_UNINTERRUPTIBLE);
- if (!is_suspended(mddev, bio))
- break;
- schedule();
- }
- finish_wait(&mddev->sb_wait, &__wait);
+ wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
if (!percpu_ref_tryget_live(&mddev->active_io))
goto check_suspended;
if (!mddev->pers->make_request(mddev, bio)) {
percpu_ref_put(&mddev->active_io);
- if (!mddev->gendisk && mddev->pers->prepare_suspend)
+ if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
return false;
goto check_suspended;
}
@@ -687,13 +679,38 @@ static void active_io_release(struct percpu_ref *ref)
static void no_op(struct percpu_ref *r) {}
-static bool mddev_set_bitmap_ops(struct mddev *mddev)
+static void md_bitmap_sysfs_add(struct mddev *mddev)
+{
+ if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups))
+ pr_warn("md: cannot register extra bitmap attributes for %s\n",
+ mdname(mddev));
+ else
+ /*
+ * Inform user with KOBJ_CHANGE about new bitmap
+ * attributes.
+ */
+ kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
+}
+
+static void md_bitmap_sysfs_del(struct mddev *mddev)
+{
+ int nr_groups = 0;
+
+ for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++)
+ ;
+
+ while (--nr_groups >= 1)
+ sysfs_unmerge_group(&mddev->kobj,
+ mddev->bitmap_ops->groups[nr_groups]);
+ sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]);
+}
+
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
- struct bitmap_operations *old = mddev->bitmap_ops;
struct md_submodule_head *head;
- if (mddev->bitmap_id == ID_BITMAP_NONE ||
- (old && old->head.id == mddev->bitmap_id))
+ if (mddev->bitmap_ops &&
+ mddev->bitmap_ops->head.id == mddev->bitmap_id)
return true;
xa_lock(&md_submodule);
@@ -711,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
mddev->bitmap_ops = (void *)head;
xa_unlock(&md_submodule);
-
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
- if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
- pr_warn("md: cannot register extra bitmap attributes for %s\n",
- mdname(mddev));
- else
- /*
- * Inform user with KOBJ_CHANGE about new bitmap
- * attributes.
- */
- kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
- }
return true;
err:
@@ -730,15 +735,6 @@ err:
return false;
}
-static void mddev_clear_bitmap_ops(struct mddev *mddev)
-{
- if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
- mddev->bitmap_ops->group)
- sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
-
- mddev->bitmap_ops = NULL;
-}
-
int mddev_init(struct mddev *mddev)
{
int err = 0;
@@ -4279,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char *page)
xa_lock(&md_submodule);
xa_for_each(&md_submodule, i, head) {
- if (head->type != MD_BITMAP)
+ if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE)
continue;
if (mddev->bitmap_id == head->id)
@@ -6059,10 +6055,7 @@ static struct attribute *md_default_attrs[] = {
&md_logical_block_size.attr,
NULL,
};
-
-static const struct attribute_group md_default_group = {
- .attrs = md_default_attrs,
-};
+ATTRIBUTE_GROUPS(md_default);
static struct attribute *md_redundancy_attrs[] = {
&md_scan_mode.attr,
@@ -6087,11 +6080,6 @@ static const struct attribute_group md_redundancy_group = {
.attrs = md_redundancy_attrs,
};
-static const struct attribute_group *md_attr_groups[] = {
- &md_default_group,
- NULL,
-};
-
static ssize_t
md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
@@ -6174,7 +6162,7 @@ static const struct sysfs_ops md_sysfs_ops = {
static const struct kobj_type md_ktype = {
.release = md_kobj_release,
.sysfs_ops = &md_sysfs_ops,
- .default_groups = md_attr_groups,
+ .default_groups = md_default_groups,
};
int mdp_major = 0;
@@ -6539,7 +6527,7 @@ out:
return id;
}
-static int md_bitmap_create(struct mddev *mddev)
+int md_bitmap_create_nosysfs(struct mddev *mddev)
{
enum md_submodule_id orig_id = mddev->bitmap_id;
enum md_submodule_id sb_id;
@@ -6548,8 +6536,10 @@ static int md_bitmap_create(struct mddev *mddev)
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
- if (!mddev_set_bitmap_ops(mddev))
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
+ mddev->bitmap_id = orig_id;
return -ENOENT;
+ }
err = mddev->bitmap_ops->create(mddev);
if (!err)
@@ -6560,37 +6550,72 @@ static int md_bitmap_create(struct mddev *mddev)
* doesn't match, and mdadm is not the latest version to set
* bitmap_type, set bitmap_ops based on the disk version.
*/
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
sb_id = md_bitmap_get_id_from_sb(mddev);
- if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
+ if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) {
+ mddev->bitmap_id = orig_id;
return err;
+ }
pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
mdname(mddev), orig_id, sb_id);
mddev->bitmap_id = sb_id;
- if (!mddev_set_bitmap_ops(mddev)) {
+ if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
mddev->bitmap_id = orig_id;
return -ENOENT;
}
err = mddev->bitmap_ops->create(mddev);
if (err) {
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
mddev->bitmap_id = orig_id;
}
return err;
}
-static void md_bitmap_destroy(struct mddev *mddev)
+static int md_bitmap_create(struct mddev *mddev)
+{
+ int err;
+
+ err = md_bitmap_create_nosysfs(mddev);
+ if (err)
+ return err;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_add(mddev);
+
+ return 0;
+}
+
+void md_bitmap_destroy_nosysfs(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
mddev->bitmap_ops->destroy(mddev);
- mddev_clear_bitmap_ops(mddev);
+ mddev->bitmap_ops = NULL;
+}
+
+static void md_bitmap_destroy(struct mddev *mddev)
+{
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
+ mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_del(mddev);
+
+ md_bitmap_destroy_nosysfs(mddev);
+}
+
+static void md_bitmap_set_none(struct mddev *mddev)
+{
+ mddev->bitmap_id = ID_BITMAP_NONE;
+ if (!mddev_set_bitmap_ops_nosysfs(mddev))
+ return;
+
+ if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
+ md_bitmap_sysfs_add(mddev);
}
int md_run(struct mddev *mddev)
@@ -6713,7 +6738,7 @@ int md_run(struct mddev *mddev)
}
/* dm-raid expect sync_thread to be frozen until resume */
- if (mddev->gendisk)
+ if (!mddev_is_dm(mddev))
mddev->recovery = 0;
/* may be over-ridden by personality */
@@ -6802,6 +6827,10 @@ int md_run(struct mddev *mddev)
if (mddev->sb_flags)
md_update_sb(mddev, 0);
+ if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
+ !mddev->bitmap_info.offset)
+ md_bitmap_set_none(mddev);
+
md_new_event();
return 0;
@@ -7747,7 +7776,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
{
int err = 0;
- if (!md_bitmap_registered(mddev))
+ if (!md_bitmap_registered(mddev) ||
+ mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (mddev->pers) {
@@ -7812,10 +7842,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (err) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
fd = -1;
}
} else if (fd < 0) {
md_bitmap_destroy(mddev);
+ md_bitmap_set_none(mddev);
}
}
@@ -8122,12 +8154,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->bitmap_info.default_offset;
mddev->bitmap_info.space =
mddev->bitmap_info.default_space;
+ mddev->bitmap_id = ID_BITMAP;
rv = md_bitmap_create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
- if (rv)
+ if (rv) {
md_bitmap_destroy(mddev);
+ mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
+ }
} else {
struct md_bitmap_stats stats;
@@ -8155,6 +8191,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
}
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
+ md_bitmap_set_none(mddev);
}
}
md_update_sb(mddev, 1);
@@ -9341,9 +9378,11 @@ static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone)
static void md_end_clone_io(struct bio *bio)
{
- struct md_io_clone *md_io_clone = bio->bi_private;
+ struct md_io_clone *md_io_clone = container_of(bio, struct md_io_clone,
+ bio_clone);
struct bio *orig_bio = md_io_clone->orig_bio;
struct mddev *mddev = md_io_clone->mddev;
+ struct completion *reshape_completion = bio->bi_private;
if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false))
md_bitmap_end(mddev, md_io_clone);
@@ -9355,7 +9394,10 @@ static void md_end_clone_io(struct bio *bio)
bio_end_io_acct(orig_bio, md_io_clone->start_time);
bio_put(bio);
- bio_endio(orig_bio);
+ if (unlikely(reshape_completion))
+ complete(reshape_completion);
+ else
+ bio_endio(orig_bio);
percpu_ref_put(&mddev->active_io);
}
@@ -9380,7 +9422,7 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio)
}
clone->bi_end_io = md_end_clone_io;
- clone->bi_private = md_io_clone;
+ clone->bi_private = NULL;
*bio = clone;
}
@@ -9391,26 +9433,6 @@ void md_account_bio(struct mddev *mddev, struct bio **bio)
}
EXPORT_SYMBOL_GPL(md_account_bio);
-void md_free_cloned_bio(struct bio *bio)
-{
- struct md_io_clone *md_io_clone = bio->bi_private;
- struct bio *orig_bio = md_io_clone->orig_bio;
- struct mddev *mddev = md_io_clone->mddev;
-
- if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false))
- md_bitmap_end(mddev, md_io_clone);
-
- if (bio->bi_status && !orig_bio->bi_status)
- orig_bio->bi_status = bio->bi_status;
-
- if (md_io_clone->start_time)
- bio_end_io_acct(orig_bio, md_io_clone->start_time);
-
- bio_put(bio);
- percpu_ref_put(&mddev->active_io);
-}
-EXPORT_SYMBOL_GPL(md_free_cloned_bio);
-
/* md_allow_write(mddev)
* Calling this ensures that the array is marked 'active' so that writes
* may proceed without blocking. It is important to call this before
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d6f5482e2479..52c378086046 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -920,7 +920,6 @@ extern void md_finish_reshape(struct mddev *mddev);
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size);
void md_account_bio(struct mddev *mddev, struct bio **bio);
-void md_free_cloned_bio(struct bio *bio);
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev,
@@ -935,6 +934,9 @@ extern void md_allow_write(struct mddev *mddev);
extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
+bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev);
+int md_bitmap_create_nosysfs(struct mddev *mddev);
+void md_bitmap_destroy_nosysfs(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
@@ -1015,7 +1017,7 @@ static inline int mddev_suspend_and_lock(struct mddev *mddev)
static inline void mddev_suspend_and_lock_nointr(struct mddev *mddev)
{
mddev_suspend(mddev, false);
- mutex_lock(&mddev->reconfig_mutex);
+ mddev_lock_nointr(mddev);
}
static inline void mddev_unlock_and_resume(struct mddev *mddev)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index c33099925f23..56a56a4da4f8 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,
* bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is
* submitted to the underlying disks, hence don't record badblocks or retry
* in this case.
+ *
+ * BLK_STS_INVAL means the bio was not valid for the underlying device. This
+ * is a user error, not a device failure, so retrying or recording bad blocks
+ * would be wrong.
*/
static inline bool raid1_should_handle_error(struct bio *bio)
{
- return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT));
+ return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) &&
+ bio->bi_status != BLK_STS_INVAL;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index ba91f7e61920..64d970e2ef50 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1510,21 +1510,14 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mddev->cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector, bio_end_sector(bio))) {
- DEFINE_WAIT(w);
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
return;
}
- for (;;) {
- prepare_to_wait(&conf->wait_barrier,
- &w, TASK_IDLE);
- if (!mddev->cluster_ops->area_resyncing(mddev, WRITE,
- bio->bi_iter.bi_sector,
- bio_end_sector(bio)))
- break;
- schedule();
- }
- finish_wait(&conf->wait_barrier, &w);
+ wait_event_idle(conf->wait_barrier,
+ !mddev->cluster_ops->area_resyncing(mddev, WRITE,
+ bio->bi_iter.bi_sector,
+ bio_end_sector(bio)));
}
/*
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 4901ebe45c87..39085e7dd6d2 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3791,6 +3791,8 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
nc = layout & 255;
fc = (layout >> 8) & 255;
fo = layout & (1<<16);
+ if (!nc || !fc)
+ return -1;
geo->raid_disks = disks;
geo->near_copies = nc;
geo->far_copies = fc;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 6e79829c5acb..0d76e82f4506 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6217,7 +6217,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
mempool_free(ctx, conf->ctx_pool);
if (res == STRIPE_WAIT_RESHAPE) {
- md_free_cloned_bio(bi);
+ DECLARE_COMPLETION_ONSTACK(done);
+ WRITE_ONCE(bi->bi_private, &done);
+
+ bio_endio(bi);
+
+ wait_for_completion(&done);
return false;
}