dm: fix a race condition in dm_get_md
The function dm_get_md finds a device mapper device with a given dev_t, increases the reference count and returns the pointer. dm_get_md calls dm_find_md, dm_find_md takes _minor_lock, finds the device, tests that the device doesn't have DMF_DELETING or DMF_FREEING flag, drops _minor_lock and returns pointer to the device. dm_get_md then calls dm_get. dm_get calls BUG if the device has the DMF_FREEING flag, otherwise it increments the reference count. There is a possible race condition - after dm_find_md exits and before dm_get is called, there are no locks held, so the device may disappear or DMF_FREEING flag may be set, which results in BUG. To fix this bug, we need to call dm_get while we hold _minor_lock. This patch renames dm_find_md to dm_get_md and changes it so that it calls dm_get while holding the lock. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: stable@vger.kernel.org
This commit is contained in:
parent
b3c5fd3052
commit
2bec1f4a88
|
@ -2571,7 +2571,7 @@ int dm_setup_md_queue(struct mapped_device *md)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mapped_device *dm_find_md(dev_t dev)
|
struct mapped_device *dm_get_md(dev_t dev)
|
||||||
{
|
{
|
||||||
struct mapped_device *md;
|
struct mapped_device *md;
|
||||||
unsigned minor = MINOR(dev);
|
unsigned minor = MINOR(dev);
|
||||||
|
@ -2582,12 +2582,15 @@ static struct mapped_device *dm_find_md(dev_t dev)
|
||||||
spin_lock(&_minor_lock);
|
spin_lock(&_minor_lock);
|
||||||
|
|
||||||
md = idr_find(&_minor_idr, minor);
|
md = idr_find(&_minor_idr, minor);
|
||||||
if (md && (md == MINOR_ALLOCED ||
|
if (md) {
|
||||||
(MINOR(disk_devt(dm_disk(md))) != minor) ||
|
if ((md == MINOR_ALLOCED ||
|
||||||
dm_deleting_md(md) ||
|
(MINOR(disk_devt(dm_disk(md))) != minor) ||
|
||||||
test_bit(DMF_FREEING, &md->flags))) {
|
dm_deleting_md(md) ||
|
||||||
md = NULL;
|
test_bit(DMF_FREEING, &md->flags))) {
|
||||||
goto out;
|
md = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
dm_get(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -2595,16 +2598,6 @@ out:
|
||||||
|
|
||||||
return md;
|
return md;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mapped_device *dm_get_md(dev_t dev)
|
|
||||||
{
|
|
||||||
struct mapped_device *md = dm_find_md(dev);
|
|
||||||
|
|
||||||
if (md)
|
|
||||||
dm_get(md);
|
|
||||||
|
|
||||||
return md;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(dm_get_md);
|
EXPORT_SYMBOL_GPL(dm_get_md);
|
||||||
|
|
||||||
void *dm_get_mdptr(struct mapped_device *md)
|
void *dm_get_mdptr(struct mapped_device *md)
|
||||||
|
|
Loading…
Reference in New Issue