Commit 5d0edf29 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dm-3.3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm

Pull device-mapper fixes for 3.3 from Alasdair Kergon

Eight small device-mapper bug fixes.

* tag 'dm-3.3-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm:
  dm raid: fix flush support
  dm raid: set MD_CHANGE_DEVS when rebuilding
  dm thin metadata: decrement counter after removing mapped block
  dm thin metadata: unlock superblock in init_pmd error path
  dm thin metadata: remove incorrect close_device on creation error paths
  dm flakey: fix crash on read when corrupt_bio_byte not set
  dm io: fix discard support
  dm ioctl: do not leak argv if target message only contains whitespace
parents 4f262acf 0ca93de9
...@@ -323,7 +323,7 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, ...@@ -323,7 +323,7 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio,
* Corrupt successful READs while in down state. * Corrupt successful READs while in down state.
* If flags were specified, only corrupt those that match. * If flags were specified, only corrupt those that match.
*/ */
if (!error && bio_submitted_while_down && if (fc->corrupt_bio_byte && !error && bio_submitted_while_down &&
(bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) && (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
all_corrupt_bio_flags_match(bio, fc)) all_corrupt_bio_flags_match(bio, fc))
corrupt_bio_data(bio, fc); corrupt_bio_data(bio, fc);
......
...@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -296,6 +296,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
unsigned offset; unsigned offset;
unsigned num_bvecs; unsigned num_bvecs;
sector_t remaining = where->count; sector_t remaining = where->count;
struct request_queue *q = bdev_get_queue(where->bdev);
sector_t discard_sectors;
/* /*
* where->count may be zero if rw holds a flush and we need to * where->count may be zero if rw holds a flush and we need to
...@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -305,9 +307,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
/* /*
* Allocate a suitably sized-bio. * Allocate a suitably sized-bio.
*/ */
num_bvecs = dm_sector_div_up(remaining, if (rw & REQ_DISCARD)
(PAGE_SIZE >> SECTOR_SHIFT)); num_bvecs = 1;
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev), num_bvecs); else
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT)));
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining); bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev; bio->bi_bdev = where->bdev;
...@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, ...@@ -315,10 +320,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
bio->bi_destructor = dm_bio_destructor; bio->bi_destructor = dm_bio_destructor;
store_io_and_region_in_bio(bio, io, region); store_io_and_region_in_bio(bio, io, region);
if (rw & REQ_DISCARD) {
discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
bio->bi_size = discard_sectors << SECTOR_SHIFT;
remaining -= discard_sectors;
} else while (remaining) {
/* /*
* Try and add as many pages as possible. * Try and add as many pages as possible.
*/ */
while (remaining) {
dp->get_page(dp, &page, &len, &offset); dp->get_page(dp, &page, &len, &offset);
len = min(len, to_bytes(remaining)); len = min(len, to_bytes(remaining));
if (!bio_add_page(bio, page, len, offset)) if (!bio_add_page(bio, page, len, offset))
......
...@@ -1437,7 +1437,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size) ...@@ -1437,7 +1437,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (!argc) { if (!argc) {
DMWARN("Empty message received."); DMWARN("Empty message received.");
goto out; goto out_argv;
} }
table = dm_get_live_table(md); table = dm_get_live_table(md);
......
...@@ -668,7 +668,14 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev) ...@@ -668,7 +668,14 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
return ret; return ret;
sb = page_address(rdev->sb_page); sb = page_address(rdev->sb_page);
if (sb->magic != cpu_to_le32(DM_RAID_MAGIC)) {
/*
* Two cases that we want to write new superblocks and rebuild:
* 1) New device (no matching magic number)
* 2) Device specified for rebuild (!In_sync w/ offset == 0)
*/
if ((sb->magic != cpu_to_le32(DM_RAID_MAGIC)) ||
(!test_bit(In_sync, &rdev->flags) && !rdev->recovery_offset)) {
super_sync(rdev->mddev, rdev); super_sync(rdev->mddev, rdev);
set_bit(FirstUse, &rdev->flags); set_bit(FirstUse, &rdev->flags);
...@@ -745,11 +752,8 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev) ...@@ -745,11 +752,8 @@ static int super_init_validation(struct mddev *mddev, struct md_rdev *rdev)
*/ */
rdev_for_each(r, t, mddev) { rdev_for_each(r, t, mddev) {
if (!test_bit(In_sync, &r->flags)) { if (!test_bit(In_sync, &r->flags)) {
if (!test_bit(FirstUse, &r->flags)) DMINFO("Device %d specified for rebuild: "
DMERR("Superblock area of " "Clearing superblock", r->raid_disk);
"rebuild device %d should have been "
"cleared.", r->raid_disk);
set_bit(FirstUse, &r->flags);
rebuilds++; rebuilds++;
} else if (test_bit(FirstUse, &r->flags)) } else if (test_bit(FirstUse, &r->flags))
new_devs++; new_devs++;
...@@ -971,6 +975,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -971,6 +975,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
INIT_WORK(&rs->md.event_work, do_table_event); INIT_WORK(&rs->md.event_work, do_table_event);
ti->private = rs; ti->private = rs;
ti->num_flush_requests = 1;
mutex_lock(&rs->md.reconfig_mutex); mutex_lock(&rs->md.reconfig_mutex);
ret = md_run(&rs->md); ret = md_run(&rs->md);
......
...@@ -385,6 +385,7 @@ static int init_pmd(struct dm_pool_metadata *pmd, ...@@ -385,6 +385,7 @@ static int init_pmd(struct dm_pool_metadata *pmd,
data_sm = dm_sm_disk_create(tm, nr_blocks); data_sm = dm_sm_disk_create(tm, nr_blocks);
if (IS_ERR(data_sm)) { if (IS_ERR(data_sm)) {
DMERR("sm_disk_create failed"); DMERR("sm_disk_create failed");
dm_tm_unlock(tm, sblock);
r = PTR_ERR(data_sm); r = PTR_ERR(data_sm);
goto bad; goto bad;
} }
...@@ -789,6 +790,11 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd) ...@@ -789,6 +790,11 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
return 0; return 0;
} }
/*
* __open_device: Returns @td corresponding to device with id @dev,
* creating it if @create is set and incrementing @td->open_count.
* On failure, @td is undefined.
*/
static int __open_device(struct dm_pool_metadata *pmd, static int __open_device(struct dm_pool_metadata *pmd,
dm_thin_id dev, int create, dm_thin_id dev, int create,
struct dm_thin_device **td) struct dm_thin_device **td)
...@@ -799,10 +805,16 @@ static int __open_device(struct dm_pool_metadata *pmd, ...@@ -799,10 +805,16 @@ static int __open_device(struct dm_pool_metadata *pmd,
struct disk_device_details details_le; struct disk_device_details details_le;
/* /*
* Check the device isn't already open. * If the device is already open, return it.
*/ */
list_for_each_entry(td2, &pmd->thin_devices, list) list_for_each_entry(td2, &pmd->thin_devices, list)
if (td2->id == dev) { if (td2->id == dev) {
/*
* May not create an already-open device.
*/
if (create)
return -EEXIST;
td2->open_count++; td2->open_count++;
*td = td2; *td = td2;
return 0; return 0;
...@@ -817,6 +829,9 @@ static int __open_device(struct dm_pool_metadata *pmd, ...@@ -817,6 +829,9 @@ static int __open_device(struct dm_pool_metadata *pmd,
if (r != -ENODATA || !create) if (r != -ENODATA || !create)
return r; return r;
/*
* Create new device.
*/
changed = 1; changed = 1;
details_le.mapped_blocks = 0; details_le.mapped_blocks = 0;
details_le.transaction_id = cpu_to_le64(pmd->trans_id); details_le.transaction_id = cpu_to_le64(pmd->trans_id);
...@@ -882,12 +897,10 @@ static int __create_thin(struct dm_pool_metadata *pmd, ...@@ -882,12 +897,10 @@ static int __create_thin(struct dm_pool_metadata *pmd,
r = __open_device(pmd, dev, 1, &td); r = __open_device(pmd, dev, 1, &td);
if (r) { if (r) {
__close_device(td);
dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root); dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
dm_btree_del(&pmd->bl_info, dev_root); dm_btree_del(&pmd->bl_info, dev_root);
return r; return r;
} }
td->changed = 1;
__close_device(td); __close_device(td);
return r; return r;
...@@ -967,14 +980,14 @@ static int __create_snap(struct dm_pool_metadata *pmd, ...@@ -967,14 +980,14 @@ static int __create_snap(struct dm_pool_metadata *pmd,
goto bad; goto bad;
r = __set_snapshot_details(pmd, td, origin, pmd->time); r = __set_snapshot_details(pmd, td, origin, pmd->time);
__close_device(td);
if (r) if (r)
goto bad; goto bad;
__close_device(td);
return 0; return 0;
bad: bad:
__close_device(td);
dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root); dm_btree_remove(&pmd->tl_info, pmd->root, &key, &pmd->root);
dm_btree_remove(&pmd->details_info, pmd->details_root, dm_btree_remove(&pmd->details_info, pmd->details_root,
&key, &pmd->details_root); &key, &pmd->details_root);
...@@ -1211,6 +1224,8 @@ static int __remove(struct dm_thin_device *td, dm_block_t block) ...@@ -1211,6 +1224,8 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
if (r) if (r)
return r; return r;
td->mapped_blocks--;
td->changed = 1;
pmd->need_commit = 1; pmd->need_commit = 1;
return 0; return 0;
......
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