From: Alasdair G Kergon Add parameter to register_snapshot() which we can set if we know the origin structure already exists so will never need allocating. (A subsequent patch will call it in such circumstances.) Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) Index: linux-2.6.32-rc6/drivers/md/dm-snap.c =================================================================== --- linux-2.6.32-rc6.orig/drivers/md/dm-snap.c +++ linux-2.6.32-rc6/drivers/md/dm-snap.c @@ -306,15 +306,19 @@ static void __insert_origin(struct origi * Make a note of the snapshot and its origin so we can look it * up when the origin has a write on it. */ -static int register_snapshot(struct dm_snapshot *snap) +static int register_snapshot(struct dm_snapshot *snap, + int origin_exists) { struct dm_snapshot *l; - struct origin *o, *new_o; + struct origin *o, *new_o = NULL; struct block_device *bdev = snap->origin->bdev; + int r = 0; - new_o = kmalloc(sizeof(*new_o), GFP_KERNEL); - if (!new_o) - return -ENOMEM; + if (!origin_exists) { + new_o = kmalloc(sizeof(*new_o), GFP_KERNEL); + if (!new_o) + return -ENOMEM; + } down_write(&_origins_lock); o = __lookup_origin(bdev); @@ -322,6 +326,12 @@ static int register_snapshot(struct dm_s if (o) kfree(new_o); else { + if (origin_exists) { + DMERR("register_snapshot failed to find origin."); + r = -EINVAL; + goto out; + } + /* New origin */ o = new_o; @@ -338,8 +348,10 @@ static int register_snapshot(struct dm_s break; list_add_tail(&snap->list, &l->list); +out: up_write(&_origins_lock); - return 0; + + return r; } static void unregister_snapshot(struct dm_snapshot *s) @@ -715,7 +727,7 @@ static int snapshot_ctr(struct dm_target /* Add snapshot to the list of snapshots for this origin */ /* Exceptions aren't triggered till snapshot_resume() is called */ - if (register_snapshot(s)) { + if (register_snapshot(s, 0)) { r = -EINVAL; ti->error = "Cannot register snapshot origin"; goto bad_load_and_register;