dm snapshot: fix register_snapshot deadlock
register_snapshot() performs a GFP_KERNEL allocation while holding _origins_lock for write, but that could write out dirty pages onto a device that attempts to acquire _origins_lock for read, resulting in deadlock. So move the allocation up before taking the lock. This path is not performance-critical, so it doesn't matter that we allocate memory and free it if we find that we won't need it. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
b34578a484
commit
60c856c8e2
1 changed files with 9 additions and 7 deletions
|
@ -229,19 +229,21 @@ static void __insert_origin(struct origin *o)
|
|||
*/
|
||||
static int register_snapshot(struct dm_snapshot *snap)
|
||||
{
|
||||
struct origin *o;
|
||||
struct origin *o, *new_o;
|
||||
struct block_device *bdev = snap->origin->bdev;
|
||||
|
||||
new_o = kmalloc(sizeof(*new_o), GFP_KERNEL);
|
||||
if (!new_o)
|
||||
return -ENOMEM;
|
||||
|
||||
down_write(&_origins_lock);
|
||||
o = __lookup_origin(bdev);
|
||||
|
||||
if (!o) {
|
||||
if (o)
|
||||
kfree(new_o);
|
||||
else {
|
||||
/* New origin */
|
||||
o = kmalloc(sizeof(*o), GFP_KERNEL);
|
||||
if (!o) {
|
||||
up_write(&_origins_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
o = new_o;
|
||||
|
||||
/* Initialise the struct */
|
||||
INIT_LIST_HEAD(&o->snapshots);
|
||||
|
|
Loading…
Reference in a new issue