Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c286e81 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull MD fixes from Shaohua Li:
 "There are several bug fixes queued:

   - fix raid5-cache recovery bugs

   - fix discard IO error handling for raid1/10

   - fix array sync writes bogus position to superblock

   - fix IO error handling for raid array with external metadata"

* tag 'md/4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md:
  md: be careful not lot leak internal curr_resync value into metadata. -- (all)
  raid1: handle read error also in readonly mode
  raid5-cache: correct condition for empty metadata write
  md: report 'write_pending' state when array in sync
  md/raid5: write an empty meta-block when creating log super-block
  md/raid5: initialize next_checkpoint field before use
  RAID10: ignore discard error
  RAID1: ignore discard error
parents e12d8d51 1217e1d1
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -3887,10 +3887,10 @@ array_state_show(struct mddev *mddev, char *page)
			st = read_auto;
			st = read_auto;
			break;
			break;
		case 0:
		case 0:
			if (mddev->in_sync)
			if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
				st = clean;
			else if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
				st = write_pending;
				st = write_pending;
			else if (mddev->in_sync)
				st = clean;
			else if (mddev->safemode)
			else if (mddev->safemode)
				st = active_idle;
				st = active_idle;
			else
			else
@@ -8144,14 +8144,14 @@ void md_do_sync(struct md_thread *thread)


	if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
	if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
	    !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
	    !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
	    mddev->curr_resync > 2) {
	    mddev->curr_resync > 3) {
		mddev->curr_resync_completed = mddev->curr_resync;
		mddev->curr_resync_completed = mddev->curr_resync;
		sysfs_notify(&mddev->kobj, NULL, "sync_completed");
		sysfs_notify(&mddev->kobj, NULL, "sync_completed");
	}
	}
	mddev->pers->sync_request(mddev, max_sectors, &skipped);
	mddev->pers->sync_request(mddev, max_sectors, &skipped);


	if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
	if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
	    mddev->curr_resync > 2) {
	    mddev->curr_resync > 3) {
		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
			if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
			if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
				if (mddev->curr_resync >= mddev->recovery_cp) {
				if (mddev->curr_resync >= mddev->recovery_cp) {
+15 −11
Original line number Original line Diff line number Diff line
@@ -403,11 +403,14 @@ static void raid1_end_write_request(struct bio *bio)
	struct bio *to_put = NULL;
	struct bio *to_put = NULL;
	int mirror = find_bio_disk(r1_bio, bio);
	int mirror = find_bio_disk(r1_bio, bio);
	struct md_rdev *rdev = conf->mirrors[mirror].rdev;
	struct md_rdev *rdev = conf->mirrors[mirror].rdev;
	bool discard_error;

	discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD;


	/*
	/*
	 * 'one mirror IO has finished' event handler:
	 * 'one mirror IO has finished' event handler:
	 */
	 */
	if (bio->bi_error) {
	if (bio->bi_error && !discard_error) {
		set_bit(WriteErrorSeen,	&rdev->flags);
		set_bit(WriteErrorSeen,	&rdev->flags);
		if (!test_and_set_bit(WantReplacement, &rdev->flags))
		if (!test_and_set_bit(WantReplacement, &rdev->flags))
			set_bit(MD_RECOVERY_NEEDED, &
			set_bit(MD_RECOVERY_NEEDED, &
@@ -444,7 +447,7 @@ static void raid1_end_write_request(struct bio *bio)


		/* Maybe we can clear some bad blocks. */
		/* Maybe we can clear some bad blocks. */
		if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
		if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors,
				&first_bad, &bad_sectors)) {
				&first_bad, &bad_sectors) && !discard_error) {
			r1_bio->bios[mirror] = IO_MADE_GOOD;
			r1_bio->bios[mirror] = IO_MADE_GOOD;
			set_bit(R1BIO_MadeGood, &r1_bio->state);
			set_bit(R1BIO_MadeGood, &r1_bio->state);
		}
		}
@@ -2294,17 +2297,23 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
	 * This is all done synchronously while the array is
	 * This is all done synchronously while the array is
	 * frozen
	 * frozen
	 */
	 */

	bio = r1_bio->bios[r1_bio->read_disk];
	bdevname(bio->bi_bdev, b);
	bio_put(bio);
	r1_bio->bios[r1_bio->read_disk] = NULL;

	if (mddev->ro == 0) {
	if (mddev->ro == 0) {
		freeze_array(conf, 1);
		freeze_array(conf, 1);
		fix_read_error(conf, r1_bio->read_disk,
		fix_read_error(conf, r1_bio->read_disk,
			       r1_bio->sector, r1_bio->sectors);
			       r1_bio->sector, r1_bio->sectors);
		unfreeze_array(conf);
		unfreeze_array(conf);
	} else
	} else {
		md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
		r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
	}

	rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);
	rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev);


	bio = r1_bio->bios[r1_bio->read_disk];
	bdevname(bio->bi_bdev, b);
read_more:
read_more:
	disk = read_balance(conf, r1_bio, &max_sectors);
	disk = read_balance(conf, r1_bio, &max_sectors);
	if (disk == -1) {
	if (disk == -1) {
@@ -2315,11 +2324,6 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
	} else {
	} else {
		const unsigned long do_sync
		const unsigned long do_sync
			= r1_bio->master_bio->bi_opf & REQ_SYNC;
			= r1_bio->master_bio->bi_opf & REQ_SYNC;
		if (bio) {
			r1_bio->bios[r1_bio->read_disk] =
				mddev->ro ? IO_BLOCKED : NULL;
			bio_put(bio);
		}
		r1_bio->read_disk = disk;
		r1_bio->read_disk = disk;
		bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev);
		bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev);
		bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector,
		bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector,
+5 −2
Original line number Original line Diff line number Diff line
@@ -447,6 +447,9 @@ static void raid10_end_write_request(struct bio *bio)
	struct r10conf *conf = r10_bio->mddev->private;
	struct r10conf *conf = r10_bio->mddev->private;
	int slot, repl;
	int slot, repl;
	struct md_rdev *rdev = NULL;
	struct md_rdev *rdev = NULL;
	bool discard_error;

	discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD;


	dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
	dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl);


