Skip to content

Commit

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

Pull device mapper fixes from Mike Snitzer:
 "A few dm-thinp fixes for changes merged in 3.15-rc1.

  A dm-verity fix for an immutable biovec regression that affects 3.14+.

  A dm-cache fix to properly quiesce when using writethrough mode (3.14+)"

* tag 'dm-3.15-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm cache: fix writethrough mode quiescing in cache_map
  dm thin: use INIT_WORK_ONSTACK in noflush_work to avoid ODEBUG warning
  dm verity: fix biovecs hash calculation regression
  dm thin: fix rcu_read_lock being held in code that can sleep
  dm thin: irqsave must always be used with the pool->lock spinlock
  • Loading branch information
Linus Torvalds committed May 2, 2014
2 parents 0845e11 + 131cd13 commit 54366a7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 12 deletions.
1 change: 1 addition & 0 deletions drivers/md/dm-cache-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -2488,6 +2488,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)

} else {
inc_hit_counter(cache, bio);
pb->all_io_entry = dm_deferred_entry_inc(cache->all_io_ds);

if (bio_data_dir(bio) == WRITE && writethrough_mode(&cache->features) &&
!is_dirty(cache, lookup_result.cblock))
Expand Down
77 changes: 71 additions & 6 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,13 @@ struct thin_c {
struct bio_list deferred_bio_list;
struct bio_list retry_on_resume_list;
struct rb_root sort_bio_list; /* sorted list of deferred bios */

/*
* Ensures the thin is not destroyed until the worker has finished
* iterating the active_thins list.
*/
atomic_t refcount;
struct completion can_destroy;
};

/*----------------------------------------------------------------*/
Expand Down Expand Up @@ -1486,17 +1493,57 @@ static void process_thin_deferred_bios(struct thin_c *tc)
blk_finish_plug(&plug);
}

static void thin_get(struct thin_c *tc);
static void thin_put(struct thin_c *tc);

/*
* We can't hold rcu_read_lock() around code that can block. So we
* find a thin with the rcu lock held; bump a refcount; then drop
* the lock.
*/
static struct thin_c *get_first_thin(struct pool *pool)
{
struct thin_c *tc = NULL;

rcu_read_lock();
if (!list_empty(&pool->active_thins)) {
tc = list_entry_rcu(pool->active_thins.next, struct thin_c, list);
thin_get(tc);
}
rcu_read_unlock();

return tc;
}

static struct thin_c *get_next_thin(struct pool *pool, struct thin_c *tc)
{
struct thin_c *old_tc = tc;

rcu_read_lock();
list_for_each_entry_continue_rcu(tc, &pool->active_thins, list) {
thin_get(tc);
thin_put(old_tc);
rcu_read_unlock();
return tc;
}
thin_put(old_tc);
rcu_read_unlock();

return NULL;
}

static void process_deferred_bios(struct pool *pool)
{
unsigned long flags;
struct bio *bio;
struct bio_list bios;
struct thin_c *tc;

rcu_read_lock();
list_for_each_entry_rcu(tc, &pool->active_thins, list)
tc = get_first_thin(pool);
while (tc) {
process_thin_deferred_bios(tc);
rcu_read_unlock();
tc = get_next_thin(pool, tc);
}

/*
* If there are any deferred flush bios, we must commit
Expand Down Expand Up @@ -1578,7 +1625,7 @@ static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
{
struct noflush_work w;

INIT_WORK(&w.worker, fn);
INIT_WORK_ONSTACK(&w.worker, fn);
w.tc = tc;
atomic_set(&w.complete, 0);
init_waitqueue_head(&w.wait);
Expand Down Expand Up @@ -3061,11 +3108,25 @@ static struct target_type pool_target = {
/*----------------------------------------------------------------
* Thin target methods
*--------------------------------------------------------------*/
static void thin_get(struct thin_c *tc)
{
atomic_inc(&tc->refcount);
}

static void thin_put(struct thin_c *tc)
{
if (atomic_dec_and_test(&tc->refcount))
complete(&tc->can_destroy);
}

static void thin_dtr(struct dm_target *ti)
{
struct thin_c *tc = ti->private;
unsigned long flags;

thin_put(tc);
wait_for_completion(&tc->can_destroy);

spin_lock_irqsave(&tc->pool->lock, flags);
list_del_rcu(&tc->list);
spin_unlock_irqrestore(&tc->pool->lock, flags);
Expand Down Expand Up @@ -3101,6 +3162,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct thin_c *tc;
struct dm_dev *pool_dev, *origin_dev;
struct mapped_device *pool_md;
unsigned long flags;

mutex_lock(&dm_thin_pool_table.mutex);

Expand Down Expand Up @@ -3191,9 +3253,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)

mutex_unlock(&dm_thin_pool_table.mutex);

spin_lock(&tc->pool->lock);
atomic_set(&tc->refcount, 1);
init_completion(&tc->can_destroy);

spin_lock_irqsave(&tc->pool->lock, flags);
list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
spin_unlock(&tc->pool->lock);
spin_unlock_irqrestore(&tc->pool->lock, flags);
/*
* This synchronize_rcu() call is needed here otherwise we risk a
* wake_worker() call finding no bios to process (because the newly
Expand Down
15 changes: 9 additions & 6 deletions drivers/md/dm-verity.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,24 +330,27 @@ static int verity_verify_io(struct dm_verity_io *io)
return r;
}
}

todo = 1 << v->data_dev_block_bits;
while (io->iter.bi_size) {
do {
u8 *page;
unsigned len;
struct bio_vec bv = bio_iter_iovec(bio, io->iter);

page = kmap_atomic(bv.bv_page);
r = crypto_shash_update(desc, page + bv.bv_offset,
bv.bv_len);
len = bv.bv_len;
if (likely(len >= todo))
len = todo;
r = crypto_shash_update(desc, page + bv.bv_offset, len);
kunmap_atomic(page);

if (r < 0) {
DMERR("crypto_shash_update failed: %d", r);
return r;
}

bio_advance_iter(bio, &io->iter, bv.bv_len);
}
bio_advance_iter(bio, &io->iter, len);
todo -= len;
} while (todo);

if (!v->version) {
r = crypto_shash_update(desc, v->salt, v->salt_size);
Expand Down

0 comments on commit 54366a7

Please sign in to comment.