Skip to content

Commit 9d37fe3

Browse files
Li Nangregkh
authored andcommitted
md: init bioset in mddev_init
[ Upstream commit 381a3ce ] IO operations may be needed before md_run(), such as updating metadata after writing sysfs. Without bioset, this triggers a NULL pointer dereference as below: BUG: kernel NULL pointer dereference, address: 0000000000000020 Call Trace: md_update_sb+0x658/0xe00 new_level_store+0xc5/0x120 md_attr_store+0xc9/0x1e0 sysfs_kf_write+0x6f/0xa0 kernfs_fop_write_iter+0x141/0x2a0 vfs_write+0x1fc/0x5a0 ksys_write+0x79/0x180 __x64_sys_write+0x1d/0x30 x64_sys_call+0x2818/0x2880 do_syscall_64+0xa9/0x580 entry_SYSCALL_64_after_hwframe+0x4b/0x53 Reproducer ``` mdadm -CR /dev/md0 -l1 -n2 /dev/sd[cd] echo inactive > /sys/block/md0/md/array_state echo 10 > /sys/block/md0/md/new_level ``` mddev_init() can only be called once per mddev, no need to test if bioset has been initialized anymore. Link: https://lore.kernel.org/linux-raid/20251103125757.1405796-3-linan666@huaweicloud.com Fixes: d981ed8 ("md: Add new_level sysfs interface") Signed-off-by: Li Nan <linan122@huawei.com> Reviewed-by: Xiao Ni <xni@redhat.com> Signed-off-by: Yu Kuai <yukuai@fnnas.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent a66e5f5 commit 9d37fe3

File tree

1 file changed

+33
-36
lines changed

1 file changed

+33
-36
lines changed

drivers/md/md.c

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,8 @@ static void mddev_clear_bitmap_ops(struct mddev *mddev)
730730

731731
int mddev_init(struct mddev *mddev)
732732
{
733+
int err = 0;
734+
733735
if (!IS_ENABLED(CONFIG_MD_BITMAP))
734736
mddev->bitmap_id = ID_BITMAP_NONE;
735737
else
@@ -741,10 +743,23 @@ int mddev_init(struct mddev *mddev)
741743

742744
if (percpu_ref_init(&mddev->writes_pending, no_op,
743745
PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
744-
percpu_ref_exit(&mddev->active_io);
745-
return -ENOMEM;
746+
err = -ENOMEM;
747+
goto exit_acitve_io;
746748
}
747749

750+
err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
751+
if (err)
752+
goto exit_writes_pending;
753+
754+
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
755+
if (err)
756+
goto exit_bio_set;
757+
758+
err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
759+
offsetof(struct md_io_clone, bio_clone), 0);
760+
if (err)
761+
goto exit_sync_set;
762+
748763
/* We want to start with the refcount at zero */
749764
percpu_ref_put(&mddev->writes_pending);
750765

@@ -773,11 +788,24 @@ int mddev_init(struct mddev *mddev)
773788
INIT_WORK(&mddev->del_work, mddev_delayed_delete);
774789

775790
return 0;
791+
792+
exit_sync_set:
793+
bioset_exit(&mddev->sync_set);
794+
exit_bio_set:
795+
bioset_exit(&mddev->bio_set);
796+
exit_writes_pending:
797+
percpu_ref_exit(&mddev->writes_pending);
798+
exit_acitve_io:
799+
percpu_ref_exit(&mddev->active_io);
800+
return err;
776801
}
777802
EXPORT_SYMBOL_GPL(mddev_init);
778803

779804
void mddev_destroy(struct mddev *mddev)
780805
{
806+
bioset_exit(&mddev->bio_set);
807+
bioset_exit(&mddev->sync_set);
808+
bioset_exit(&mddev->io_clone_set);
781809
percpu_ref_exit(&mddev->active_io);
782810
percpu_ref_exit(&mddev->writes_pending);
783811
}
@@ -6387,29 +6415,9 @@ int md_run(struct mddev *mddev)
63876415
nowait = nowait && bdev_nowait(rdev->bdev);
63886416
}
63896417

6390-
if (!bioset_initialized(&mddev->bio_set)) {
6391-
err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
6392-
if (err)
6393-
return err;
6394-
}
6395-
if (!bioset_initialized(&mddev->sync_set)) {
6396-
err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
6397-
if (err)
6398-
goto exit_bio_set;
6399-
}
6400-
6401-
if (!bioset_initialized(&mddev->io_clone_set)) {
6402-
err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE,
6403-
offsetof(struct md_io_clone, bio_clone), 0);
6404-
if (err)
6405-
goto exit_sync_set;
6406-
}
6407-
64086418
pers = get_pers(mddev->level, mddev->clevel);
6409-
if (!pers) {
6410-
err = -EINVAL;
6411-
goto abort;
6412-
}
6419+
if (!pers)
6420+
return -EINVAL;
64136421
if (mddev->level != pers->head.id) {
64146422
mddev->level = pers->head.id;
64156423
mddev->new_level = pers->head.id;
@@ -6420,8 +6428,7 @@ int md_run(struct mddev *mddev)
64206428
pers->start_reshape == NULL) {
64216429
/* This personality cannot handle reshaping... */
64226430
put_pers(pers);
6423-
err = -EINVAL;
6424-
goto abort;
6431+
return -EINVAL;
64256432
}
64266433

64276434
if (pers->sync_request) {
@@ -6548,12 +6555,6 @@ int md_run(struct mddev *mddev)
65486555
mddev->private = NULL;
65496556
put_pers(pers);
65506557
md_bitmap_destroy(mddev);
6551-
abort:
6552-
bioset_exit(&mddev->io_clone_set);
6553-
exit_sync_set:
6554-
bioset_exit(&mddev->sync_set);
6555-
exit_bio_set:
6556-
bioset_exit(&mddev->bio_set);
65576558
return err;
65586559
}
65596560
EXPORT_SYMBOL_GPL(md_run);
@@ -6778,10 +6779,6 @@ static void __md_stop(struct mddev *mddev)
67786779
mddev->private = NULL;
67796780
put_pers(pers);
67806781
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
6781-
6782-
bioset_exit(&mddev->bio_set);
6783-
bioset_exit(&mddev->sync_set);
6784-
bioset_exit(&mddev->io_clone_set);
67856782
}
67866783

67876784
void md_stop(struct mddev *mddev)

0 commit comments

Comments
 (0)