@@ -460,7 +463,7 @@ static void raid10_end_write_request(struct bio *bio)
	/*
	/*
	 * this branch is our 'one mirror IO has finished' event handler:
	 * this branch is our 'one mirror IO has finished' event handler:
	 */
	 */
	if (bio->bi_error) {
	if (bio->bi_error && !discard_error) {
		if (repl)
		if (repl)
			/* Never record new bad blocks to replacement,
			/* Never record new bad blocks to replacement,
			 * just fail it.
			 * just fail it.
@@ -503,7 +506,7 @@ static void raid10_end_write_request(struct bio *bio)
		if (is_badblock(rdev,
		if (is_badblock(rdev,
				r10_bio->devs[slot].addr,
				r10_bio->devs[slot].addr,
				r10_bio->sectors,
				r10_bio->sectors,
				&first_bad, &bad_sectors)) {
				&first_bad, &bad_sectors) && !discard_error) {
			bio_put(bio);
			bio_put(bio);
			if (repl)
			if (repl)
				r10_bio->devs[slot].repl_bio = IO_MADE_GOOD;
				r10_bio->devs[slot].repl_bio = IO_MADE_GOOD;
+5 −1
Original line number Original line Diff line number Diff line
@@ -1087,7 +1087,7 @@ static int r5l_recovery_log(struct r5l_log *log)
	 * 1's seq + 10 and let superblock points to meta2. The same recovery will
	 * 1's seq + 10 and let superblock points to meta2. The same recovery will
	 * not think meta 3 is a valid meta, because its seq doesn't match
	 * not think meta 3 is a valid meta, because its seq doesn't match
	 */
	 */
	if (ctx.seq > log->last_cp_seq + 1) {
	if (ctx.seq > log->last_cp_seq) {
		int ret;
		int ret;


		ret = r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq + 10);
		ret = r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq + 10);
@@ -1096,6 +1096,8 @@ static int r5l_recovery_log(struct r5l_log *log)
		log->seq = ctx.seq + 11;
		log->seq = ctx.seq + 11;
		log->log_start = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
		log->log_start = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
		r5l_write_super(log, ctx.pos);
		r5l_write_super(log, ctx.pos);
		log->last_checkpoint = ctx.pos;
		log->next_checkpoint = ctx.pos;
	} else {
	} else {
		log->log_start = ctx.pos;
		log->log_start = ctx.pos;
		log->seq = ctx.seq;
		log->seq = ctx.seq;
@@ -1154,6 +1156,7 @@ static int r5l_load_log(struct r5l_log *log)
	if (create_super) {
	if (create_super) {
		log->last_cp_seq = prandom_u32();
		log->last_cp_seq = prandom_u32();
		cp = 0;
		cp = 0;
		r5l_log_write_empty_meta_block(log, cp, log->last_cp_seq);
		/*
		/*
		 * Make sure super points to correct address. Log might have
		 * Make sure super points to correct address. Log might have
		 * data very soon. If super hasn't correct log tail address,
		 * data very soon. If super hasn't correct log tail address,
@@ -1168,6 +1171,7 @@ static int r5l_load_log(struct r5l_log *log)
	if (log->max_free_space > RECLAIM_MAX_FREE_SPACE)
	if (log->max_free_space > RECLAIM_MAX_FREE_SPACE)
		log->max_free_space = RECLAIM_MAX_FREE_SPACE;
		log->max_free_space = RECLAIM_MAX_FREE_SPACE;
	log->last_checkpoint = cp;
	log->last_checkpoint = cp;
	log->next_checkpoint = cp;


	__free_page(page);
	__free_page(page);