aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-04-09 00:33:51 -0400
committerNeilBrown <neilb@suse.de>2014-04-09 00:42:34 -0400
commite2f23b606b94f28a8febd5aa715df697d80b018e (patch)
treed9f21bd649683bedbdadb301b1533c09e13591ba
parentda1aab3dca9aa88ae34ca392470b8943159e25fe (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.c16
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
7168static int md_unloading;
7168static unsigned int mdstat_poll(struct file *filp, poll_table *wait) 7169static 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;