Commit 54366a7f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dm-3.15-fixes' of git://git.kernel.org/pub/scm/linux/kernel/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
parents 0845e11c 131cd131
...@@ -2488,6 +2488,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio) ...@@ -2488,6 +2488,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
} else { } else {
inc_hit_counter(cache, bio); 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) && if (bio_data_dir(bio) == WRITE && writethrough_mode(&cache->features) &&
!is_dirty(cache, lookup_result.cblock)) !is_dirty(cache, lookup_result.cblock))
......
...@@ -232,6 +232,13 @@ struct thin_c { ...@@ -232,6 +232,13 @@ struct thin_c {
struct bio_list deferred_bio_list; struct bio_list deferred_bio_list;
struct bio_list retry_on_resume_list; struct bio_list retry_on_resume_list;
struct rb_root sort_bio_list; /* sorted list of deferred bios */ 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;
}; };
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
...@@ -1486,6 +1493,45 @@ static void process_thin_deferred_bios(struct thin_c *tc) ...@@ -1486,6 +1493,45 @@ static void process_thin_deferred_bios(struct thin_c *tc)
blk_finish_plug(&plug); 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) static void process_deferred_bios(struct pool *pool)
{ {
unsigned long flags; unsigned long flags;
...@@ -1493,10 +1539,11 @@ static void process_deferred_bios(struct pool *pool) ...@@ -1493,10 +1539,11 @@ static void process_deferred_bios(struct pool *pool)
struct bio_list bios; struct bio_list bios;
struct thin_c *tc; struct thin_c *tc;
rcu_read_lock(); tc = get_first_thin(pool);
list_for_each_entry_rcu(tc, &pool->active_thins, list) while (tc) {
process_thin_deferred_bios(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 * If there are any deferred flush bios, we must commit
...@@ -1578,7 +1625,7 @@ static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *)) ...@@ -1578,7 +1625,7 @@ static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
{ {
struct noflush_work w; struct noflush_work w;
INIT_WORK(&w.worker, fn); INIT_WORK_ONSTACK(&w.worker, fn);
w.tc = tc; w.tc = tc;
atomic_set(&w.complete, 0); atomic_set(&w.complete, 0);
init_waitqueue_head(&w.wait); init_waitqueue_head(&w.wait);
...@@ -3061,11 +3108,25 @@ static struct target_type pool_target = { ...@@ -3061,11 +3108,25 @@ static struct target_type pool_target = {
/*---------------------------------------------------------------- /*----------------------------------------------------------------
* Thin target methods * 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) static void thin_dtr(struct dm_target *ti)
{ {
struct thin_c *tc = ti->private; struct thin_c *tc = ti->private;
unsigned long flags; unsigned long flags;
thin_put(tc);
wait_for_completion(&tc->can_destroy);
spin_lock_irqsave(&tc->pool->lock, flags); spin_lock_irqsave(&tc->pool->lock, flags);
list_del_rcu(&tc->list); list_del_rcu(&tc->list);
spin_unlock_irqrestore(&tc->pool->lock, flags); spin_unlock_irqrestore(&tc->pool->lock, flags);
...@@ -3101,6 +3162,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -3101,6 +3162,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
struct thin_c *tc; struct thin_c *tc;
struct dm_dev *pool_dev, *origin_dev; struct dm_dev *pool_dev, *origin_dev;
struct mapped_device *pool_md; struct mapped_device *pool_md;
unsigned long flags;
mutex_lock(&dm_thin_pool_table.mutex); mutex_lock(&dm_thin_pool_table.mutex);
...@@ -3191,9 +3253,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) ...@@ -3191,9 +3253,12 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
mutex_unlock(&dm_thin_pool_table.mutex); 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); 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 * This synchronize_rcu() call is needed here otherwise we risk a
* wake_worker() call finding no bios to process (because the newly * wake_worker() call finding no bios to process (because the newly
......
...@@ -330,15 +330,17 @@ static int verity_verify_io(struct dm_verity_io *io) ...@@ -330,15 +330,17 @@ static int verity_verify_io(struct dm_verity_io *io)
return r; return r;
} }
} }
todo = 1 << v->data_dev_block_bits; todo = 1 << v->data_dev_block_bits;
while (io->iter.bi_size) { do {
u8 *page; u8 *page;
unsigned len;
struct bio_vec bv = bio_iter_iovec(bio, io->iter); struct bio_vec bv = bio_iter_iovec(bio, io->iter);
page = kmap_atomic(bv.bv_page); page = kmap_atomic(bv.bv_page);
r = crypto_shash_update(desc, page + bv.bv_offset, len = bv.bv_len;
bv.bv_len); if (likely(len >= todo))
len = todo;
r = crypto_shash_update(desc, page + bv.bv_offset, len);
kunmap_atomic(page); kunmap_atomic(page);
if (r < 0) { if (r < 0) {
...@@ -346,8 +348,9 @@ static int verity_verify_io(struct dm_verity_io *io) ...@@ -346,8 +348,9 @@ static int verity_verify_io(struct dm_verity_io *io)
return 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) { if (!v->version) {
r = crypto_shash_update(desc, v->salt, v->salt_size); r = crypto_shash_update(desc, v->salt, v->salt_size);
......
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