Skip to content

Commit

Permalink
Merge tag 'for-5.0/dm-fixes-3' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

 - Fix bug in DM crypt's sizing of its block integrity tag space,
   resulting in less memory use when DM crypt layers on DM integrity.

 - Fix a long-standing DM thinp crash consistency bug that was due to
   improper handling of FUA. This issue is specific to writes that fill
   an entire thinp block which needs to be allocated.

* tag 'for-5.0/dm-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm thin: fix bug where bio that overwrites thin block ignores FUA
  dm crypt: don't overallocate the integrity tag space
  • Loading branch information
Linus Torvalds committed Feb 15, 2019
2 parents dfeae33 + 4ae280b commit ae3fa8b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
2 changes: 1 addition & 1 deletion drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ static int dm_crypt_integrity_io_alloc(struct dm_crypt_io *io, struct bio *bio)
if (IS_ERR(bip))
return PTR_ERR(bip);

tag_len = io->cc->on_disk_tag_size * bio_sectors(bio);
tag_len = io->cc->on_disk_tag_size * (bio_sectors(bio) >> io->cc->sector_shift);

bip->bip_iter.bi_size = tag_len;
bip->bip_iter.bi_sector = io->cc->start + io->sector;
Expand Down
55 changes: 50 additions & 5 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ struct pool {

spinlock_t lock;
struct bio_list deferred_flush_bios;
struct bio_list deferred_flush_completions;
struct list_head prepared_mappings;
struct list_head prepared_discards;
struct list_head prepared_discards_pt2;
Expand Down Expand Up @@ -956,6 +957,39 @@ static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
mempool_free(m, &m->tc->pool->mapping_pool);
}

static void complete_overwrite_bio(struct thin_c *tc, struct bio *bio)
{
struct pool *pool = tc->pool;
unsigned long flags;

/*
* If the bio has the REQ_FUA flag set we must commit the metadata
* before signaling its completion.
*/
if (!bio_triggers_commit(tc, bio)) {
bio_endio(bio);
return;
}

/*
* Complete bio with an error if earlier I/O caused changes to the
* metadata that can't be committed, e.g, due to I/O errors on the
* metadata device.
*/
if (dm_thin_aborted_changes(tc->td)) {
bio_io_error(bio);
return;
}

/*
* Batch together any bios that trigger commits and then issue a
* single commit for them in process_deferred_bios().
*/
spin_lock_irqsave(&pool->lock, flags);
bio_list_add(&pool->deferred_flush_completions, bio);
spin_unlock_irqrestore(&pool->lock, flags);
}

static void process_prepared_mapping(struct dm_thin_new_mapping *m)
{
struct thin_c *tc = m->tc;
Expand Down Expand Up @@ -988,7 +1022,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
*/
if (bio) {
inc_remap_and_issue_cell(tc, m->cell, m->data_block);
bio_endio(bio);
complete_overwrite_bio(tc, bio);
} else {
inc_all_io_entry(tc->pool, m->cell->holder);
remap_and_issue(tc, m->cell->holder, m->data_block);
Expand Down Expand Up @@ -2317,7 +2351,7 @@ static void process_deferred_bios(struct pool *pool)
{
unsigned long flags;
struct bio *bio;
struct bio_list bios;
struct bio_list bios, bio_completions;
struct thin_c *tc;

tc = get_first_thin(pool);
Expand All @@ -2328,26 +2362,36 @@ static void process_deferred_bios(struct pool *pool)
}

/*
* If there are any deferred flush bios, we must commit
* the metadata before issuing them.
* If there are any deferred flush bios, we must commit the metadata
* before issuing them or signaling their completion.
*/
bio_list_init(&bios);
bio_list_init(&bio_completions);

spin_lock_irqsave(&pool->lock, flags);
bio_list_merge(&bios, &pool->deferred_flush_bios);
bio_list_init(&pool->deferred_flush_bios);

bio_list_merge(&bio_completions, &pool->deferred_flush_completions);
bio_list_init(&pool->deferred_flush_completions);
spin_unlock_irqrestore(&pool->lock, flags);

if (bio_list_empty(&bios) &&
if (bio_list_empty(&bios) && bio_list_empty(&bio_completions) &&
!(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
return;

if (commit(pool)) {
bio_list_merge(&bios, &bio_completions);

while ((bio = bio_list_pop(&bios)))
bio_io_error(bio);
return;
}
pool->last_commit_jiffies = jiffies;

while ((bio = bio_list_pop(&bio_completions)))
bio_endio(bio);

while ((bio = bio_list_pop(&bios)))
generic_make_request(bio);
}
Expand Down Expand Up @@ -2954,6 +2998,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
INIT_DELAYED_WORK(&pool->no_space_timeout, do_no_space_timeout);
spin_lock_init(&pool->lock);
bio_list_init(&pool->deferred_flush_bios);
bio_list_init(&pool->deferred_flush_completions);
INIT_LIST_HEAD(&pool->prepared_mappings);
INIT_LIST_HEAD(&pool->prepared_discards);
INIT_LIST_HEAD(&pool->prepared_discards_pt2);
Expand Down

0 comments on commit ae3fa8b

Please sign in to comment.