[dm-devel] [PATCH 2/3] dm: release _hash_lock when removing device in remove_all

Kiyoshi Ueda k-ueda at ct.jp.nec.com
Tue Jun 8 10:26:34 UTC 2010


This patch changes dm_hash_remove_all() to release _hash_lock when
removing a device.  After removing the device, dm_hash_remove_all()
takes _hash_lock and searches the hash from scratch again.

This patch is a preparation for the next patch, which changes device
deletion code to wait for md reference to be 0.  Without this patch,
the wait in the next patch may cause AB-BA deadlock:
  CPU0                                CPU1
  -----------------------------------------------------------------------
  dm_hash_remove_all()
    down_write(_hash_lock)
                                      table_status()
                                        md = find_device()
                                               dm_get(md)
                                                 <increment md->holders>
                                        dm_get_live_or_inactive_table()
                                          dm_get_inactive_table()
                                            down_write(_hash_lock)
    <in the md deletion code>
      <wait for md->holders to be 0>

Signed-off-by: Kiyoshi Ueda <k-ueda at ct.jp.nec.com>
Signed-off-by: Jun'ichi Nomura <j-nomura at ce.jp.nec.com>
Cc: Alasdair G Kergon <agk at redhat.com>
---
 drivers/md/dm-ioctl.c |   46 ++++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 22 deletions(-)

Index: 2.6.35-rc1/drivers/md/dm-ioctl.c
===================================================================
--- 2.6.35-rc1.orig/drivers/md/dm-ioctl.c
+++ 2.6.35-rc1/drivers/md/dm-ioctl.c
@@ -249,40 +249,42 @@ static void __hash_remove(struct hash_ce
 
 static void dm_hash_remove_all(int keep_open_devices)
 {
-	int i, dev_skipped, dev_removed;
+	int i, dev_skipped;
 	struct hash_cell *hc;
-	struct list_head *tmp, *n;
-
-	down_write(&_hash_lock);
+	struct mapped_device *md;
 
 retry:
-	dev_skipped = dev_removed = 0;
-	for (i = 0; i < NUM_BUCKETS; i++) {
-		list_for_each_safe (tmp, n, _name_buckets + i) {
-			hc = list_entry(tmp, struct hash_cell, name_list);
+	down_write(&_hash_lock);
+	for (dev_skipped = 0, i = 0; i < NUM_BUCKETS; i++) {
+		list_for_each_entry(hc, _name_buckets + i, name_list) {
+			md = hc->md;
+			dm_get(md);
 
-			if (keep_open_devices &&
-			    dm_lock_for_deletion(hc->md)) {
+			if (keep_open_devices && dm_lock_for_deletion(md)) {
+				dm_put(md);
 				dev_skipped++;
 				continue;
 			}
+
 			__hash_remove(hc);
-			dev_removed = 1;
-		}
-	}
+			up_write(&_hash_lock);
 
-	/*
-	 * Some mapped devices may be using other mapped devices, so if any
-	 * still exist, repeat until we make no further progress.
-	 */
-	if (dev_skipped) {
-		if (dev_removed)
-			goto retry;
+			dm_put(md);
 
-		DMWARN("remove_all left %d open device(s)", dev_skipped);
+			/*
+			 * Some mapped devices may be using other mapped
+			 * devices, so repeat until we make no further
+			 * progress.
+			 * If a new mapped device is created here, it will be
+			 * also removed.
+			 */
+			goto retry;
+		}
 	}
-
 	up_write(&_hash_lock);
+
+	if (dev_skipped)
+		DMWARN("remove_all left %d open device(s)", dev_skipped);
 }
 
 static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,




More information about the dm-devel mailing list