From: Mikulas Patocka 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 Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) Index: linux-2.6.28-rc2/drivers/md/dm-snap.c =================================================================== --- linux-2.6.28-rc2.orig/drivers/md/dm-snap.c 2008-10-30 13:26:33.000000000 +0000 +++ linux-2.6.28-rc2/drivers/md/dm-snap.c 2008-10-30 13:27:18.000000000 +0000 @@ -229,19 +229,21 @@ static void __insert_origin(struct origi */ 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);