diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-12-09 11:18:08 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-12-09 11:18:08 -0500 |
| commit | af209e0aea2b1a6216c728decfaa231f587b8c2b (patch) | |
| tree | d50d386d7e84abfd6ae96eb30cf08d19f8946f93 | |
| parent | 53523d5263dce1a3e3662c612f7050a4569071ad (diff) | |
| parent | 5d8c71f9e5fbdd95650be00294d238e27a363b5c (diff) | |
Merge branch 'for-linus' of git://neil.brown.name/md
* 'for-linus' of git://neil.brown.name/md:
md: raid5 crash during degradation
md/raid5: never wait for bad-block acks on failed device.
md: ensure new badblocks are handled promptly.
md: bad blocks shouldn't cause a Blocked status on a Faulty device.
md: take a reference to mddev during sysfs access.
md: refine interpretation of "hold_active == UNTIL_IOCTL".
md/lock: ensure updates to page_attrs are properly locked.
| -rw-r--r-- | drivers/md/bitmap.c | 4 | ||||
| -rw-r--r-- | drivers/md/md.c | 27 | ||||
| -rw-r--r-- | drivers/md/raid5.c | 8 |
3 files changed, 32 insertions, 7 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7878712721bf..b6907118283a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
| @@ -1106,10 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap) | |||
| 1106 | */ | 1106 | */ |
| 1107 | int i; | 1107 | int i; |
| 1108 | 1108 | ||
| 1109 | spin_lock_irq(&bitmap->lock); | ||
| 1109 | for (i = 0; i < bitmap->file_pages; i++) | 1110 | for (i = 0; i < bitmap->file_pages; i++) |
| 1110 | set_page_attr(bitmap, bitmap->filemap[i], | 1111 | set_page_attr(bitmap, bitmap->filemap[i], |
| 1111 | BITMAP_PAGE_NEEDWRITE); | 1112 | BITMAP_PAGE_NEEDWRITE); |
| 1112 | bitmap->allclean = 0; | 1113 | bitmap->allclean = 0; |
| 1114 | spin_unlock_irq(&bitmap->lock); | ||
| 1113 | } | 1115 | } |
| 1114 | 1116 | ||
| 1115 | static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) | 1117 | static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) |
| @@ -1605,7 +1607,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e) | |||
| 1605 | for (chunk = s; chunk <= e; chunk++) { | 1607 | for (chunk = s; chunk <= e; chunk++) { |
| 1606 | sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap); | 1608 | sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap); |
| 1607 | bitmap_set_memory_bits(bitmap, sec, 1); | 1609 | bitmap_set_memory_bits(bitmap, sec, 1); |
| 1610 | spin_lock_irq(&bitmap->lock); | ||
| 1608 | bitmap_file_set_bit(bitmap, sec); | 1611 | bitmap_file_set_bit(bitmap, sec); |
| 1612 | spin_unlock_irq(&bitmap->lock); | ||
| 1609 | if (sec < bitmap->mddev->recovery_cp) | 1613 | if (sec < bitmap->mddev->recovery_cp) |
| 1610 | /* We are asserting that the array is dirty, | 1614 | /* We are asserting that the array is dirty, |
| 1611 | * so move the recovery_cp address back so | 1615 | * so move the recovery_cp address back so |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 84acfe7d10e4..ee981737edfc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -570,7 +570,7 @@ static void mddev_put(struct mddev *mddev) | |||
| 570 | mddev->ctime == 0 && !mddev->hold_active) { | 570 | mddev->ctime == 0 && !mddev->hold_active) { |
| 571 | /* Array is not configured at all, and not held active, | 571 | /* Array is not configured at all, and not held active, |
| 572 | * so destroy it */ | 572 | * so destroy it */ |
| 573 | list_del(&mddev->all_mddevs); | 573 | list_del_init(&mddev->all_mddevs); |
| 574 | bs = mddev->bio_set; | 574 | bs = mddev->bio_set; |
| 575 | mddev->bio_set = NULL; | 575 | mddev->bio_set = NULL; |
| 576 | if (mddev->gendisk) { | 576 | if (mddev->gendisk) { |
| @@ -2546,7 +2546,8 @@ state_show(struct md_rdev *rdev, char *page) | |||
| 2546 | sep = ","; | 2546 | sep = ","; |
| 2547 | } | 2547 | } |
| 2548 | if (test_bit(Blocked, &rdev->flags) || | 2548 | if (test_bit(Blocked, &rdev->flags) || |
| 2549 | rdev->badblocks.unacked_exist) { | 2549 | (rdev->badblocks.unacked_exist |
| 2550 | && !test_bit(Faulty, &rdev->flags))) { | ||
| 2550 | len += sprintf(page+len, "%sblocked", sep); | 2551 | len += sprintf(page+len, "%sblocked", sep); |
| 2551 | sep = ","; | 2552 | sep = ","; |
| 2552 | } | 2553 | } |
| @@ -3788,6 +3789,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) | |||
| 3788 | if (err) | 3789 | if (err) |
| 3789 | return err; | 3790 | return err; |
| 3790 | else { | 3791 | else { |
| 3792 | if (mddev->hold_active == UNTIL_IOCTL) | ||
| 3793 | mddev->hold_active = 0; | ||
| 3791 | sysfs_notify_dirent_safe(mddev->sysfs_state); | 3794 | sysfs_notify_dirent_safe(mddev->sysfs_state); |
| 3792 | return len; | 3795 | return len; |
| 3793 | } | 3796 | } |
| @@ -4487,11 +4490,20 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | |||
| 4487 | 4490 | ||
| 4488 | if (!entry->show) | 4491 | if (!entry->show) |
| 4489 | return -EIO; | 4492 | return -EIO; |
| 4493 | spin_lock(&all_mddevs_lock); | ||
| 4494 | if (list_empty(&mddev->all_mddevs)) { | ||
| 4495 | spin_unlock(&all_mddevs_lock); | ||
| 4496 | return -EBUSY; | ||
| 4497 | } | ||
| 4498 | mddev_get(mddev); | ||
| 4499 | spin_unlock(&all_mddevs_lock); | ||
| 4500 | |||
| 4490 | rv = mddev_lock(mddev); | 4501 | rv = mddev_lock(mddev); |
| 4491 | if (!rv) { | 4502 | if (!rv) { |
| 4492 | rv = entry->show(mddev, page); | 4503 | rv = entry->show(mddev, page); |
| 4493 | mddev_unlock(mddev); | 4504 | mddev_unlock(mddev); |
| 4494 | } | 4505 | } |
| 4506 | mddev_put(mddev); | ||
| 4495 | return rv; | 4507 | return rv; |
| 4496 | } | 4508 | } |
| 4497 | 4509 | ||
| @@ -4507,13 +4519,19 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, | |||
| 4507 | return -EIO; | 4519 | return -EIO; |
| 4508 | if (!capable(CAP_SYS_ADMIN)) | 4520 | if (!capable(CAP_SYS_ADMIN)) |
| 4509 | return -EACCES; | 4521 | return -EACCES; |
| 4522 | spin_lock(&all_mddevs_lock); | ||
| 4523 | if (list_empty(&mddev->all_mddevs)) { | ||
| 4524 | spin_unlock(&all_mddevs_lock); | ||
| 4525 | return -EBUSY; | ||
| 4526 | } | ||
| 4527 | mddev_get(mddev); | ||
| 4528 | spin_unlock(&all_mddevs_lock); | ||
| 4510 | rv = mddev_lock(mddev); | 4529 | rv = mddev_lock(mddev); |
| 4511 | if (mddev->hold_active == UNTIL_IOCTL) | ||
| 4512 | mddev->hold_active = 0; | ||
| 4513 | if (!rv) { | 4530 | if (!rv) { |
| 4514 | rv = entry->store(mddev, page, length); | 4531 | rv = entry->store(mddev, page, length); |
| 4515 | mddev_unlock(mddev); | 4532 | mddev_unlock(mddev); |
| 4516 | } | 4533 | } |
| 4534 | mddev_put(mddev); | ||
| 4517 | return rv; | 4535 | return rv; |
| 4518 | } | 4536 | } |
| 4519 | 4537 | ||
| @@ -7840,6 +7858,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors, | |||
| 7840 | s + rdev->data_offset, sectors, acknowledged); | 7858 | s + rdev->data_offset, sectors, acknowledged); |
| 7841 | if (rv) { | 7859 | if (rv) { |
| 7842 | /* Make sure they get written out promptly */ | 7860 | /* Make sure they get written out promptly */ |
| 7861 | sysfs_notify_dirent_safe(rdev->sysfs_state); | ||
| 7843 | set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags); | 7862 | set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags); |
| 7844 | md_wakeup_thread(rdev->mddev->thread); | 7863 | md_wakeup_thread(rdev->mddev->thread); |
| 7845 | } | 7864 | } |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 297e26092178..31670f8d6b65 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -3036,6 +3036,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) | |||
| 3036 | if (dev->written) | 3036 | if (dev->written) |
| 3037 | s->written++; | 3037 | s->written++; |
| 3038 | rdev = rcu_dereference(conf->disks[i].rdev); | 3038 | rdev = rcu_dereference(conf->disks[i].rdev); |
| 3039 | if (rdev && test_bit(Faulty, &rdev->flags)) | ||
| 3040 | rdev = NULL; | ||
| 3039 | if (rdev) { | 3041 | if (rdev) { |
| 3040 | is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS, | 3042 | is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS, |
| 3041 | &first_bad, &bad_sectors); | 3043 | &first_bad, &bad_sectors); |
| @@ -3063,12 +3065,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) | |||
| 3063 | } | 3065 | } |
| 3064 | } else if (test_bit(In_sync, &rdev->flags)) | 3066 | } else if (test_bit(In_sync, &rdev->flags)) |
| 3065 | set_bit(R5_Insync, &dev->flags); | 3067 | set_bit(R5_Insync, &dev->flags); |
| 3066 | else if (!test_bit(Faulty, &rdev->flags)) { | 3068 | else { |
| 3067 | /* in sync if before recovery_offset */ | 3069 | /* in sync if before recovery_offset */ |
| 3068 | if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) | 3070 | if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) |
| 3069 | set_bit(R5_Insync, &dev->flags); | 3071 | set_bit(R5_Insync, &dev->flags); |
| 3070 | } | 3072 | } |
| 3071 | if (test_bit(R5_WriteError, &dev->flags)) { | 3073 | if (rdev && test_bit(R5_WriteError, &dev->flags)) { |
| 3072 | clear_bit(R5_Insync, &dev->flags); | 3074 | clear_bit(R5_Insync, &dev->flags); |
| 3073 | if (!test_bit(Faulty, &rdev->flags)) { | 3075 | if (!test_bit(Faulty, &rdev->flags)) { |
| 3074 | s->handle_bad_blocks = 1; | 3076 | s->handle_bad_blocks = 1; |
| @@ -3076,7 +3078,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) | |||
| 3076 | } else | 3078 | } else |
| 3077 | clear_bit(R5_WriteError, &dev->flags); | 3079 | clear_bit(R5_WriteError, &dev->flags); |
| 3078 | } | 3080 | } |
| 3079 | if (test_bit(R5_MadeGood, &dev->flags)) { | 3081 | if (rdev && test_bit(R5_MadeGood, &dev->flags)) { |
| 3080 | if (!test_bit(Faulty, &rdev->flags)) { | 3082 | if (!test_bit(Faulty, &rdev->flags)) { |
| 3081 | s->handle_bad_blocks = 1; | 3083 | s->handle_bad_blocks = 1; |
| 3082 | atomic_inc(&rdev->nr_pending); | 3084 | atomic_inc(&rdev->nr_pending); |
