diff options
author | NeilBrown <neilb@suse.de> | 2014-04-09 00:33:51 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2014-04-09 00:42:34 -0400 |
commit | e2f23b606b94f28a8febd5aa715df697d80b018e (patch) | |
tree | d9f21bd649683bedbdadb301b1533c09e13591ba | |
parent | da1aab3dca9aa88ae34ca392470b8943159e25fe (diff) |
md: avoid oops on unload if some process is in poll or select.
If md-mod is unloaded while some process is in poll() or select(),
then that process maintains a pointer to md_event_waiters, and when
the try to unlink from that list, they will oops.
The procfs infrastructure ensures that ->poll won't be called after
remove_proc_entry, but doesn't provide a wait_queue_head for us to
use, and the waitqueue code doesn't provide a way to remove all
listeners from a waitqueue.
So we need to:
1/ make sure no further references to md_event_waiters are taken (by
setting md_unloading)
2/ wake up all processes currently waiting, and
3/ wait until all those processes have disconnected from our
wait_queue_head.
Reported-by: "majianpeng" <majianpeng@gmail.com>
Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r-- | drivers/md/md.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 3fa2fc0a5dd2..8fda38d23e38 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -7165,11 +7165,14 @@ static int md_seq_open(struct inode *inode, struct file *file) | |||
7165 | return error; | 7165 | return error; |
7166 | } | 7166 | } |
7167 | 7167 | ||
7168 | static int md_unloading; | ||
7168 | static unsigned int mdstat_poll(struct file *filp, poll_table *wait) | 7169 | static unsigned int mdstat_poll(struct file *filp, poll_table *wait) |
7169 | { | 7170 | { |
7170 | struct seq_file *seq = filp->private_data; | 7171 | struct seq_file *seq = filp->private_data; |
7171 | int mask; | 7172 | int mask; |
7172 | 7173 | ||
7174 | if (md_unloading) | ||
7175 | return POLLIN|POLLRDNORM|POLLERR|POLLPRI;; | ||
7173 | poll_wait(filp, &md_event_waiters, wait); | 7176 | poll_wait(filp, &md_event_waiters, wait); |
7174 | 7177 | ||
7175 | /* always allow read */ | 7178 | /* always allow read */ |
@@ -8655,6 +8658,7 @@ static __exit void md_exit(void) | |||
8655 | { | 8658 | { |
8656 | struct mddev *mddev; | 8659 | struct mddev *mddev; |
8657 | struct list_head *tmp; | 8660 | struct list_head *tmp; |
8661 | int delay = 1; | ||
8658 | 8662 | ||
8659 | blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS); | 8663 | blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS); |
8660 | blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS); | 8664 | blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS); |
@@ -8663,7 +8667,19 @@ static __exit void md_exit(void) | |||
8663 | unregister_blkdev(mdp_major, "mdp"); | 8667 | unregister_blkdev(mdp_major, "mdp"); |
8664 | unregister_reboot_notifier(&md_notifier); | 8668 | unregister_reboot_notifier(&md_notifier); |
8665 | unregister_sysctl_table(raid_table_header); | 8669 | unregister_sysctl_table(raid_table_header); |
8670 | |||
8671 | /* We cannot unload the modules while some process is | ||
8672 | * waiting for us in select() or poll() - wake them up | ||
8673 | */ | ||
8674 | md_unloading = 1; | ||
8675 | while (waitqueue_active(&md_event_waiters)) { | ||
8676 | /* not safe to leave yet */ | ||
8677 | wake_up(&md_event_waiters); | ||
8678 | msleep(delay); | ||
8679 | delay += delay; | ||
8680 | } | ||
8666 | remove_proc_entry("mdstat", NULL); | 8681 | remove_proc_entry("mdstat", NULL); |
8682 | |||
8667 | for_each_mddev(mddev, tmp) { | 8683 | for_each_mddev(mddev, tmp) { |
8668 | export_array(mddev); | 8684 | export_array(mddev); |
8669 | mddev->hold_active = 0; | 8685 | mddev->hold_active = 0; |