diff options
author | Dan Williams <dan.j.williams@intel.com> | 2008-04-30 03:52:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:33 -0400 |
commit | 6bfe0b499082fd3950429017cd8ebf2a6c458aa5 (patch) | |
tree | 81476cf7f7ddbea135bdb93729e0bffae0e7c163 /drivers/md/md.c | |
parent | 11e2ede0228ee0f81ccacd15894908c3bf241f73 (diff) |
md: support blocking writes to an array on device failure
Allows a userspace metadata handler to take action upon detecting a device
failure.
Based on an original patch by Neil Brown.
Changes:
-added blocked_wait waitqueue to rdev
-don't qualify Blocked with Faulty always let userspace block writes
-added md_wait_for_blocked_rdev to wait for the block device to be clear, if
userspace misses the notification another one is sent every 5 seconds
-set MD_RECOVERY_NEEDED after clearing "blocked"
-kill DoBlock flag, just test mddev->external
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index bec00b201a73..83eb78b00137 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1828,6 +1828,10 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
1828 | len += sprintf(page+len, "%swrite_mostly",sep); | 1828 | len += sprintf(page+len, "%swrite_mostly",sep); |
1829 | sep = ","; | 1829 | sep = ","; |
1830 | } | 1830 | } |
1831 | if (test_bit(Blocked, &rdev->flags)) { | ||
1832 | len += sprintf(page+len, "%sblocked", sep); | ||
1833 | sep = ","; | ||
1834 | } | ||
1831 | if (!test_bit(Faulty, &rdev->flags) && | 1835 | if (!test_bit(Faulty, &rdev->flags) && |
1832 | !test_bit(In_sync, &rdev->flags)) { | 1836 | !test_bit(In_sync, &rdev->flags)) { |
1833 | len += sprintf(page+len, "%sspare", sep); | 1837 | len += sprintf(page+len, "%sspare", sep); |
@@ -1844,6 +1848,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | |||
1844 | * remove - disconnects the device | 1848 | * remove - disconnects the device |
1845 | * writemostly - sets write_mostly | 1849 | * writemostly - sets write_mostly |
1846 | * -writemostly - clears write_mostly | 1850 | * -writemostly - clears write_mostly |
1851 | * blocked - sets the Blocked flag | ||
1852 | * -blocked - clears the Blocked flag | ||
1847 | */ | 1853 | */ |
1848 | int err = -EINVAL; | 1854 | int err = -EINVAL; |
1849 | if (cmd_match(buf, "faulty") && rdev->mddev->pers) { | 1855 | if (cmd_match(buf, "faulty") && rdev->mddev->pers) { |
@@ -1866,6 +1872,16 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | |||
1866 | } else if (cmd_match(buf, "-writemostly")) { | 1872 | } else if (cmd_match(buf, "-writemostly")) { |
1867 | clear_bit(WriteMostly, &rdev->flags); | 1873 | clear_bit(WriteMostly, &rdev->flags); |
1868 | err = 0; | 1874 | err = 0; |
1875 | } else if (cmd_match(buf, "blocked")) { | ||
1876 | set_bit(Blocked, &rdev->flags); | ||
1877 | err = 0; | ||
1878 | } else if (cmd_match(buf, "-blocked")) { | ||
1879 | clear_bit(Blocked, &rdev->flags); | ||
1880 | wake_up(&rdev->blocked_wait); | ||
1881 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); | ||
1882 | md_wakeup_thread(rdev->mddev->thread); | ||
1883 | |||
1884 | err = 0; | ||
1869 | } | 1885 | } |
1870 | return err ? err : len; | 1886 | return err ? err : len; |
1871 | } | 1887 | } |
@@ -2194,7 +2210,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi | |||
2194 | goto abort_free; | 2210 | goto abort_free; |
2195 | } | 2211 | } |
2196 | } | 2212 | } |
2213 | |||
2197 | INIT_LIST_HEAD(&rdev->same_set); | 2214 | INIT_LIST_HEAD(&rdev->same_set); |
2215 | init_waitqueue_head(&rdev->blocked_wait); | ||
2198 | 2216 | ||
2199 | return rdev; | 2217 | return rdev; |
2200 | 2218 | ||
@@ -4958,6 +4976,9 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
4958 | 4976 | ||
4959 | if (!rdev || test_bit(Faulty, &rdev->flags)) | 4977 | if (!rdev || test_bit(Faulty, &rdev->flags)) |
4960 | return; | 4978 | return; |
4979 | |||
4980 | if (mddev->external) | ||
4981 | set_bit(Blocked, &rdev->flags); | ||
4961 | /* | 4982 | /* |
4962 | dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", | 4983 | dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", |
4963 | mdname(mddev), | 4984 | mdname(mddev), |
@@ -5760,7 +5781,7 @@ static int remove_and_add_spares(mddev_t *mddev) | |||
5760 | 5781 | ||
5761 | rdev_for_each(rdev, rtmp, mddev) | 5782 | rdev_for_each(rdev, rtmp, mddev) |
5762 | if (rdev->raid_disk >= 0 && | 5783 | if (rdev->raid_disk >= 0 && |
5763 | !mddev->external && | 5784 | !test_bit(Blocked, &rdev->flags) && |
5764 | (test_bit(Faulty, &rdev->flags) || | 5785 | (test_bit(Faulty, &rdev->flags) || |
5765 | ! test_bit(In_sync, &rdev->flags)) && | 5786 | ! test_bit(In_sync, &rdev->flags)) && |
5766 | atomic_read(&rdev->nr_pending)==0) { | 5787 | atomic_read(&rdev->nr_pending)==0) { |
@@ -5959,6 +5980,16 @@ void md_check_recovery(mddev_t *mddev) | |||
5959 | } | 5980 | } |
5960 | } | 5981 | } |
5961 | 5982 | ||
5983 | void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev) | ||
5984 | { | ||
5985 | sysfs_notify(&rdev->kobj, NULL, "state"); | ||
5986 | wait_event_timeout(rdev->blocked_wait, | ||
5987 | !test_bit(Blocked, &rdev->flags), | ||
5988 | msecs_to_jiffies(5000)); | ||
5989 | rdev_dec_pending(rdev, mddev); | ||
5990 | } | ||
5991 | EXPORT_SYMBOL(md_wait_for_blocked_rdev); | ||
5992 | |||
5962 | static int md_notify_reboot(struct notifier_block *this, | 5993 | static int md_notify_reboot(struct notifier_block *this, |
5963 | unsigned long code, void *x) | 5994 | unsigned long code, void *x) |
5964 | { | 5995 | { |