--- /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;
+ }
+