diff options
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 81 |
1 files changed, 76 insertions, 5 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 1364a1c97e6f..6101879a730f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/devfs_fs_kernel.h> | 42 | #include <linux/devfs_fs_kernel.h> |
43 | #include <linux/buffer_head.h> /* for invalidate_bdev */ | 43 | #include <linux/buffer_head.h> /* for invalidate_bdev */ |
44 | #include <linux/suspend.h> | 44 | #include <linux/suspend.h> |
45 | #include <linux/poll.h> | ||
45 | 46 | ||
46 | #include <linux/init.h> | 47 | #include <linux/init.h> |
47 | 48 | ||
@@ -134,6 +135,24 @@ static struct block_device_operations md_fops; | |||
134 | static int start_readonly; | 135 | static int start_readonly; |
135 | 136 | ||
136 | /* | 137 | /* |
138 | * We have a system wide 'event count' that is incremented | ||
139 | * on any 'interesting' event, and readers of /proc/mdstat | ||
140 | * can use 'poll' or 'select' to find out when the event | ||
141 | * count increases. | ||
142 | * | ||
143 | * Events are: | ||
144 | * start array, stop array, error, add device, remove device, | ||
145 | * start build, activate spare | ||
146 | */ | ||
147 | DECLARE_WAIT_QUEUE_HEAD(md_event_waiters); | ||
148 | static atomic_t md_event_count; | ||
149 | void md_new_event(mddev_t *mddev) | ||
150 | { | ||
151 | atomic_inc(&md_event_count); | ||
152 | wake_up(&md_event_waiters); | ||
153 | } | ||
154 | |||
155 | /* | ||
137 | * Enables to iterate over all existing md arrays | 156 | * Enables to iterate over all existing md arrays |
138 | * all_mddevs_lock protects this list. | 157 | * all_mddevs_lock protects this list. |
139 | */ | 158 | */ |
@@ -2111,6 +2130,7 @@ static int do_md_run(mddev_t * mddev) | |||
2111 | mddev->queue->make_request_fn = mddev->pers->make_request; | 2130 | mddev->queue->make_request_fn = mddev->pers->make_request; |
2112 | 2131 | ||
2113 | mddev->changed = 1; | 2132 | mddev->changed = 1; |
2133 | md_new_event(mddev); | ||
2114 | return 0; | 2134 | return 0; |
2115 | } | 2135 | } |
2116 | 2136 | ||
@@ -2238,6 +2258,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2238 | printk(KERN_INFO "md: %s switched to read-only mode.\n", | 2258 | printk(KERN_INFO "md: %s switched to read-only mode.\n", |
2239 | mdname(mddev)); | 2259 | mdname(mddev)); |
2240 | err = 0; | 2260 | err = 0; |
2261 | md_new_event(mddev); | ||
2241 | out: | 2262 | out: |
2242 | return err; | 2263 | return err; |
2243 | } | 2264 | } |
@@ -2712,6 +2733,7 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev) | |||
2712 | 2733 | ||
2713 | kick_rdev_from_array(rdev); | 2734 | kick_rdev_from_array(rdev); |
2714 | md_update_sb(mddev); | 2735 | md_update_sb(mddev); |
2736 | md_new_event(mddev); | ||
2715 | 2737 | ||
2716 | return 0; | 2738 | return 0; |
2717 | busy: | 2739 | busy: |
@@ -2802,7 +2824,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) | |||
2802 | */ | 2824 | */ |
2803 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 2825 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
2804 | md_wakeup_thread(mddev->thread); | 2826 | md_wakeup_thread(mddev->thread); |
2805 | 2827 | md_new_event(mddev); | |
2806 | return 0; | 2828 | return 0; |
2807 | 2829 | ||
2808 | abort_unbind_export: | 2830 | abort_unbind_export: |
@@ -3531,6 +3553,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
3531 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 3553 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
3532 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 3554 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
3533 | md_wakeup_thread(mddev->thread); | 3555 | md_wakeup_thread(mddev->thread); |
3556 | md_new_event(mddev); | ||
3534 | } | 3557 | } |
3535 | 3558 | ||
3536 | /* seq_file implementation /proc/mdstat */ | 3559 | /* seq_file implementation /proc/mdstat */ |
@@ -3671,12 +3694,17 @@ static void md_seq_stop(struct seq_file *seq, void *v) | |||
3671 | mddev_put(mddev); | 3694 | mddev_put(mddev); |
3672 | } | 3695 | } |
3673 | 3696 | ||
3697 | struct mdstat_info { | ||
3698 | int event; | ||
3699 | }; | ||
3700 | |||
3674 | static int md_seq_show(struct seq_file *seq, void *v) | 3701 | static int md_seq_show(struct seq_file *seq, void *v) |
3675 | { | 3702 | { |
3676 | mddev_t *mddev = v; | 3703 | mddev_t *mddev = v; |
3677 | sector_t size; | 3704 | sector_t size; |
3678 | struct list_head *tmp2; | 3705 | struct list_head *tmp2; |
3679 | mdk_rdev_t *rdev; | 3706 | mdk_rdev_t *rdev; |
3707 | struct mdstat_info *mi = seq->private; | ||
3680 | int i; | 3708 | int i; |
3681 | struct bitmap *bitmap; | 3709 | struct bitmap *bitmap; |
3682 | 3710 | ||
@@ -3689,6 +3717,7 @@ static int md_seq_show(struct seq_file *seq, void *v) | |||
3689 | 3717 | ||
3690 | spin_unlock(&pers_lock); | 3718 | spin_unlock(&pers_lock); |
3691 | seq_printf(seq, "\n"); | 3719 | seq_printf(seq, "\n"); |
3720 | mi->event = atomic_read(&md_event_count); | ||
3692 | return 0; | 3721 | return 0; |
3693 | } | 3722 | } |
3694 | if (v == (void*)2) { | 3723 | if (v == (void*)2) { |
@@ -3797,16 +3826,52 @@ static struct seq_operations md_seq_ops = { | |||
3797 | static int md_seq_open(struct inode *inode, struct file *file) | 3826 | static int md_seq_open(struct inode *inode, struct file *file) |
3798 | { | 3827 | { |
3799 | int error; | 3828 | int error; |
3829 | struct mdstat_info *mi = kmalloc(sizeof(*mi), GFP_KERNEL); | ||
3830 | if (mi == NULL) | ||
3831 | return -ENOMEM; | ||
3800 | 3832 | ||
3801 | error = seq_open(file, &md_seq_ops); | 3833 | error = seq_open(file, &md_seq_ops); |
3834 | if (error) | ||
3835 | kfree(mi); | ||
3836 | else { | ||
3837 | struct seq_file *p = file->private_data; | ||
3838 | p->private = mi; | ||
3839 | mi->event = atomic_read(&md_event_count); | ||
3840 | } | ||
3802 | return error; | 3841 | return error; |
3803 | } | 3842 | } |
3804 | 3843 | ||
3844 | static int md_seq_release(struct inode *inode, struct file *file) | ||
3845 | { | ||
3846 | struct seq_file *m = file->private_data; | ||
3847 | struct mdstat_info *mi = m->private; | ||
3848 | m->private = NULL; | ||
3849 | kfree(mi); | ||
3850 | return seq_release(inode, file); | ||
3851 | } | ||
3852 | |||
3853 | static unsigned int mdstat_poll(struct file *filp, poll_table *wait) | ||
3854 | { | ||
3855 | struct seq_file *m = filp->private_data; | ||
3856 | struct mdstat_info *mi = m->private; | ||
3857 | int mask; | ||
3858 | |||
3859 | poll_wait(filp, &md_event_waiters, wait); | ||
3860 | |||
3861 | /* always allow read */ | ||
3862 | mask = POLLIN | POLLRDNORM; | ||
3863 | |||
3864 | if (mi->event != atomic_read(&md_event_count)) | ||
3865 | mask |= POLLERR | POLLPRI; | ||
3866 | return mask; | ||
3867 | } | ||
3868 | |||
3805 | static struct file_operations md_seq_fops = { | 3869 | static struct file_operations md_seq_fops = { |
3806 | .open = md_seq_open, | 3870 | .open = md_seq_open, |
3807 | .read = seq_read, | 3871 | .read = seq_read, |
3808 | .llseek = seq_lseek, | 3872 | .llseek = seq_lseek, |
3809 | .release = seq_release, | 3873 | .release = md_seq_release, |
3874 | .poll = mdstat_poll, | ||
3810 | }; | 3875 | }; |
3811 | 3876 | ||
3812 | int register_md_personality(int pnum, mdk_personality_t *p) | 3877 | int register_md_personality(int pnum, mdk_personality_t *p) |
@@ -4076,7 +4141,11 @@ static void md_do_sync(mddev_t *mddev) | |||
4076 | 4141 | ||
4077 | j += sectors; | 4142 | j += sectors; |
4078 | if (j>1) mddev->curr_resync = j; | 4143 | if (j>1) mddev->curr_resync = j; |
4079 | 4144 | if (last_check == 0) | |
4145 | /* this is the earliers that rebuilt will be | ||
4146 | * visible in /proc/mdstat | ||
4147 | */ | ||
4148 | md_new_event(mddev); | ||
4080 | 4149 | ||
4081 | if (last_check + window > io_sectors || j == max_sectors) | 4150 | if (last_check + window > io_sectors || j == max_sectors) |
4082 | continue; | 4151 | continue; |
@@ -4262,6 +4331,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4262 | mddev->recovery = 0; | 4331 | mddev->recovery = 0; |
4263 | /* flag recovery needed just to double check */ | 4332 | /* flag recovery needed just to double check */ |
4264 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 4333 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
4334 | md_new_event(mddev); | ||
4265 | goto unlock; | 4335 | goto unlock; |
4266 | } | 4336 | } |
4267 | /* Clear some bits that don't mean anything, but | 4337 | /* Clear some bits that don't mean anything, but |
@@ -4299,6 +4369,7 @@ void md_check_recovery(mddev_t *mddev) | |||
4299 | sprintf(nm, "rd%d", rdev->raid_disk); | 4369 | sprintf(nm, "rd%d", rdev->raid_disk); |
4300 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); | 4370 | sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); |
4301 | spares++; | 4371 | spares++; |
4372 | md_new_event(mddev); | ||
4302 | } else | 4373 | } else |
4303 | break; | 4374 | break; |
4304 | } | 4375 | } |
@@ -4331,9 +4402,9 @@ void md_check_recovery(mddev_t *mddev) | |||
4331 | mdname(mddev)); | 4402 | mdname(mddev)); |
4332 | /* leave the spares where they are, it shouldn't hurt */ | 4403 | /* leave the spares where they are, it shouldn't hurt */ |
4333 | mddev->recovery = 0; | 4404 | mddev->recovery = 0; |
4334 | } else { | 4405 | } else |
4335 | md_wakeup_thread(mddev->sync_thread); | 4406 | md_wakeup_thread(mddev->sync_thread); |
4336 | } | 4407 | md_new_event(mddev); |
4337 | } | 4408 | } |
4338 | unlock: | 4409 | unlock: |
4339 | mddev_unlock(mddev); | 4410 | mddev_unlock(mddev); |