Split parts of snapshot_ctr() into a separate function, snapshot_init() and parts of snapshot_dtr() into snapshot_destroy(). This is needed by later patches because the merging target re-uses the dm_snapshot structure, but the merging target doesn't register itself as a snapshot (i.e. origin writes shouldn't cause an exception), has a different set of arguments and in some ways behaves more like a snapshot-origin target. Index: linux-2.6.16.i686/drivers/md/dm-snap.c =================================================================== --- linux-2.6.16.i686.orig/drivers/md/dm-snap.c 2006-05-04 08:52:34.000000000 +0100 +++ linux-2.6.16.i686/drivers/md/dm-snap.c 2006-05-04 12:04:32.000000000 +0100 @@ -390,18 +390,9 @@ static inline ulong round_up(ulong n, ul return (n + size) & ~size; } -static int check_chunk_size(struct dm_snapshot *s, const char *chunk_size_str, +static int check_chunk_size(struct dm_snapshot *s, unsigned long chunk_size, char **error) { - unsigned long chunk_size; - char *value; - - chunk_size = simple_strtoul(chunk_size_str, &value, 10); - if (chunk_size == 0 || value == NULL) { - *error = "Invalid chunk size"; - return 0; - } - /* * Chunk size must be multiple of page size. Silently * round up if it's not. @@ -427,69 +418,32 @@ static int check_chunk_size(struct dm_sn return 1; } -/* - * Construct a snapshot mapping:

- */ -static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) +static int snapshot_init(struct dm_target *ti, struct dm_snapshot *s, + const char *origin_path, int origin_mode, + const char *cow_path, int cow_mode, + char type, unsigned long chunk_size) { - struct dm_snapshot *s; - int r = -EINVAL; - char persistent; - char *origin_path; - char *cow_path; - - if (argc != 3 && argc != 4) { - ti->error = "dm-snapshot: requires exactly 3 or 4 arguments"; - r = -EINVAL; - goto bad1; - } - - origin_path = argv[0]; - cow_path = argv[1]; - persistent = toupper(*argv[2]); - - if (persistent != 'P' && persistent != 'N') { - ti->error = "Persistent flag is not P or N"; - r = -EINVAL; - goto bad1; - } - - if (persistent == 'N' && argc != 4) { - ti->error = "Chunk size is required for transient snapshots"; - r = -EINVAL; - goto bad1; - } - - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) { - ti->error = "Cannot allocate snapshot context private " - "structure"; - r = -ENOMEM; - goto bad1; - } + int r; - r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); + r = dm_get_device(ti, origin_path, 0, ti->len, origin_mode, &s->origin); if (r) { ti->error = "Cannot get origin device"; - goto bad2; + goto bad1; } - r = dm_get_device(ti, cow_path, 0, 0, - FMODE_READ | FMODE_WRITE, &s->cow); + r = dm_get_device(ti, cow_path, 0, 0, cow_mode, &s->cow); if (r) { - dm_put_device(ti, s->origin); ti->error = "Cannot get COW device"; goto bad2; } s->chunk_size = s->chunk_mask = s->chunk_shift = 0; - if (argc == 4 && !check_chunk_size(s, argv[3], &ti->error)) { + if (chunk_size && !check_chunk_size(s, chunk_size, &ti->error)) { r = -EINVAL; goto bad3; } - s->type = persistent; - + s->type = type; s->valid = 1; s->active = 0; s->last_percent = 0; @@ -506,7 +460,7 @@ static int snapshot_ctr(struct dm_target s->store.snap = s; - if (persistent == 'P') + if (s->type == 'P') r = dm_create_persistent(&s->store); else r = dm_create_transient(&s->store); @@ -533,36 +487,108 @@ static int snapshot_ctr(struct dm_target bio_list_init(&s->queued_bios); INIT_WORK(&s->queued_bios_work, flush_queued_bios, s); - /* Add snapshot to the list of snapshots for this origin */ - /* Exceptions aren't triggered till snapshot_resume() is called */ - if (register_snapshot(s)) { - r = -EINVAL; - ti->error = "Cannot register snapshot origin"; - goto bad6; - } - - ti->private = s; - ti->split_io = s->chunk_size; - return 0; bad6: kcopyd_client_destroy(s->kcopyd_client); - bad5: s->store.destroy(&s->store); - bad4: exit_exception_table(&s->pending, pending_cache); exit_exception_table(&s->complete, exception_cache); - bad3: dm_put_device(ti, s->cow); + bad2: dm_put_device(ti, s->origin); + bad1: + return r; +} + +static void snapshot_destroy(struct dm_target *ti, struct dm_snapshot *s) +{ + kcopyd_client_destroy(s->kcopyd_client); + + exit_exception_table(&s->pending, pending_cache); + exit_exception_table(&s->complete, exception_cache); + + /* Deallocate memory used */ + s->store.destroy(&s->store); + dm_put_device(ti, s->origin); + dm_put_device(ti, s->cow); +} + +/* + * Construct a snapshot mapping:

+ */ +static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct dm_snapshot *s; + int r = -EINVAL; + char persistent; + char *origin_path; + char *cow_path; + unsigned long chunk_size = 0; + char *value; + + if (argc != 3 && argc != 4) { + ti->error = "dm-snapshot: requires exactly 3 or 4 arguments"; + goto bad1; + } + + origin_path = argv[0]; + cow_path = argv[1]; + persistent = toupper(*argv[2]); + + if (persistent != 'P' && persistent != 'N') { + ti->error = "Persistent flag is not P or N"; + goto bad1; + } + + if (persistent == 'N' && argc != 4) { + ti->error = "Chunk size is required for transient snapshots"; + goto bad1; + } + + if (argc == 4) { + chunk_size = simple_strtoul(argv[3], &value, 10); + if (chunk_size == 0 || value == NULL) { + ti->error = "Invalid chunk size"; + goto bad1; + } + } + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) { + ti->error = "Cannot allocate snapshot context private " + "structure"; + r = -ENOMEM; + goto bad1; + } + + r = snapshot_init(ti, s, origin_path, FMODE_READ, + cow_path, FMODE_READ | FMODE_WRITE, + persistent, chunk_size); + if (r) + goto bad2; + + /* Add snapshot to the list of snapshots for this origin */ + /* Exceptions aren't triggered till snapshot_resume() is called */ + if (register_snapshot(s)) { + r = -EINVAL; + ti->error = "Cannot register snapshot origin"; + goto bad3; + } + + ti->private = s; + ti->split_io = s->chunk_size; + + return 0; + + bad3: + snapshot_destroy(ti, s); bad2: kfree(s); - bad1: return r; } @@ -577,16 +603,7 @@ static void snapshot_dtr(struct dm_targe /* After this returns there can be no new kcopyd jobs. */ unregister_snapshot(s); - kcopyd_client_destroy(s->kcopyd_client); - - exit_exception_table(&s->pending, pending_cache); - exit_exception_table(&s->complete, exception_cache); - - /* Deallocate memory used */ - s->store.destroy(&s->store); - - dm_put_device(ti, s->origin); - dm_put_device(ti, s->cow); + snapshot_destroy(ti, s); kfree(s); }