Skip to content

Commit 7deac11

Browse files
YuKuai-huaweiliu-song-6
authored andcommitted
md: don't dereference mddev after export_rdev()
Except for initial reference, mddev->kobject is referenced by rdev->kobject, and if the last rdev is freed, there is no guarantee that mddev is still valid. Hence mddev should not be used anymore after export_rdev(). This problem can be triggered by following test for mdadm at very low rate: New file: mdadm/tests/23rdev-lifetime devname=${dev0##*/} devt=`cat /sys/block/$devname/dev` pid="" runtime=2 clean_up_test() { pill -9 $pid echo clear > /sys/block/md0/md/array_state } trap 'clean_up_test' EXIT add_by_sysfs() { while true; do echo $devt > /sys/block/md0/md/new_dev done } remove_by_sysfs(){ while true; do echo remove > /sys/block/md0/md/dev-${devname}/state done } echo md0 > /sys/module/md_mod/parameters/new_array || die "create md0 failed" add_by_sysfs & pid="$pid $!" remove_by_sysfs & pid="$pid $!" sleep $runtime exit 0 Test cmd: ./test --save-logs --logdir=/tmp/ --keep-going --dev=loop --tests=23rdev-lifetime Test result: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6bcb: 0000 [#4] PREEMPT SMP CPU: 0 PID: 1292 Comm: test Tainted: G D W 6.5.0-rc2-00121-g01e55c376936 #562 RIP: 0010:md_wakeup_thread+0x9e/0x320 [md_mod] Call Trace: <TASK> mddev_unlock+0x1b6/0x310 [md_mod] rdev_attr_store+0xec/0x190 [md_mod] sysfs_kf_write+0x52/0x70 kernfs_fop_write_iter+0x19a/0x2a0 vfs_write+0x3b5/0x770 ksys_write+0x74/0x150 __x64_sys_write+0x22/0x30 do_syscall_64+0x40/0x90 entry_SYSCALL_64_after_hwframe+0x63/0xcd Fix this problem by don't dereference mddev after export_rdev(). Fixes: 3ce94ce ("md: fix duplicate filename for rdev") Signed-off-by: Yu Kuai <[email protected]> Signed-off-by: Song Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 4b9c2ed commit 7deac11

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

drivers/md/md.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,14 +798,14 @@ void mddev_unlock(struct mddev *mddev)
798798
} else
799799
mutex_unlock(&mddev->reconfig_mutex);
800800

801+
md_wakeup_thread(mddev->thread);
802+
wake_up(&mddev->sb_wait);
803+
801804
list_for_each_entry_safe(rdev, tmp, &delete, same_set) {
802805
list_del_init(&rdev->same_set);
803806
kobject_del(&rdev->kobj);
804807
export_rdev(rdev, mddev);
805808
}
806-
807-
md_wakeup_thread(mddev->thread);
808-
wake_up(&mddev->sb_wait);
809809
}
810810
EXPORT_SYMBOL_GPL(mddev_unlock);
811811

0 commit comments

Comments
 (0)