Commit e0f3e6a7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dm-4.9-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

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
...@@ -309,3 +309,4 @@ Version History ...@@ -309,3 +309,4 @@ Version History
with a reshape in progress. with a reshape in progress.
1.9.0 Add support for RAID level takeover/reshape/region size 1.9.0 Add support for RAID level takeover/reshape/region size
and set size reduction. and set size reduction.
1.9.1 Fix activation of existing RAID 4/10 mapped devices
...@@ -266,7 +266,7 @@ static struct raid_type { ...@@ -266,7 +266,7 @@ static struct raid_type {
{"raid10_offset", "raid10 offset (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_OFFSET}, {"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_near", "raid10 near (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_NEAR},
{"raid10", "raid10 (striped mirrors)", 0, 2, 10, ALGORITHM_RAID10_DEFAULT}, {"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_n", "raid5 (dedicated last parity disk)", 1, 2, 5, ALGORITHM_PARITY_N},
{"raid5_ls", "raid5 (left symmetric)", 1, 2, 5, ALGORITHM_LEFT_SYMMETRIC}, {"raid5_ls", "raid5 (left symmetric)", 1, 2, 5, ALGORITHM_LEFT_SYMMETRIC},
{"raid5_rs", "raid5 (right symmetric)", 1, 2, 5, ALGORITHM_RIGHT_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) ...@@ -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 * 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)"); DMERR("Reshaping/takeover raid sets not yet supported. (raid level/stripes/size change)");
return -EINVAL; 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("Reshaping raid sets not yet supported. (raid layout change)");
DMERR(" 0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout); DMERR(" 0x%X vs 0x%X", le32_to_cpu(sb->layout), mddev->layout);
DMERR(" Old layout: %s w/ %d copies", DMERR(" Old layout: %s w/ %d copies",
...@@ -2102,7 +2102,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) ...@@ -2102,7 +2102,7 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
raid10_md_layout_to_copies(mddev->layout)); raid10_md_layout_to_copies(mddev->layout));
return -EINVAL; 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)"); DMERR("Reshaping raid sets not yet supported. (stripe sectors change)");
return -EINVAL; return -EINVAL;
} }
...@@ -2115,6 +2115,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev) ...@@ -2115,6 +2115,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
return -EINVAL; return -EINVAL;
} }
DMINFO("Discovered old metadata format; upgrading to extended metadata format");
/* Table line is checked vs. authoritative superblock */ /* Table line is checked vs. authoritative superblock */
rs_set_new(rs); rs_set_new(rs);
} }
...@@ -2258,7 +2260,8 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev) ...@@ -2258,7 +2260,8 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
if (!mddev->events && super_init_validation(rs, rdev)) if (!mddev->events && super_init_validation(rs, rdev))
return -EINVAL; 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"; rs->ti->error = "Unable to assemble array: Unknown flag(s) in compatible feature flags";
return -EINVAL; return -EINVAL;
} }
...@@ -3646,7 +3649,7 @@ static void raid_resume(struct dm_target *ti) ...@@ -3646,7 +3649,7 @@ static void raid_resume(struct dm_target *ti)
static struct target_type raid_target = { static struct target_type raid_target = {
.name = "raid", .name = "raid",
.version = {1, 9, 0}, .version = {1, 9, 1},
.module = THIS_MODULE, .module = THIS_MODULE,
.ctr = raid_ctr, .ctr = raid_ctr,
.dtr = raid_dtr, .dtr = raid_dtr,
......
...@@ -145,7 +145,6 @@ static void dispatch_bios(void *context, struct bio_list *bio_list) ...@@ -145,7 +145,6 @@ static void dispatch_bios(void *context, struct bio_list *bio_list)
struct dm_raid1_bio_record { struct dm_raid1_bio_record {
struct mirror *m; struct mirror *m;
/* if details->bi_bdev == NULL, details were not saved */
struct dm_bio_details details; struct dm_bio_details details;
region_t write_region; region_t write_region;
}; };
...@@ -1200,8 +1199,6 @@ static int mirror_map(struct dm_target *ti, struct bio *bio) ...@@ -1200,8 +1199,6 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)
struct dm_raid1_bio_record *bio_record = struct dm_raid1_bio_record *bio_record =
dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record)); dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));
bio_record->details.bi_bdev = NULL;
if (rw == WRITE) { if (rw == WRITE) {
/* Save region for mirror_end_io() handler */ /* Save region for mirror_end_io() handler */
bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio); 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) ...@@ -1260,22 +1257,12 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
} }
if (error == -EOPNOTSUPP) if (error == -EOPNOTSUPP)
goto out; return error;
if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD)) if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
goto out; return error;
if (unlikely(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; m = bio_record->m;
DMERR("Mirror read failed from %s. Trying alternative device.", 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) ...@@ -1291,7 +1278,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
bd = &bio_record->details; bd = &bio_record->details;
dm_bio_restore(bd, bio); dm_bio_restore(bd, bio);
bio_record->details.bi_bdev = NULL; bio->bi_error = 0;
queue_bio(ms, bio, rw); queue_bio(ms, bio, rw);
return DM_ENDIO_INCOMPLETE; return DM_ENDIO_INCOMPLETE;
...@@ -1299,9 +1286,6 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) ...@@ -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"); DMERR("All replicated volumes dead, failing I/O");
} }
out:
bio_record->details.bi_bdev = NULL;
return error; return error;
} }
......
...@@ -856,8 +856,11 @@ int dm_old_init_request_queue(struct mapped_device *md) ...@@ -856,8 +856,11 @@ int dm_old_init_request_queue(struct mapped_device *md)
kthread_init_worker(&md->kworker); kthread_init_worker(&md->kworker);
md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker, md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker,
"kdmwork-%s", dm_device_name(md)); "kdmwork-%s", dm_device_name(md));
if (IS_ERR(md->kworker_task)) if (IS_ERR(md->kworker_task)) {
return PTR_ERR(md->kworker_task); int error = PTR_ERR(md->kworker_task);
md->kworker_task = NULL;
return error;
}
elv_register_queue(md->queue); elv_register_queue(md->queue);
......
...@@ -695,37 +695,32 @@ int dm_table_add_target(struct dm_table *t, const char *type, ...@@ -695,37 +695,32 @@ int dm_table_add_target(struct dm_table *t, const char *type,
tgt->type = dm_get_target_type(type); tgt->type = dm_get_target_type(type);
if (!tgt->type) { if (!tgt->type) {
DMERR("%s: %s: unknown target type", dm_device_name(t->md), DMERR("%s: %s: unknown target type", dm_device_name(t->md), type);
type);
return -EINVAL; return -EINVAL;
} }
if (dm_target_needs_singleton(tgt->type)) { if (dm_target_needs_singleton(tgt->type)) {
if (t->num_targets) { if (t->num_targets) {
DMERR("%s: target type %s must appear alone in table", tgt->error = "singleton target type must appear alone in table";
dm_device_name(t->md), type); goto bad;
return -EINVAL;
} }
t->singleton = true; t->singleton = true;
} }
if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) { if (dm_target_always_writeable(tgt->type) && !(t->mode & FMODE_WRITE)) {
DMERR("%s: target type %s may not be included in read-only tables", tgt->error = "target type may not be included in a read-only table";
dm_device_name(t->md), type); goto bad;
return -EINVAL;
} }
if (t->immutable_target_type) { if (t->immutable_target_type) {
if (t->immutable_target_type != tgt->type) { if (t->immutable_target_type != tgt->type) {
DMERR("%s: immutable target type %s cannot be mixed with other target types", tgt->error = "immutable target type cannot be mixed with other target types";
dm_device_name(t->md), t->immutable_target_type->name); goto bad;
return -EINVAL;
} }
} else if (dm_target_is_immutable(tgt->type)) { } else if (dm_target_is_immutable(tgt->type)) {
if (t->num_targets) { if (t->num_targets) {
DMERR("%s: immutable target type %s cannot be mixed with other target types", tgt->error = "immutable target type cannot be mixed with other target types";
dm_device_name(t->md), tgt->type->name); goto bad;
return -EINVAL;
} }
t->immutable_target_type = tgt->type; t->immutable_target_type = tgt->type;
} }
...@@ -740,7 +735,6 @@ int dm_table_add_target(struct dm_table *t, const char *type, ...@@ -740,7 +735,6 @@ int dm_table_add_target(struct dm_table *t, const char *type,
*/ */
if (!adjoin(t, tgt)) { if (!adjoin(t, tgt)) {
tgt->error = "Gap in table"; tgt->error = "Gap in table";
r = -EINVAL;
goto bad; goto bad;
} }
......
...@@ -1423,8 +1423,6 @@ static void cleanup_mapped_device(struct mapped_device *md) ...@@ -1423,8 +1423,6 @@ static void cleanup_mapped_device(struct mapped_device *md)
if (md->bs) if (md->bs)
bioset_free(md->bs); bioset_free(md->bs);
cleanup_srcu_struct(&md->io_barrier);
if (md->disk) { if (md->disk) {
spin_lock(&_minor_lock); spin_lock(&_minor_lock);
md->disk->private_data = NULL; md->disk->private_data = NULL;
...@@ -1436,6 +1434,8 @@ static void cleanup_mapped_device(struct mapped_device *md) ...@@ -1436,6 +1434,8 @@ static void cleanup_mapped_device(struct mapped_device *md)
if (md->queue) if (md->queue)
blk_cleanup_queue(md->queue); blk_cleanup_queue(md->queue);
cleanup_srcu_struct(&md->io_barrier);
if (md->bdev) { if (md->bdev) {
bdput(md->bdev); bdput(md->bdev);
md->bdev = NULL; md->bdev = 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