aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-thin.c
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2012-05-11 20:43:16 -0400
committerAlasdair G Kergon <agk@redhat.com>2012-05-11 20:43:16 -0400
commitc3a0ce2eab76daf9516c817c3f227ea3f4549bd8 (patch)
treec2510a2e8a4a0f2c0eb66f736d1e1b70b53d0e27 /drivers/md/dm-thin.c
parent03aaae7cdc71bc306888440b1f569d463e917b6d (diff)
dm thin: fix unprotected use of prepared_discards list
Fix two places in commit 104655fd4dce ("dm thin: support discards") that didn't use pool->lock to protect against concurrent changes to the prepared_discards list. Without this fix, thin_endio() can race with process_discard(), leading to concurrent list_add()s that result in the processes locking up with an error like the following: WARNING: at lib/list_debug.c:32 __list_add+0x8f/0xa0() ... list_add corruption. next->prev should be prev (ffff880323b96140), but was ffff8801d2c48440. (next=ffff8801d2c485c0). ... Pid: 17205, comm: kworker/u:1 Tainted: G W O 3.4.0-rc3.snitm+ #1 Call Trace: [<ffffffff8103ca1f>] warn_slowpath_common+0x7f/0xc0 [<ffffffff8103cb16>] warn_slowpath_fmt+0x46/0x50 [<ffffffffa04f6ce6>] ? bio_detain+0xc6/0x210 [dm_thin_pool] [<ffffffff8124ff3f>] __list_add+0x8f/0xa0 [<ffffffffa04f70d2>] process_discard+0x2a2/0x2d0 [dm_thin_pool] [<ffffffffa04f6a78>] ? remap_and_issue+0x38/0x50 [dm_thin_pool] [<ffffffffa04f7c3b>] process_deferred_bios+0x7b/0x230 [dm_thin_pool] [<ffffffffa04f7df0>] ? process_deferred_bios+0x230/0x230 [dm_thin_pool] [<ffffffffa04f7e42>] do_worker+0x52/0x60 [dm_thin_pool] [<ffffffff81056fa9>] process_one_work+0x129/0x450 [<ffffffff81059b9c>] worker_thread+0x17c/0x3c0 [<ffffffff81059a20>] ? manage_workers+0x120/0x120 [<ffffffff8105eabe>] kthread+0x9e/0xb0 [<ffffffff814ceda4>] kernel_thread_helper+0x4/0x10 [<ffffffff8105ea20>] ? kthread_freezable_should_stop+0x70/0x70 [<ffffffff814ceda0>] ? gs_change+0x13/0x13 ---[ end trace 7e0a523bc5e52692 ]--- Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-thin.c')
-rw-r--r--drivers/md/dm-thin.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 301db0f45d3b..69a2d51ef4e1 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1180,6 +1180,7 @@ static void no_space(struct cell *cell)
1180static void process_discard(struct thin_c *tc, struct bio *bio) 1180static void process_discard(struct thin_c *tc, struct bio *bio)
1181{ 1181{
1182 int r; 1182 int r;
1183 unsigned long flags;
1183 struct pool *pool = tc->pool; 1184 struct pool *pool = tc->pool;
1184 struct cell *cell, *cell2; 1185 struct cell *cell, *cell2;
1185 struct cell_key key, key2; 1186 struct cell_key key, key2;
@@ -1221,7 +1222,9 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
1221 m->bio = bio; 1222 m->bio = bio;
1222 1223
1223 if (!ds_add_work(&pool->all_io_ds, &m->list)) { 1224 if (!ds_add_work(&pool->all_io_ds, &m->list)) {
1225 spin_lock_irqsave(&pool->lock, flags);
1224 list_add(&m->list, &pool->prepared_discards); 1226 list_add(&m->list, &pool->prepared_discards);
1227 spin_unlock_irqrestore(&pool->lock, flags);
1225 wake_worker(pool); 1228 wake_worker(pool);
1226 } 1229 }
1227 } else { 1230 } else {
@@ -2629,8 +2632,10 @@ static int thin_endio(struct dm_target *ti,
2629 if (h->all_io_entry) { 2632 if (h->all_io_entry) {
2630 INIT_LIST_HEAD(&work); 2633 INIT_LIST_HEAD(&work);
2631 ds_dec(h->all_io_entry, &work); 2634 ds_dec(h->all_io_entry, &work);
2635 spin_lock_irqsave(&pool->lock, flags);
2632 list_for_each_entry_safe(m, tmp, &work, list) 2636 list_for_each_entry_safe(m, tmp, &work, list)
2633 list_add(&m->list, &pool->prepared_discards); 2637 list_add(&m->list, &pool->prepared_discards);
2638 spin_unlock_irqrestore(&pool->lock, flags);
2634 } 2639 }
2635 2640
2636 mempool_free(h, pool->endio_hook_pool); 2641 mempool_free(h, pool->endio_hook_pool);