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

Commit e0f3e6a7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull device mapper fixes from Mike Snitzer:

 - a couple DM raid and DM mirror fixes

 - a couple .request_fn request-based DM NULL pointer fixes

 - a fix for a DM target reference count leak, on target load error,
   that prevented associated DM target kernel module(s) from being
   removed

* tag 'dm-4.9-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm table: fix missing dm_put_target_type() in dm_table_add_target()
  dm rq: clear kworker_task if kthread_run() returned an error
  dm: free io_barrier after blk_cleanup_queue call
  dm raid: fix activation of existing raid4/10 devices
  dm mirror: use all available legs on multiple failures
  dm mirror: fix read error on recovery after default leg failure
  dm raid: fix compat_features validation
parents 43937003 dafa724b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -309,3 +309,4 @@ Version History
	with a reshape in progress.
1.9.0   Add support for RAID level takeover/reshape/region size
	and set size reduction.
1.9.1   Fix activation of existing RAID 4/10 mapped devices
+9 −6
Original line number Diff line number Diff line
@@ -266,7 +266,7 @@ static struct raid_type {
	{"raid10_offset", "raid10 offset (striped mirrors)",	    0, 2, 10, ALGORITHM_RAID10_OFFSET},
	{"raid10_near",	  "raid10 near (striped mirrors)",	    0, 2, 10, ALGORITHM_RAID10_NEAR},
	{"raid10",	  "raid10 (striped mirrors)",		    0, 2, 10, ALGORITHM_RAID10_DEFAULT},
	{"raid4",	  "raid4 (dedicated last parity disk)",	    1, 2, 4,  ALGORITHM_PARITY_N}, /* raid4 layout = raid5_n */
	{"raid4",	  "raid4 (dedicated first parity disk)",    1, 2, 5,  ALGORITHM_PARITY_0}, /* raid4 layout = raid5_0 */
	{"raid5_n",	  "raid5 (dedicated last parity disk)",	    1, 2, 5,  ALGORITHM_PARITY_N},
	{"raid5_ls",	  "raid5 (left symmetric)",		    1, 2, 5,  ALGORITHM_LEFT_SYMMETRIC},
	{"raid5_rs",	  "raid5 (right symmetric)",		    1, 2, 5,  ALGORITHM_RIGHT_SYMMETRIC},
@@ -2087,11 +2087,11 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
		/*
		 * No takeover/reshaping, because we don't have the extended v1.9.0 metadata
		 */
		if (le32_to_cpu(sb->level) != mddev->level) {
		if (le32_to_cpu(sb->level) != mddev->new_level) {
			DMERR("Reshaping/takeover raid sets not yet supported. (raid level/stripes/size change)");
			return -EINVAL;
		}
		if (le32_to_cpu(sb->layout) != mddev->layout) {
		if (le32_to_cpu(sb->layout) != mddev->new_layout) {
			DMERR("Reshaping raid sets not yet supported. (raid layout change)");
			DMERR("	 0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout);
			DMERR("	 Old layout: %s w/ %d copies",
@@ -2102,7 +2102,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
			      raid10_md_layout_to_copies(mddev->layout));
			return -EINVAL;
		}
		if (le32_to_cpu(sb->stripe_sectors) != mddev->chunk_sectors) {
		if (le32_to_cpu(sb->stripe_sectors) != mddev->new_chunk_sectors) {
			DMERR("Reshaping raid sets not yet supported. (stripe sectors change)");
			return -EINVAL;
		}
@@ -2115,6 +2115,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
			return -EINVAL;
		}

		DMINFO("Discovered old metadata format; upgrading to extended metadata format");

		/* Table line is checked vs. authoritative superblock */
		rs_set_new(rs);
	}
@@ -2258,7 +2260,8 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
	if (!mddev->events && super_init_validation(rs, rdev))
		return -EINVAL;

	if (le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) {
	if (le32_to_cpu(sb->compat_features) &&
	    le32_to_cpu(sb->compat_features) != FEATURE_FLAG_SUPPORTS_V190) {
		rs->ti->error = "Unable to assemble array: Unknown flag(s) in compatible feature flags";
		return -EINVAL;
	}
@@ -3646,7 +3649,7 @@ static void raid_resume(struct dm_target *ti)

static struct target_type raid_target = {
	.name = "raid",
	.version = {1, 9, 0},
	.version = {1, 9, 1},
	.module = THIS_MODULE,
	.ctr = raid_ctr,
	.dtr = raid_dtr,
+3 −19
Original line number Diff line number Diff line
@@ -145,7 +145,6 @@ static void dispatch_bios(void *context, struct bio_list *bio_list)

struct dm_raid1_bio_record {
	struct mirror *m;
	/* if details->bi_bdev == NULL, details were not saved */
	struct dm_bio_details details;
	region_t write_region;
};
@@ -1200,8 +1199,6 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)
	struct dm_raid1_bio_record *bio_record =
	  dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));

	bio_record->details.bi_bdev = NULL;

	if (rw == WRITE) {
		/* Save region for mirror_end_io() handler */
		bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio);
@@ -1260,22 +1257,12 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
	}

	if (error == -EOPNOTSUPP)
		goto out;
		return error;

	if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
		goto out;
		return error;

	if (unlikely(error)) {
		if (!bio_record->details.bi_bdev) {
			/*
			 * There wasn't enough memory to record necessary
			 * information for a retry or there was no other
			 * mirror in-sync.
			 */
			DMERR_LIMIT("Mirror read failed.");
			return -EIO;
		}

		m = bio_record->m;

		DMERR("Mirror read failed from %s. Trying alternative device.",
@@ -1291,7 +1278,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
			bd = &bio_record->details;

			dm_bio_restore(bd, bio);
			bio_record->details.bi_bdev = NULL;
			bio->bi_error = 0;

			queue_bio(ms, bio, rw);
			return DM_ENDIO_INCOMPLETE;
@@ -1299,9 +1286,6 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
		DMERR("All replicated volumes dead, failing I/O");
	}

out:
	bio_record->details.bi_bdev = NULL;

	return error;
}

+5 −2
Original line number Diff line number Diff line
@@ -856,8 +856,11 @@ int dm_old_init_request_queue(struct mapped_device *md)
	kthread_init_worker(&md->kworker);
	md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker,
				       "kdmwork-%s", dm_device_name(md));
	if (IS_ERR(md->kworker_task))
		return PTR_ERR(md->kworker_task);
	if (IS_ERR(md->kworker_task)) {
		int error = PTR_ERR(md->kworker_task);
		md->kworker_task = NULL;
		return error;
	}

	elv_register_queue(md->queue);

+9 −15
Original line number Diff line number Diff line
@@ -695,37 +695,32 @@ int dm_table_add_target(struct dm_table *t, const char *type,

	tgt->type = dm_get_target_type(type);
	if (!tgt->type) {
		DMERR("%s: %s: unknown target type", dm_device_name(t->md),
		      type);
		DMERR("%s: %s: unknown target type", dm_device_name(t->md), type);
		return -EINVAL;
	}

	if (dm_target_needs_singleton(tgt->type)) {
		if (t->num_targets) {
			DMERR("%s: target type %s must appear alone in table",
			      dm_device_name(t->md), type);
			return -EINVAL;
			tgt->error = "singleton target type must appear alone in table";
			goto bad;
		}
		t->singleton = true;
	}

	if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) {
		DMERR("%s: target type %s may not be included in read-only tables",
		      dm_device_name(t->md), type);
		return -EINVAL;
		tgt->error = "target type may not be included in a read-only table";
		goto bad;
	}

	if (t->immutable_target_type) {
		if (t->immutable_target_type != tgt->type) {
			DMERR("%s: immutable target type %s cannot be mixed with other target types",
			      dm_device_name(t->md), t->immutable_target_type->name);
			return -EINVAL;
			tgt->error = "immutable target type cannot be mixed with other target types";
			goto bad;
		}
	} else if (dm_target_is_immutable(tgt->type)) {
		if (t->num_targets) {
			DMERR("%s: immutable target type %s cannot be mixed with other target types",
			      dm_device_name(t->md), tgt->type->name);
			return -EINVAL;
			tgt->error = "immutable target type cannot be mixed with other target types";
			goto bad;
		}
		t->immutable_target_type = tgt->type;
	}
@@ -740,7 +735,6 @@ int dm_table_add_target(struct dm_table *t, const char *type,
	 */
	if (!adjoin(t, tgt)) {
		tgt->error = "Gap in table";
		r = -EINVAL;
		goto bad;
	}

Loading