* [PATCH 0/3] dm: separate device deletion from dm_put()
@ 2010-06-08 10:21 Kiyoshi Ueda
2010-06-08 10:25 ` [PATCH 1/3] dm: prevent access to md being deleted Kiyoshi Ueda
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Kiyoshi Ueda @ 2010-06-08 10:21 UTC (permalink / raw)
To: Alasdair Kergon; +Cc: device-mapper development
Hi Alasdair,
This is an updated patch-set to fix bugs in device removal corner-cases,
replacing the previous version found in:
https://patchwork.kernel.org/patch/83995/
Please review and take this patch-set instead.
This patch-set can be applied on top of 2.6.35-rc1 + your NEXT_PATCHES.
The patch-set contains 3 patches:
The 3rd patch is basically same as the one I posted before.
The 1st patch is a new patch fixing possible NULL pointer dereference.
The 2nd patch fixes a deadlock, which is introduced by the 3rd patch.
The deadlock is AB-BA deadlock between dm_hash_remove_all(), which waits
for md->holders to be 0 with _hash_lock held, and other ioctls which waits
for _hash_lock with md->holders held (e.g. table_status(), table_load()):
CPU0 CPU1
------------------------------------------------------------------
dm_hash_remove_all()
down_write(_hash_lock)
table_status()
md = find_device()
dm_get(md)
dm_get_live_or_inactive_table()
dm_get_inactive_table()
down_write(_hash_lock)
dm_destroy(md)
while (md->holders)
msleep(1)
To fix this deadlock problem, this patch-set changes dm_hash_remove_all()
to release _hash_lock when removing a mapped_device, then, take _hash_lock
and start over again.
Summary of the patch-set:
1/3: dm: prevent access to md being deleted
2/3: dm: release _hash_lock when removing device in remove_all
3/3: dm: separate device deletion from dm_put()
drivers/md/dm-ioctl.c | 61 ++++++++++++++++++++++++++++----------------------
drivers/md/dm.c | 60 ++++++++++++++++++++++++++++++++++++-------------
drivers/md/dm.h | 5 ++++
3 files changed, 84 insertions(+), 42 deletions(-)
Thanks,
Kiyoshi Ueda
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 1/3] dm: prevent access to md being deleted 2010-06-08 10:21 [PATCH 0/3] dm: separate device deletion from dm_put() Kiyoshi Ueda @ 2010-06-08 10:25 ` Kiyoshi Ueda 2010-06-08 10:26 ` [PATCH 2/3] dm: release _hash_lock when removing device in remove_all Kiyoshi Ueda 2010-06-08 10:27 ` [PATCH 3/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2 siblings, 0 replies; 6+ messages in thread From: Kiyoshi Ueda @ 2010-06-08 10:25 UTC (permalink / raw) To: Alasdair Kergon; +Cc: device-mapper development This patch prevents access to mapped_device which is being deleted. Currently, even after a mapped_device has been removed from the hash, it could be accessed through idr_find() using minor number. That could cause a race and NULL pointer reference below: CPU0 CPU1 ------------------------------------------------------------------ dev_remove(param) down_write(_hash_lock) dm_lock_for_deletion(md) spin_lock(_minor_lock) set_bit(DMF_DELETING) spin_unlock(_minor_lock) __hash_remove(hc) up_write(_hash_lock) dev_status(param) md = find_device(param) down_read(_hash_lock) __find_device_hash_cell(param) dm_get_md(param->dev) md = dm_find_md(dev) spin_lock(_minor_lock) md = idr_find(MINOR(dev)) spin_unlock(_minor_lock) dm_put(md) free_dev(md) dm_get(md) up_read(_hash_lock) __dev_status(md, param) dm_put(md) This patch fixes such problems. Signed-off-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Cc: Alasdair G Kergon <agk@redhat.com> --- drivers/md/dm.c | 1 + 1 file changed, 1 insertion(+) Index: 2.6.35-rc1/drivers/md/dm.c =================================================================== --- 2.6.35-rc1.orig/drivers/md/dm.c +++ 2.6.35-rc1/drivers/md/dm.c @@ -2141,6 +2141,7 @@ static struct mapped_device *dm_find_md( md = idr_find(&_minor_idr, minor); if (md && (md == MINOR_ALLOCED || (MINOR(disk_devt(dm_disk(md))) != minor) || + dm_deleting_md(md) || test_bit(DMF_FREEING, &md->flags))) { md = NULL; goto out; ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/3] dm: release _hash_lock when removing device in remove_all 2010-06-08 10:21 [PATCH 0/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2010-06-08 10:25 ` [PATCH 1/3] dm: prevent access to md being deleted Kiyoshi Ueda @ 2010-06-08 10:26 ` Kiyoshi Ueda 2010-06-08 10:27 ` [PATCH 3/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2 siblings, 0 replies; 6+ messages in thread From: Kiyoshi Ueda @ 2010-06-08 10:26 UTC (permalink / raw) To: Alasdair Kergon; +Cc: device-mapper development 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: Alasdair G Kergon <agk@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, ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] dm: separate device deletion from dm_put() 2010-06-08 10:21 [PATCH 0/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2010-06-08 10:25 ` [PATCH 1/3] dm: prevent access to md being deleted Kiyoshi Ueda 2010-06-08 10:26 ` [PATCH 2/3] dm: release _hash_lock when removing device in remove_all Kiyoshi Ueda @ 2010-06-08 10:27 ` Kiyoshi Ueda 2010-07-23 17:59 ` Alasdair G Kergon 2 siblings, 1 reply; 6+ messages in thread From: Kiyoshi Ueda @ 2010-06-08 10:27 UTC (permalink / raw) To: Alasdair Kergon; +Cc: device-mapper development This patch separates the device deletion code from dm_put() to make sure the deletion happens in the process context. By this patch, device deletion always occurs in an ioctl (process) context and dm_put() can be called in interrupt context. As a result, the request-based dm's bad dm_put() usage pointed out by Mikulas below disappears. http://marc.info/?l=dm-devel&m=126699981019735&w=2 Without this patch, I confirmed there is a case to crash the system: dm_put() => dm_table_destroy() => vfree() => BUG_ON(in_interrupt()) Some more backgrounds and details: In request-based dm, a device opener can remove a mapped_device while the last request is still completing, because bios in the last request complete first and then the device opener can close and remove the mapped_device before the last request completes: CPU0 CPU1 ================================================================= <<INTERRUPT>> blk_end_request_all(clone_rq) blk_update_request(clone_rq) bio_endio(clone_bio) == end_clone_bio blk_update_request(orig_rq) bio_endio(orig_bio) <<I/O completed>> dm_blk_close() dev_remove() dm_put(md) <<Free md>> blk_finish_request(clone_rq) .... dm_end_request(clone_rq) free_rq_clone(clone_rq) blk_end_request_all(orig_rq) rq_completed(md) So request-based dm used dm_get()/dm_put() to hold md for each I/O until its request completion handling is fully done. However, the final dm_put() can call the device deletion code which must not be run in interrupt context and may cause kernel panic. To solve the problem, this patch moves the device deletion code, dm_destroy(), to predetermined places that is actually deleting the mapped_device in ioctl (process) context, and changes dm_put() just to decrement the reference count of the mapped_device. By this change, dm_put() can be used in any context and the symmetric model below is introduced: dm_create(): create a mapped_device dm_destroy(): destroy a mapped_device dm_get(): increment the reference count of a mapped_device dm_put(): decrement the reference count of a mapped_device dm_destroy() waits for all references of the mapped_device to disappear, then deletes the mapped_device. dm_destroy() uses active waiting with msleep(1), since deleting the mapped_device isn't performance-critical task. And since at this point, nobody opens the mapped_device and no new reference will be taken, the pending counts are just for racing completing activity and will eventually decrease to zero. For the unlikely case of the forced module unload, dm_destroy_nowait(), which doesn't wait and forcibly deletes the mapped_device, is also introduced and used in dm_hash_remove_all(). Otherwise, "rmmod -f" may be stuck and never return. And now, because the mapped_device is deleted at this point, subsequent accesses to the mapped_device may cause NULL pointer references. Signed-off-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Cc: Alasdair G Kergon <agk@redhat.com> --- drivers/md/dm-ioctl.c | 15 +++++++++--- drivers/md/dm.c | 59 ++++++++++++++++++++++++++++++++++++-------------- drivers/md/dm.h | 5 ++++ 3 files changed, 59 insertions(+), 20 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 @@ -270,6 +270,10 @@ retry: up_write(&_hash_lock); dm_put(md); + if (likely(keep_open_devices)) + dm_destroy(md); + else + dm_destroy_nowait(md); /* * Some mapped devices may be using other mapped @@ -640,17 +644,19 @@ static int dev_create(struct dm_ioctl *p return r; r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - if (r) - goto out; + if (r) { + dm_put(md); + dm_destroy(md); + return r; + } param->flags &= ~DM_INACTIVE_PRESENT_FLAG; __dev_status(md, param); -out: dm_put(md); - return r; + return 0; } /* @@ -744,6 +750,7 @@ static int dev_remove(struct dm_ioctl *p param->flags |= DM_UEVENT_GENERATED_FLAG; dm_put(md); + dm_destroy(md); return 0; } Index: 2.6.35-rc1/drivers/md/dm.c =================================================================== --- 2.6.35-rc1.orig/drivers/md/dm.c +++ 2.6.35-rc1/drivers/md/dm.c @@ -2176,6 +2176,7 @@ void dm_set_mdptr(struct mapped_device * void dm_get(struct mapped_device *md) { atomic_inc(&md->holders); + BUG_ON(test_bit(DMF_FREEING, &md->flags)); } const char *dm_device_name(struct mapped_device *md) @@ -2184,27 +2185,53 @@ const char *dm_device_name(struct mapped } EXPORT_SYMBOL_GPL(dm_device_name); -void dm_put(struct mapped_device *md) +static void __dm_destroy(struct mapped_device *md, bool wait) { struct dm_table *map; - BUG_ON(test_bit(DMF_FREEING, &md->flags)); + might_sleep(); - if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { - map = dm_get_live_table(md); - idr_replace(&_minor_idr, MINOR_ALLOCED, - MINOR(disk_devt(dm_disk(md)))); - set_bit(DMF_FREEING, &md->flags); - spin_unlock(&_minor_lock); - if (!dm_suspended_md(md)) { - dm_table_presuspend_targets(map); - dm_table_postsuspend_targets(map); - } - dm_sysfs_exit(md); - dm_table_put(map); - dm_table_destroy(__unbind(md)); - free_dev(md); + spin_lock(&_minor_lock); + map = dm_get_live_table(md); + idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); + set_bit(DMF_FREEING, &md->flags); + spin_unlock(&_minor_lock); + + if (!dm_suspended_md(md)) { + dm_table_presuspend_targets(map); + dm_table_postsuspend_targets(map); } + + /* + * Rare but there may be I/O requests still going to complete, + * for example. Wait for all references to disappear. + * No one shouldn't increment the reference count of the mapped_device, + * after the mapped_device becomes DMF_FREEING state. + */ + if (wait) { + while (atomic_read(&md->holders)) + msleep(1); + } + + dm_sysfs_exit(md); + dm_table_put(map); + dm_table_destroy(__unbind(md)); + free_dev(md); +} + +void dm_destroy(struct mapped_device *md) +{ + __dm_destroy(md, true); +} + +void dm_destroy_nowait(struct mapped_device *md) +{ + __dm_destroy(md, false); +} + +void dm_put(struct mapped_device *md) +{ + atomic_dec(&md->holders); } EXPORT_SYMBOL_GPL(dm_put); Index: 2.6.35-rc1/drivers/md/dm.h =================================================================== --- 2.6.35-rc1.orig/drivers/md/dm.h +++ 2.6.35-rc1/drivers/md/dm.h @@ -122,6 +122,11 @@ void dm_linear_exit(void); int dm_stripe_init(void); void dm_stripe_exit(void); +/* + * mapped_device operations + */ +void dm_destroy(struct mapped_device *md); +void dm_destroy_nowait(struct mapped_device *md); int dm_open_count(struct mapped_device *md); int dm_lock_for_deletion(struct mapped_device *md); ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] dm: separate device deletion from dm_put() 2010-06-08 10:27 ` [PATCH 3/3] dm: separate device deletion from dm_put() Kiyoshi Ueda @ 2010-07-23 17:59 ` Alasdair G Kergon 2010-08-03 7:19 ` Kiyoshi Ueda 0 siblings, 1 reply; 6+ messages in thread From: Alasdair G Kergon @ 2010-07-23 17:59 UTC (permalink / raw) To: Kiyoshi Ueda; +Cc: device-mapper development On Tue, Jun 08, 2010 at 07:27:20PM +0900, Kiyoshi Ueda wrote: > For the unlikely case of the forced module unload, dm_destroy_nowait(), > which doesn't wait and forcibly deletes the mapped_device, is also > introduced and used in dm_hash_remove_all(). Otherwise, "rmmod -f" > may be stuck and never return. > And now, because the mapped_device is deleted at this point, subsequent > accesses to the mapped_device may cause NULL pointer references. Do we get a warning message logged when this situation occurs and md->holders is still set or should we add one? > + if (wait) { > + while (atomic_read(&md->holders)) > + msleep(1); Alasdair ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/3] dm: separate device deletion from dm_put() 2010-07-23 17:59 ` Alasdair G Kergon @ 2010-08-03 7:19 ` Kiyoshi Ueda 0 siblings, 0 replies; 6+ messages in thread From: Kiyoshi Ueda @ 2010-08-03 7:19 UTC (permalink / raw) To: Alasdair Kergon; +Cc: device-mapper development Hi Alasdair, Sorry for the long delay, I was on vacation. On 07/24/2010 02:59 AM +0900, Alasdair G Kergon wrote: > On Tue, Jun 08, 2010 at 07:27:20PM +0900, Kiyoshi Ueda wrote: >> For the unlikely case of the forced module unload, dm_destroy_nowait(), >> which doesn't wait and forcibly deletes the mapped_device, is also >> introduced and used in dm_hash_remove_all(). Otherwise, "rmmod -f" >> may be stuck and never return. > >> And now, because the mapped_device is deleted at this point, subsequent >> accesses to the mapped_device may cause NULL pointer references. > > Do we get a warning message logged when this situation occurs > and md->holders is still set or should we add one? > >> + if (wait) { >> + while (atomic_read(&md->holders)) >> + msleep(1); OK, since there was no warning message, I added one as below: if (wait) { while (atomic_read(&md->holders)) msleep(1); } else if (atomic_read(&md->holders)) DMWARN("%s: Deleting mapped_device still in use! (%d users)", dm_device_name(md), atomic_read(&md->holders)); Here is the refreshed patch which can be applied on your editing tree. Please review and apply. Thanks, Kiyoshi Ueda Subject: [PATCH 3/3] dm: separate device deletion from dm_put() This patch separates the device deletion code from dm_put() to make sure the deletion happens in the process context. By this patch, device deletion always occurs in an ioctl (process) context and dm_put() can be called in interrupt context. As a result, the request-based dm's bad dm_put() usage pointed out by Mikulas below disappears. http://marc.info/?l=dm-devel&m=126699981019735&w=2 Without this patch, I confirmed there is a case to crash the system: dm_put() => dm_table_destroy() => vfree() => BUG_ON(in_interrupt()) Some more backgrounds and details: In request-based dm, a device opener can remove a mapped_device while the last request is still completing, because bios in the last request complete first and then the device opener can close and remove the mapped_device before the last request completes: CPU0 CPU1 ================================================================= <<INTERRUPT>> blk_end_request_all(clone_rq) blk_update_request(clone_rq) bio_endio(clone_bio) == end_clone_bio blk_update_request(orig_rq) bio_endio(orig_bio) <<I/O completed>> dm_blk_close() dev_remove() dm_put(md) <<Free md>> blk_finish_request(clone_rq) .... dm_end_request(clone_rq) free_rq_clone(clone_rq) blk_end_request_all(orig_rq) rq_completed(md) So request-based dm used dm_get()/dm_put() to hold md for each I/O until its request completion handling is fully done. However, the final dm_put() can call the device deletion code which must not be run in interrupt context and may cause kernel panic. To solve the problem, this patch moves the device deletion code, dm_destroy(), to predetermined places that is actually deleting the mapped_device in ioctl (process) context, and changes dm_put() just to decrement the reference count of the mapped_device. By this change, dm_put() can be used in any context and the symmetric model below is introduced: dm_create(): create a mapped_device dm_destroy(): destroy a mapped_device dm_get(): increment the reference count of a mapped_device dm_put(): decrement the reference count of a mapped_device dm_destroy() waits for all references of the mapped_device to disappear, then deletes the mapped_device. dm_destroy() uses active waiting with msleep(1), since deleting the mapped_device isn't performance-critical task. And since at this point, nobody opens the mapped_device and no new reference will be taken, the pending counts are just for racing completing activity and will eventually decrease to zero. For the unlikely case of the forced module unload, dm_destroy_nowait(), which doesn't wait and forcibly deletes the mapped_device, is also introduced and used in dm_hash_remove_all(). Otherwise, "rmmod -f" may be stuck and never return. And now, because the mapped_device is deleted at this point, subsequent accesses to the mapped_device may cause NULL pointer references. Signed-off-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com> Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Cc: Alasdair G Kergon <agk@redhat.com> --- drivers/md/dm-ioctl.c | 15 +++++++++--- drivers/md/dm.c | 61 ++++++++++++++++++++++++++++++++++++-------------- drivers/md/dm.h | 5 ++++ 3 files changed, 61 insertions(+), 20 deletions(-) Index: 2.6.35/drivers/md/dm-ioctl.c =================================================================== --- 2.6.35.orig/drivers/md/dm-ioctl.c +++ 2.6.35/drivers/md/dm-ioctl.c @@ -270,6 +270,10 @@ retry: up_write(&_hash_lock); dm_put(md); + if (likely(keep_open_devices)) + dm_destroy(md); + else + dm_destroy_nowait(md); /* * Some mapped devices may be using other mapped @@ -640,17 +644,19 @@ static int dev_create(struct dm_ioctl *p return r; r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); - if (r) - goto out; + if (r) { + dm_put(md); + dm_destroy(md); + return r; + } param->flags &= ~DM_INACTIVE_PRESENT_FLAG; __dev_status(md, param); -out: dm_put(md); - return r; + return 0; } /* @@ -744,6 +750,7 @@ static int dev_remove(struct dm_ioctl *p param->flags |= DM_UEVENT_GENERATED_FLAG; dm_put(md); + dm_destroy(md); return 0; } Index: 2.6.35/drivers/md/dm.c =================================================================== --- 2.6.35.orig/drivers/md/dm.c +++ 2.6.35/drivers/md/dm.c @@ -2176,6 +2176,7 @@ void dm_set_mdptr(struct mapped_device * void dm_get(struct mapped_device *md) { atomic_inc(&md->holders); + BUG_ON(test_bit(DMF_FREEING, &md->flags)); } const char *dm_device_name(struct mapped_device *md) @@ -2184,27 +2185,55 @@ const char *dm_device_name(struct mapped } EXPORT_SYMBOL_GPL(dm_device_name); -void dm_put(struct mapped_device *md) +static void __dm_destroy(struct mapped_device *md, bool wait) { struct dm_table *map; - BUG_ON(test_bit(DMF_FREEING, &md->flags)); + might_sleep(); - if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { - map = dm_get_live_table(md); - idr_replace(&_minor_idr, MINOR_ALLOCED, - MINOR(disk_devt(dm_disk(md)))); - set_bit(DMF_FREEING, &md->flags); - spin_unlock(&_minor_lock); - if (!dm_suspended_md(md)) { - dm_table_presuspend_targets(map); - dm_table_postsuspend_targets(map); - } - dm_sysfs_exit(md); - dm_table_put(map); - dm_table_destroy(__unbind(md)); - free_dev(md); + spin_lock(&_minor_lock); + map = dm_get_live_table(md); + idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); + set_bit(DMF_FREEING, &md->flags); + spin_unlock(&_minor_lock); + + if (!dm_suspended_md(md)) { + dm_table_presuspend_targets(map); + dm_table_postsuspend_targets(map); } + + /* + * Rare but there may be I/O requests still going to complete, + * for example. Wait for all references to disappear. + * No one shouldn't increment the reference count of the mapped_device, + * after the mapped_device becomes DMF_FREEING state. + */ + if (wait) { + while (atomic_read(&md->holders)) + msleep(1); + } else if (atomic_read(&md->holders)) + DMWARN("%s: Deleting mapped_device still in use! (%d users)", + dm_device_name(md), atomic_read(&md->holders)); + + dm_sysfs_exit(md); + dm_table_put(map); + dm_table_destroy(__unbind(md)); + free_dev(md); +} + +void dm_destroy(struct mapped_device *md) +{ + __dm_destroy(md, true); +} + +void dm_destroy_nowait(struct mapped_device *md) +{ + __dm_destroy(md, false); +} + +void dm_put(struct mapped_device *md) +{ + atomic_dec(&md->holders); } EXPORT_SYMBOL_GPL(dm_put); Index: 2.6.35/drivers/md/dm.h =================================================================== --- 2.6.35.orig/drivers/md/dm.h +++ 2.6.35/drivers/md/dm.h @@ -122,6 +122,11 @@ void dm_linear_exit(void); int dm_stripe_init(void); void dm_stripe_exit(void); +/* + * mapped_device operations + */ +void dm_destroy(struct mapped_device *md); +void dm_destroy_nowait(struct mapped_device *md); int dm_open_count(struct mapped_device *md); int dm_lock_for_deletion(struct mapped_device *md); ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-08-03 7:19 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-06-08 10:21 [PATCH 0/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2010-06-08 10:25 ` [PATCH 1/3] dm: prevent access to md being deleted Kiyoshi Ueda 2010-06-08 10:26 ` [PATCH 2/3] dm: release _hash_lock when removing device in remove_all Kiyoshi Ueda 2010-06-08 10:27 ` [PATCH 3/3] dm: separate device deletion from dm_put() Kiyoshi Ueda 2010-07-23 17:59 ` Alasdair G Kergon 2010-08-03 7:19 ` Kiyoshi Ueda
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.