Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

md: init bioset in mddev_init

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: d981ed841930 ("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>

authored by

Li Nan and committed by
Yu Kuai
381a3ce1 0ce112d9

+33 -36
+33 -36
drivers/md/md.c
··· 730 730 731 731 int mddev_init(struct mddev *mddev) 732 732 { 733 + int err = 0; 734 + 733 735 if (!IS_ENABLED(CONFIG_MD_BITMAP)) 734 736 mddev->bitmap_id = ID_BITMAP_NONE; 735 737 else ··· 743 741 744 742 if (percpu_ref_init(&mddev->writes_pending, no_op, 745 743 PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) { 746 - percpu_ref_exit(&mddev->active_io); 747 - return -ENOMEM; 744 + err = -ENOMEM; 745 + goto exit_acitve_io; 748 746 } 747 + 748 + err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); 749 + if (err) 750 + goto exit_writes_pending; 751 + 752 + err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); 753 + if (err) 754 + goto exit_bio_set; 755 + 756 + err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE, 757 + offsetof(struct md_io_clone, bio_clone), 0); 758 + if (err) 759 + goto exit_sync_set; 749 760 750 761 /* We want to start with the refcount at zero */ 751 762 percpu_ref_put(&mddev->writes_pending); ··· 788 773 INIT_WORK(&mddev->del_work, mddev_delayed_delete); 789 774 790 775 return 0; 776 + 777 + exit_sync_set: 778 + bioset_exit(&mddev->sync_set); 779 + exit_bio_set: 780 + bioset_exit(&mddev->bio_set); 781 + exit_writes_pending: 782 + percpu_ref_exit(&mddev->writes_pending); 783 + exit_acitve_io: 784 + percpu_ref_exit(&mddev->active_io); 785 + return err; 791 786 } 792 787 EXPORT_SYMBOL_GPL(mddev_init); 793 788 794 789 void mddev_destroy(struct mddev *mddev) 795 790 { 791 + bioset_exit(&mddev->bio_set); 792 + bioset_exit(&mddev->sync_set); 793 + bioset_exit(&mddev->io_clone_set); 796 794 percpu_ref_exit(&mddev->active_io); 797 795 percpu_ref_exit(&mddev->writes_pending); 798 796 } ··· 6422 6394 nowait = nowait && bdev_nowait(rdev->bdev); 6423 6395 } 6424 6396 6425 - if (!bioset_initialized(&mddev->bio_set)) { 6426 - err = bioset_init(&mddev->bio_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); 6427 - if (err) 6428 - return err; 6429 - } 6430 - if (!bioset_initialized(&mddev->sync_set)) { 6431 - err = bioset_init(&mddev->sync_set, BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS); 6432 - if (err) 6433 - goto exit_bio_set; 6434 - } 6435 - 6436 - if (!bioset_initialized(&mddev->io_clone_set)) { 6437 - err = bioset_init(&mddev->io_clone_set, BIO_POOL_SIZE, 6438 - offsetof(struct md_io_clone, bio_clone), 0); 6439 - if (err) 6440 - goto exit_sync_set; 6441 - } 6442 - 6443 6397 pers = get_pers(mddev->level, mddev->clevel); 6444 - if (!pers) { 6445 - err = -EINVAL; 6446 - goto abort; 6447 - } 6398 + if (!pers) 6399 + return -EINVAL; 6448 6400 if (mddev->level != pers->head.id) { 6449 6401 mddev->level = pers->head.id; 6450 6402 mddev->new_level = pers->head.id; ··· 6435 6427 pers->start_reshape == NULL) { 6436 6428 /* This personality cannot handle reshaping... */ 6437 6429 put_pers(pers); 6438 - err = -EINVAL; 6439 - goto abort; 6430 + return -EINVAL; 6440 6431 } 6441 6432 6442 6433 if (pers->sync_request) { ··· 6562 6555 mddev->private = NULL; 6563 6556 put_pers(pers); 6564 6557 md_bitmap_destroy(mddev); 6565 - abort: 6566 - bioset_exit(&mddev->io_clone_set); 6567 - exit_sync_set: 6568 - bioset_exit(&mddev->sync_set); 6569 - exit_bio_set: 6570 - bioset_exit(&mddev->bio_set); 6571 6558 return err; 6572 6559 } 6573 6560 EXPORT_SYMBOL_GPL(md_run); ··· 6786 6785 mddev->private = NULL; 6787 6786 put_pers(pers); 6788 6787 clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); 6789 - 6790 - bioset_exit(&mddev->bio_set); 6791 - bioset_exit(&mddev->sync_set); 6792 - bioset_exit(&mddev->io_clone_set); 6793 6788 } 6794 6789 6795 6790 void md_stop(struct mddev *mddev)