]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.25/patches.fixes/dm-avoid-put-table-dm_any_congested
Updated xen patches taken from suse.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.fixes / dm-avoid-put-table-dm_any_congested
diff --git a/src/patches/suse-2.6.27.25/patches.fixes/dm-avoid-put-table-dm_any_congested b/src/patches/suse-2.6.27.25/patches.fixes/dm-avoid-put-table-dm_any_congested
new file mode 100644 (file)
index 0000000..c8d36c3
--- /dev/null
@@ -0,0 +1,82 @@
+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;
+ }