Commit c5ef62e6 authored by Jens Axboe's avatar Jens Axboe

Merge branch 'md-next' of git://git.kernel.org/pub/scm/linux/kernel/git/song/md into for-5.4/block

Pull MD fixes from Song.

* 'md-next' of git://git.kernel.org/pub/scm/linux/kernel/git/song/md:
  md/raid5: use bio_end_sector to calculate last_sector
  md/raid1: fail run raid1 array when active disk less than one
  md raid0/linear: Mark array as 'broken' and fail BIOs if a member is gone
parents a22a9602 b0f01ecf
...@@ -258,6 +258,11 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) ...@@ -258,6 +258,11 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
bio_sector < start_sector)) bio_sector < start_sector))
goto out_of_bounds; goto out_of_bounds;
if (unlikely(is_mddev_broken(tmp_dev->rdev, "linear"))) {
bio_io_error(bio);
return true;
}
if (unlikely(bio_end_sector(bio) > end_sector)) { if (unlikely(bio_end_sector(bio) > end_sector)) {
/* This bio crosses a device boundary, so we have to split it */ /* This bio crosses a device boundary, so we have to split it */
struct bio *split = bio_split(bio, end_sector - bio_sector, struct bio *split = bio_split(bio, end_sector - bio_sector,
......
...@@ -376,6 +376,11 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio) ...@@ -376,6 +376,11 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
struct mddev *mddev = q->queuedata; struct mddev *mddev = q->queuedata;
unsigned int sectors; unsigned int sectors;
if (unlikely(test_bit(MD_BROKEN, &mddev->flags)) && (rw == WRITE)) {
bio_io_error(bio);
return BLK_QC_T_NONE;
}
blk_queue_split(q, &bio); blk_queue_split(q, &bio);
if (mddev == NULL || mddev->pers == NULL) { if (mddev == NULL || mddev->pers == NULL) {
...@@ -4158,12 +4163,17 @@ __ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR, ...@@ -4158,12 +4163,17 @@ __ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR,
* active-idle * active-idle
* like active, but no writes have been seen for a while (100msec). * like active, but no writes have been seen for a while (100msec).
* *
* broken
* RAID0/LINEAR-only: same as clean, but array is missing a member.
* It's useful because RAID0/LINEAR mounted-arrays aren't stopped
* when a member is gone, so this state will at least alert the
* user that something is wrong.
*/ */
enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active, enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active,
write_pending, active_idle, bad_word}; write_pending, active_idle, broken, bad_word};
static char *array_states[] = { static char *array_states[] = {
"clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active", "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active",
"write-pending", "active-idle", NULL }; "write-pending", "active-idle", "broken", NULL };
static int match_word(const char *word, char **list) static int match_word(const char *word, char **list)
{ {
...@@ -4179,7 +4189,7 @@ array_state_show(struct mddev *mddev, char *page) ...@@ -4179,7 +4189,7 @@ array_state_show(struct mddev *mddev, char *page)
{ {
enum array_state st = inactive; enum array_state st = inactive;
if (mddev->pers && !test_bit(MD_NOT_READY, &mddev->flags)) if (mddev->pers && !test_bit(MD_NOT_READY, &mddev->flags)) {
switch(mddev->ro) { switch(mddev->ro) {
case 1: case 1:
st = readonly; st = readonly;
...@@ -4199,7 +4209,10 @@ array_state_show(struct mddev *mddev, char *page) ...@@ -4199,7 +4209,10 @@ array_state_show(struct mddev *mddev, char *page)
st = active; st = active;
spin_unlock(&mddev->lock); spin_unlock(&mddev->lock);
} }
else {
if (test_bit(MD_BROKEN, &mddev->flags) && st == clean)
st = broken;
} else {
if (list_empty(&mddev->disks) && if (list_empty(&mddev->disks) &&
mddev->raid_disks == 0 && mddev->raid_disks == 0 &&
mddev->dev_sectors == 0) mddev->dev_sectors == 0)
...@@ -4313,6 +4326,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) ...@@ -4313,6 +4326,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
break; break;
case write_pending: case write_pending:
case active_idle: case active_idle:
case broken:
/* these cannot be set */ /* these cannot be set */
break; break;
} }
......
...@@ -251,6 +251,9 @@ enum mddev_flags { ...@@ -251,6 +251,9 @@ enum mddev_flags {
MD_NOT_READY, /* do_md_run() is active, so 'array_state' MD_NOT_READY, /* do_md_run() is active, so 'array_state'
* must not report that array is ready yet * must not report that array is ready yet
*/ */
MD_BROKEN, /* This is used in RAID-0/LINEAR only, to stop
* I/O in case an array member is gone/failed.
*/
}; };
enum mddev_sb_flags { enum mddev_sb_flags {
...@@ -739,6 +742,19 @@ extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev, ...@@ -739,6 +742,19 @@ extern void mddev_create_wb_pool(struct mddev *mddev, struct md_rdev *rdev,
struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr); struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev); struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);
static inline bool is_mddev_broken(struct md_rdev *rdev, const char *md_type)
{
int flags = rdev->bdev->bd_disk->flags;
if (!(flags & GENHD_FL_UP)) {
if (!test_and_set_bit(MD_BROKEN, &rdev->mddev->flags))
pr_warn("md: %s: %s array has a missing/failed member\n",
mdname(rdev->mddev), md_type);
return true;
}
return false;
}
static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev) static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
{ {
int faulty = test_bit(Faulty, &rdev->flags); int faulty = test_bit(Faulty, &rdev->flags);
......
...@@ -586,6 +586,12 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) ...@@ -586,6 +586,12 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)
zone = find_zone(mddev->private, &sector); zone = find_zone(mddev->private, &sector);
tmp_dev = map_sector(mddev, zone, sector, &sector); tmp_dev = map_sector(mddev, zone, sector, &sector);
if (unlikely(is_mddev_broken(tmp_dev, "raid0"))) {
bio_io_error(bio);
return true;
}
bio_set_dev(bio, tmp_dev->bdev); bio_set_dev(bio, tmp_dev->bdev);
bio->bi_iter.bi_sector = sector + zone->dev_start + bio->bi_iter.bi_sector = sector + zone->dev_start +
tmp_dev->data_offset; tmp_dev->data_offset;
......
...@@ -3129,6 +3129,13 @@ static int raid1_run(struct mddev *mddev) ...@@ -3129,6 +3129,13 @@ static int raid1_run(struct mddev *mddev)
!test_bit(In_sync, &conf->mirrors[i].rdev->flags) || !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
test_bit(Faulty, &conf->mirrors[i].rdev->flags)) test_bit(Faulty, &conf->mirrors[i].rdev->flags))
mddev->degraded++; mddev->degraded++;
/*
* RAID1 needs at least one disk in active
*/
if (conf->raid_disks - mddev->degraded < 1) {
ret = -EINVAL;
goto abort;
}
if (conf->raid_disks - mddev->degraded == 1) if (conf->raid_disks - mddev->degraded == 1)
mddev->recovery_cp = MaxSector; mddev->recovery_cp = MaxSector;
...@@ -3162,8 +3169,12 @@ static int raid1_run(struct mddev *mddev) ...@@ -3162,8 +3169,12 @@ static int raid1_run(struct mddev *mddev)
ret = md_integrity_register(mddev); ret = md_integrity_register(mddev);
if (ret) { if (ret) {
md_unregister_thread(&mddev->thread); md_unregister_thread(&mddev->thread);
raid1_free(mddev, conf); goto abort;
} }
return 0;
abort:
raid1_free(mddev, conf);
return ret; return ret;
} }
......
...@@ -5499,7 +5499,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) ...@@ -5499,7 +5499,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
return; return;
logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1);
last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9); last_sector = bio_end_sector(bi);
bi->bi_next = NULL; bi->bi_next = NULL;
......
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