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>
This commit is contained in:
parent
abdc568b05
commit
98f332855e
|
@ -249,40 +249,46 @@ static void __hash_remove(struct hash_cell *hc)
|
|||
|
||||
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;
|
||||
struct mapped_device *md;
|
||||
|
||||
retry:
|
||||
dev_skipped = 0;
|
||||
|
||||
down_write(&_hash_lock);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
dm_put(md);
|
||||
|
||||
/*
|
||||
* Some mapped devices may be using other mapped devices, so if any
|
||||
* still exist, repeat until we make no further progress.
|
||||
* 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 also get removed.
|
||||
*/
|
||||
if (dev_skipped) {
|
||||
if (dev_removed)
|
||||
goto retry;
|
||||
|
||||
DMWARN("remove_all left %d open device(s)", dev_skipped);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue