aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKiyoshi Ueda <k-ueda@ct.jp.nec.com>2010-08-11 23:13:55 -0400
committerAlasdair G Kergon <agk@redhat.com>2010-08-11 23:13:55 -0400
commit98f332855effef02aeb738e4d62e9a5b903c52fd (patch)
treeb10d7f632022415ddb047c2bacbaa1f861a76161
parentabdc568b0540bec6d3e0afebac496adef1189b77 (diff)
dm ioctl: release _hash_lock between devices in remove_all
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@ct.jp.nec.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Cc: stable@kernel.org Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r--drivers/md/dm-ioctl.c44
1 files changed, 25 insertions, 19 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 79ee5ba217f2..6a6d475f8e80 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -249,40 +249,46 @@ static void __hash_remove(struct hash_cell *hc)
249 249
250static void dm_hash_remove_all(int keep_open_devices) 250static void dm_hash_remove_all(int keep_open_devices)
251{ 251{
252 int i, dev_skipped, dev_removed; 252 int i, dev_skipped;
253 struct hash_cell *hc; 253 struct hash_cell *hc;
254 struct list_head *tmp, *n; 254 struct mapped_device *md;
255
256retry:
257 dev_skipped = 0;
255 258
256 down_write(&_hash_lock); 259 down_write(&_hash_lock);
257 260
258retry:
259 dev_skipped = dev_removed = 0;
260 for (i = 0; i < NUM_BUCKETS; i++) { 261 for (i = 0; i < NUM_BUCKETS; i++) {
261 list_for_each_safe (tmp, n, _name_buckets + i) { 262 list_for_each_entry(hc, _name_buckets + i, name_list) {
262 hc = list_entry(tmp, struct hash_cell, name_list); 263 md = hc->md;
264 dm_get(md);
263 265
264 if (keep_open_devices && 266 if (keep_open_devices && dm_lock_for_deletion(md)) {
265 dm_lock_for_deletion(hc->md)) { 267 dm_put(md);
266 dev_skipped++; 268 dev_skipped++;
267 continue; 269 continue;
268 } 270 }
271
269 __hash_remove(hc); 272 __hash_remove(hc);
270 dev_removed = 1;
271 }
272 }
273 273
274 /* 274 up_write(&_hash_lock);
275 * Some mapped devices may be using other mapped devices, so if any
276 * still exist, repeat until we make no further progress.
277 */
278 if (dev_skipped) {
279 if (dev_removed)
280 goto retry;
281 275
282 DMWARN("remove_all left %d open device(s)", dev_skipped); 276 dm_put(md);
277
278 /*
279 * Some mapped devices may be using other mapped
280 * devices, so repeat until we make no further
281 * progress. If a new mapped device is created
282 * here it will also get removed.
283 */
284 goto retry;
285 }
283 } 286 }
284 287
285 up_write(&_hash_lock); 288 up_write(&_hash_lock);
289
290 if (dev_skipped)
291 DMWARN("remove_all left %d open device(s)", dev_skipped);
286} 292}
287 293
288static struct mapped_device *dm_hash_rename(struct dm_ioctl *param, 294static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,