Commit af209e0a authored by Linus Torvalds's avatar Linus Torvalds

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.
parents 53523d52 5d8c71f9
...@@ -1106,10 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap) ...@@ -1106,10 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap)
*/ */
int i; int i;
spin_lock_irq(&bitmap->lock);
for (i = 0; i < bitmap->file_pages; i++) for (i = 0; i < bitmap->file_pages; i++)
set_page_attr(bitmap, bitmap->filemap[i], set_page_attr(bitmap, bitmap->filemap[i],
BITMAP_PAGE_NEEDWRITE); BITMAP_PAGE_NEEDWRITE);
bitmap->allclean = 0; bitmap->allclean = 0;
spin_unlock_irq(&bitmap->lock);
} }
static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) 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,7 +1607,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
for (chunk = s; chunk <= e; chunk++) { for (chunk = s; chunk <= e; chunk++) {
sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap); sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap);
bitmap_set_memory_bits(bitmap, sec, 1); bitmap_set_memory_bits(bitmap, sec, 1);
spin_lock_irq(&bitmap->lock);
bitmap_file_set_bit(bitmap, sec); bitmap_file_set_bit(bitmap, sec);
spin_unlock_irq(&bitmap->lock);
if (sec < bitmap->mddev->recovery_cp) if (sec < bitmap->mddev->recovery_cp)
/* We are asserting that the array is dirty, /* We are asserting that the array is dirty,
* so move the recovery_cp address back so * so move the recovery_cp address back so
......
...@@ -570,7 +570,7 @@ static void mddev_put(struct mddev *mddev) ...@@ -570,7 +570,7 @@ static void mddev_put(struct mddev *mddev)
mddev->ctime == 0 && !mddev->hold_active) { mddev->ctime == 0 && !mddev->hold_active) {
/* Array is not configured at all, and not held active, /* Array is not configured at all, and not held active,
* so destroy it */ * so destroy it */
list_del(&mddev->all_mddevs); list_del_init(&mddev->all_mddevs);
bs = mddev->bio_set; bs = mddev->bio_set;
mddev->bio_set = NULL; mddev->bio_set = NULL;
if (mddev->gendisk) { if (mddev->gendisk) {
...@@ -2546,7 +2546,8 @@ state_show(struct md_rdev *rdev, char *page) ...@@ -2546,7 +2546,8 @@ state_show(struct md_rdev *rdev, char *page)
sep = ","; sep = ",";
} }
if (test_bit(Blocked, &rdev->flags) || if (test_bit(Blocked, &rdev->flags) ||
rdev->badblocks.unacked_exist) { (rdev->badblocks.unacked_exist
&& !test_bit(Faulty, &rdev->flags))) {
len += sprintf(page+len, "%sblocked", sep); len += sprintf(page+len, "%sblocked", sep);
sep = ","; sep = ",";
} }
...@@ -3788,6 +3789,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -3788,6 +3789,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
if (err) if (err)
return err; return err;
else { else {
if (mddev->hold_active == UNTIL_IOCTL)
mddev->hold_active = 0;
sysfs_notify_dirent_safe(mddev->sysfs_state); sysfs_notify_dirent_safe(mddev->sysfs_state);
return len; return len;
} }
...@@ -4487,11 +4490,20 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) ...@@ -4487,11 +4490,20 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
if (!entry->show) if (!entry->show)
return -EIO; return -EIO;
spin_lock(&all_mddevs_lock);
if (list_empty(&mddev->all_mddevs)) {
spin_unlock(&all_mddevs_lock);
return -EBUSY;
}
mddev_get(mddev);
spin_unlock(&all_mddevs_lock);
rv = mddev_lock(mddev); rv = mddev_lock(mddev);
if (!rv) { if (!rv) {
rv = entry->show(mddev, page); rv = entry->show(mddev, page);
mddev_unlock(mddev); mddev_unlock(mddev);
} }
mddev_put(mddev);
return rv; return rv;
} }
...@@ -4507,13 +4519,19 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, ...@@ -4507,13 +4519,19 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
return -EIO; return -EIO;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
spin_lock(&all_mddevs_lock);
if (list_empty(&mddev->all_mddevs)) {
spin_unlock(&all_mddevs_lock);
return -EBUSY;
}
mddev_get(mddev);
spin_unlock(&all_mddevs_lock);
rv = mddev_lock(mddev); rv = mddev_lock(mddev);
if (mddev->hold_active == UNTIL_IOCTL)
mddev->hold_active = 0;
if (!rv) { if (!rv) {
rv = entry->store(mddev, page, length); rv = entry->store(mddev, page, length);
mddev_unlock(mddev); mddev_unlock(mddev);
} }
mddev_put(mddev);
return rv; return rv;
} }
...@@ -7840,6 +7858,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors, ...@@ -7840,6 +7858,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
s + rdev->data_offset, sectors, acknowledged); s + rdev->data_offset, sectors, acknowledged);
if (rv) { if (rv) {
/* Make sure they get written out promptly */ /* Make sure they get written out promptly */
sysfs_notify_dirent_safe(rdev->sysfs_state);
set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags); set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
md_wakeup_thread(rdev->mddev->thread); md_wakeup_thread(rdev->mddev->thread);
} }
......
...@@ -3036,6 +3036,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -3036,6 +3036,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
if (dev->written) if (dev->written)
s->written++; s->written++;
rdev = rcu_dereference(conf->disks[i].rdev); rdev = rcu_dereference(conf->disks[i].rdev);
if (rdev && test_bit(Faulty, &rdev->flags))
rdev = NULL;
if (rdev) { if (rdev) {
is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS, is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS,
&first_bad, &bad_sectors); &first_bad, &bad_sectors);
...@@ -3063,12 +3065,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -3063,12 +3065,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
} }
} else if (test_bit(In_sync, &rdev->flags)) } else if (test_bit(In_sync, &rdev->flags))
set_bit(R5_Insync, &dev->flags); set_bit(R5_Insync, &dev->flags);
else if (!test_bit(Faulty, &rdev->flags)) { else {
/* in sync if before recovery_offset */ /* in sync if before recovery_offset */
if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
set_bit(R5_Insync, &dev->flags); set_bit(R5_Insync, &dev->flags);
} }
if (test_bit(R5_WriteError, &dev->flags)) { if (rdev && test_bit(R5_WriteError, &dev->flags)) {
clear_bit(R5_Insync, &dev->flags); clear_bit(R5_Insync, &dev->flags);
if (!test_bit(Faulty, &rdev->flags)) { if (!test_bit(Faulty, &rdev->flags)) {
s->handle_bad_blocks = 1; s->handle_bad_blocks = 1;
...@@ -3076,7 +3078,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -3076,7 +3078,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
} else } else
clear_bit(R5_WriteError, &dev->flags); clear_bit(R5_WriteError, &dev->flags);
} }
if (test_bit(R5_MadeGood, &dev->flags)) { if (rdev && test_bit(R5_MadeGood, &dev->flags)) {
if (!test_bit(Faulty, &rdev->flags)) { if (!test_bit(Faulty, &rdev->flags)) {
s->handle_bad_blocks = 1; s->handle_bad_blocks = 1;
atomic_inc(&rdev->nr_pending); atomic_inc(&rdev->nr_pending);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment