Commit c5ef62e6 authored by Jens Axboe's avatar Jens Axboe
Browse files

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
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -258,6 +258,11 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
		     bio_sector < start_sector))
		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)) {
		/* This bio crosses a device boundary, so we have to split it */
		struct bio *split = bio_split(bio, end_sector - bio_sector,
+18 −4
Original line number Diff line number Diff line
@@ -376,6 +376,11 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
	struct mddev *mddev = q->queuedata;
	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);

	if (mddev == NULL || mddev->pers == NULL) {
@@ -4158,12 +4163,17 @@ __ATTR_PREALLOC(resync_start, S_IRUGO|S_IWUSR,
 * active-idle
 *     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,
		   write_pending, active_idle, bad_word};
		   write_pending, active_idle, broken, bad_word};
static char *array_states[] = {
	"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)
{
@@ -4179,7 +4189,7 @@ array_state_show(struct mddev *mddev, char *page)
{
	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) {
		case 1:
			st = readonly;
@@ -4199,7 +4209,10 @@ array_state_show(struct mddev *mddev, char *page)
				st = active;
			spin_unlock(&mddev->lock);
		}
	else {

		if (test_bit(MD_BROKEN, &mddev->flags) && st == clean)
			st = broken;
	} else {
		if (list_empty(&mddev->disks) &&
		    mddev->raid_disks == 0 &&
		    mddev->dev_sectors == 0)
@@ -4313,6 +4326,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
		break;
	case write_pending:
	case active_idle:
	case broken:
		/* these cannot be set */
		break;
	}
+16 −0
Original line number Diff line number Diff line
@@ -251,6 +251,9 @@ enum mddev_flags {
	MD_NOT_READY,		/* do_md_run() is active, so 'array_state'
				 * 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 {
@@ -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_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)
{
	int faulty = test_bit(Faulty, &rdev->flags);
+6 −0
Original line number Diff line number Diff line
@@ -586,6 +586,12 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio)

	zone = find_zone(mddev->private, &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->bi_iter.bi_sector = sector + zone->dev_start +
		tmp_dev->data_offset;
+12 −1
Original line number Diff line number Diff line
@@ -3129,6 +3129,13 @@ static int raid1_run(struct mddev *mddev)
		    !test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
		    test_bit(Faulty, &conf->mirrors[i].rdev->flags))
			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)
		mddev->recovery_cp = MaxSector;
@@ -3162,8 +3169,12 @@ static int raid1_run(struct mddev *mddev)
	ret = md_integrity_register(mddev);
	if (ret) {
		md_unregister_thread(&mddev->thread);
		raid1_free(mddev, conf);
		goto abort;
	}
	return 0;

abort:
	raid1_free(mddev, conf);
	return ret;
}

Loading