+++ /dev/null
-From: Chandra Seetharaman <sekharan@us.ibm.com>
-Subject: dm: avoid destroying table in dm_any_congested
-References: bnc#457205
-Patch-mainline: 2.6.28-rc4
-Signed-off-by: Nikanth Karthikesan <knikanth@suse.de>
-
-[PATCH 1/3] for bnc 457205. Even though this fix is almost
-reverted by 3rd patch in this series, this patch is used as it
-fixes a suble bug of calling dm_table_put only when dm_get_table
-succeeds. Also this makes code more inline with the mainline.
-
-mainline commit 8a57dfc6f943c92b861c9a19b0c86ddcb2aba768
-
- dm_any_congested() just checks for the DMF_BLOCK_IO and has no
- code to make sure that suspend waits for dm_any_congested() to
- complete. This patch adds such a check.
-
- Without it, a race can occur with dm_table_put() attempting to
- destroying the table in the wrong thread, the one running
- dm_any_congested() which is meant to be quick and return
- immediately.
-
- Two examples of problems:
- 1. Sleeping functions called from congested code, the caller
- of which holds a spin lock.
- 2. An ABBA deadlock between pdflush and multipathd. The two locks
- in contention are inode lock and kernel lock.
-
- Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
- Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
- Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-
-Index: linux-2.6.27/drivers/md/dm.c
-===================================================================
---- linux-2.6.27.orig/drivers/md/dm.c
-+++ linux-2.6.27/drivers/md/dm.c
-@@ -1640,22 +1640,32 @@ static void dm_unplug_all(struct request
-
- static int dm_any_congested(void *congested_data, int bdi_bits)
- {
-- int r;
-+ int r = bdi_bits;
- struct mapped_device *md = (struct mapped_device *) congested_data;
-- struct dm_table *map = dm_get_table(md);
-+ struct dm_table *map;
-
-- if (!map || test_bit(DMF_BLOCK_IO, &md->flags))
-- r = bdi_bits;
-- else if (dm_request_based(md))
-- /*
-- * Request-based dm cares about only own queue for
-- * the query about congestion status of request_queue
-- */
-- r = md->queue->backing_dev_info.state & bdi_bits;
-- else
-- r = dm_table_any_congested(map, bdi_bits);
-+ atomic_inc(&md->pending);
-+
-+ if (!test_bit(DMF_BLOCK_IO, &md->flags)) {
-+ map = dm_get_table(md);
-+ if (map) {
-+ if (dm_request_based(md))
-+ /*
-+ * Request-based dm cares about only own queue for
-+ * the query about congestion status of request_queue
-+ */
-+ r = md->queue->backing_dev_info.state & bdi_bits;
-+ else
-+ r = dm_table_any_congested(map, bdi_bits);
-+ dm_table_put(map);
-+ }
-+ }
-+
-+
-+ if (!atomic_dec_return(&md->pending))
-+ /* nudge anyone waiting on suspend queue */
-+ wake_up(&md->wait);
-
-- dm_table_put(map);
- return r;
- }
-