mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
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+). -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJTY+6+AAoJEMUj8QotnQNaeC4H/35S9GZL8SVPEDS5nbQ9YdZ9 co7wAYIGswOInX9u8nq0TqcNtBMhxwwdRX9ScPxHVUTT+/lM/c7axHiMqVjZrMme SVmmAXMp2uUMAnK4BGIQs8jjeyxBCHUF/gyfC3OC+RF72Z1bDkG/xXyKsljBSzMe RP0iFvvvA1Sm7XzBJRuhZLIdJGkXFAy0ooEBICQOoudg6iDvDKCtiU+owB/x4bBh xi9b1MY2VjkobWES6fyW/atolCEpgwU4xhsLl3w534P9oFvCkLEp4GTxdFWBhepl K3usGr0t1QhmHy1hKw++WGsAkMRHocf8nIBqxxdDNWpZvOif2z+weLYbOn+TXTM= =1Yvj -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
54366a7fd6
@ -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))
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
@ -1486,6 +1493,45 @@ 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;
|
||||
@ -1493,10 +1539,11 @@ static void process_deferred_bios(struct pool *pool)
|
||||
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
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
@ -330,15 +330,17 @@ test_block_hash:
|
||||
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) {
|
||||
@ -346,8 +348,9 @@ test_block_hash:
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user