Index: linux-2.6.18/drivers/md/dm-raid1.c =================================================================== --- linux-2.6.18.orig/drivers/md/dm-raid1.c 2006-10-20 10:39:24.000000000 -0500 +++ linux-2.6.18/drivers/md/dm-raid1.c 2006-10-20 13:54:55.000000000 -0500 @@ -1016,13 +1016,137 @@ static struct dirty_log *create_dirty_lo } /* - * Construct a mirror mapping: + * mirror_format2_ctr + * @ti + * @argc + * @argv * - * log_type #log_params - * #mirrors [mirror_path offset]{2,} + * Format2: + * format2 \ + * log <#log_params> \ + * devices <#dev_params> ... + * Example: + * format2 log 4 disk 253:2 1024 block_on_error devices 2 253:3 0 253:4 0 * - * log_type is "core" or "disk" - * #log_params is between 1 and 3 + * Format2 allows for new sections, as well as for the sections to + * be in any order. + * + * Returns: 0 on success, -EXXX on failure + */ +static int mirror_format2_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + unsigned int log_argc, devices_argc, section_argc; + char **log_argv, **devices_argv, *section_id; + struct dirty_log *dl; + unsigned int nr_mirrors, m; + + argv++; /* skip over "format2" arg */ + argc--; + + /* Identify the sections */ + while (argc) { + section_id = argv[0]; + + /* FIXME: Break this down for better error reporting? */ + if ((argc < 2) || + (sscanf(argv[1], "%u", §ion_argc) != 1) || + (section_argc > (argc - 2))) { + ti->error = "Invalid mirror mapping table"; + return -EINVAL; + } else { + argc -= 2; + argv += 2; + } + + if (!strcmp("log", section_id)) { + log_argv = argv; + log_argc = section_argc; + } else if (!strcmp("devices", section_id)) { + devices_argv = argv; + devices_argc = section_argc; + } else { + ti->error = "Unknown section in mirror mapping table"; + return -EINVAL; + } + argc -= section_argc; + argv += section_argc; + } + + /* Construct mirror - could make each section a separate function */ + if (log_argc < 2) { + ti->error = "Insufficient mirror log arguments"; + return -EINVAL;; + } + dl = dm_create_dirty_log(log_argv[0], ti, log_argc - 1, log_argv + 1); + if (!dl) { + ti->error = "Error creating mirror dirty log"; + return -EINVAL; + } + + if (!_check_region_size(ti, dl->type->get_region_size(dl))) { + ti->error = "Invalid region size"; + dm_destroy_dirty_log(dl); + return -EINVAL; + } + + /* + * Right now, devices_argc is equal to 1/2 the number of mirror + * devices specified. However, this could change in the + * future depending on feedback from other developers. + */ + nr_mirrors = devices_argc/2; + + if ((nr_mirrors < 2) || (nr_mirrors > KCOPYD_MAX_REGIONS + 1)) { + ti->error = "Invalid number of mirrors"; + dm_destroy_dirty_log(dl); + return -EINVAL; + } + + ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl); + if (!ms) { + dm_destroy_dirty_log(dl); + return -ENOMEM; + } + + /* Get the mirror parameter sets */ + for (m = 0; m < nr_mirrors; m++) { + r = get_mirror(ms, ti, m, devices_argv + (2 * m)); + if (r) { + free_context(ms, ti, m); + return r; + } + } + + ti->private = ms; + ti->split_io = ms->rh.region_size; + + r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client); + if (r) { + free_context(ms, ti, ms->nr_mirrors); + return r; + } + + add_mirror_set(ms); + return 0; +} + +/* + * mirror_ctr + * @ti + * @argc + * @argv + * + * This function constructs the mirror map given the mapping + * table found in argv. If the first argument is 'format2', + * 'mirror_format2_ctr is used; otherwise, the following is + * the valid argument set: + * <#log_params> \ + * <#mirrors> ... + * + * See the log_type implementations for details on their + * argument list. + * + * Returns: 0 on success, -EXXX on failure */ #define DM_IO_PAGES 64 static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv) @@ -1032,6 +1156,9 @@ static int mirror_ctr(struct dm_target * struct mirror_set *ms; struct dirty_log *dl; + if (!strcmp("format2", argv[0])) + return mirror_format2_ctr(ti, argc, argv); + dl = create_dirty_log(ti, argc, argv, &args_used); if (!dl) return -EINVAL;