| From 00733ab7e4c32455a6879bdcc29cb2e8dd90dcea Mon Sep 17 00:00:00 2001 |
| From: Helen Koike <helen.koike@collabora.com> |
| Date: Tue, 23 Apr 2019 15:58:36 -0300 |
| Subject: [PATCH] CHROMIUM: dm: init: convert dm= to dm-mod.create= |
| |
| Upstream code uses dm-mod.create= option to allow boot to device-mapper |
| without an initr*. |
| |
| Add a dm= kernel parameter that just convers the given format to |
| dm-mod.create= format. |
| This patch is meant to be reverted once all ChromeOS build/userspace |
| code migrate to the new format. |
| |
| BUG=chromium:960168 |
| TEST=The following script passes all tests: |
| https://gitlab.collabora.com/koike/dm-cmdline-test/tree/chrome |
| |
| Change-Id: I10ef47147a4f424d5ed00bc75ea3276e7dcd7e43 |
| Signed-off-by: Helen Koike <helen.koike@collabora.com> |
| Signed-off-by: Guenter Roeck <groeck@chromium.org> |
| --- |
| drivers/md/dm-init.c | 251 +++++++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 251 insertions(+) |
| |
| diff --git a/drivers/md/dm-init.c b/drivers/md/dm-init.c |
| index dc4381d683131e67019345294348985fcfb81cc3..4dbd8a635d321869c04b880942aa64c14871b90c 100644 |
| --- a/drivers/md/dm-init.c |
| +++ b/drivers/md/dm-init.c |
| @@ -321,3 +321,254 @@ MODULE_PARM_DESC(create, "Create a mapped device in early boot"); |
| |
| module_param_array(waitfor, charp, NULL, 0); |
| MODULE_PARM_DESC(waitfor, "Devices to wait for before setting up tables"); |
| + |
| +/* --------------------------------------------------------------- |
| + * ChromeOS shim - convert dm= format to dm-mod.create= format |
| + * --------------------------------------------------------------- |
| + */ |
| + |
| +struct dm_chrome_target { |
| + char *field[4]; |
| +}; |
| + |
| +struct dm_chrome_dev { |
| + char *name, *uuid, *mode; |
| + unsigned int num_targets; |
| + struct dm_chrome_target targets[DM_MAX_TARGETS]; |
| +}; |
| + |
| +static char __init *dm_chrome_parse_target(char *str, struct dm_chrome_target *tgt) |
| +{ |
| + unsigned int i; |
| + |
| + tgt->field[0] = str; |
| + /* Delimit first 3 fields that are separated by space */ |
| + for (i = 0; i < ARRAY_SIZE(tgt->field) - 1; i++) { |
| + tgt->field[i + 1] = str_field_delimit(&tgt->field[i], ' '); |
| + if (!tgt->field[i + 1]) |
| + return NULL; |
| + } |
| + /* Delimit last field that can be terminated by comma */ |
| + return str_field_delimit(&tgt->field[i], ','); |
| +} |
| + |
| +static char __init *dm_chrome_parse_dev(char *str, struct dm_chrome_dev *dev) |
| +{ |
| + char *target, *num; |
| + unsigned int i; |
| + |
| + if (!str) |
| + return ERR_PTR(-EINVAL); |
| + |
| + target = str_field_delimit(&str, ','); |
| + if (!target) |
| + return ERR_PTR(-EINVAL); |
| + |
| + /* Delimit first 3 fields that are separated by space */ |
| + dev->name = str; |
| + dev->uuid = str_field_delimit(&dev->name, ' '); |
| + if (!dev->uuid) |
| + return ERR_PTR(-EINVAL); |
| + |
| + dev->mode = str_field_delimit(&dev->uuid, ' '); |
| + if (!dev->mode) |
| + return ERR_PTR(-EINVAL); |
| + |
| + /* num is optional */ |
| + num = str_field_delimit(&dev->mode, ' '); |
| + if (!num) |
| + dev->num_targets = 1; |
| + else { |
| + /* Delimit num and check if it the last field */ |
| + if(str_field_delimit(&num, ' ')) |
| + return ERR_PTR(-EINVAL); |
| + if (kstrtouint(num, 0, &dev->num_targets)) |
| + return ERR_PTR(-EINVAL); |
| + } |
| + |
| + if (dev->num_targets > DM_MAX_TARGETS) { |
| + DMERR("too many targets %u > %d", |
| + dev->num_targets, DM_MAX_TARGETS); |
| + return ERR_PTR(-EINVAL); |
| + } |
| + |
| + for (i = 0; i < dev->num_targets - 1; i++) { |
| + target = dm_chrome_parse_target(target, &dev->targets[i]); |
| + if (!target) |
| + return ERR_PTR(-EINVAL); |
| + } |
| + /* The last one can return NULL if it reaches the end of str */ |
| + return dm_chrome_parse_target(target, &dev->targets[i]); |
| +} |
| + |
| +static char __init *dm_chrome_convert(struct dm_chrome_dev *devs, unsigned int num_devs) |
| +{ |
| + char *str = kmalloc(DM_MAX_STR_SIZE, GFP_KERNEL); |
| + char *p = str; |
| + unsigned int i, j; |
| + int ret; |
| + |
| + if (!str) |
| + return ERR_PTR(-ENOMEM); |
| + |
| + for (i = 0; i < num_devs; i++) { |
| + if (!strcmp(devs[i].uuid, "none")) |
| + devs[i].uuid = ""; |
| + ret = snprintf(p, DM_MAX_STR_SIZE - (p - str), |
| + "%s,%s,,%s", |
| + devs[i].name, |
| + devs[i].uuid, |
| + devs[i].mode); |
| + if (ret < 0) |
| + goto out; |
| + p += ret; |
| + |
| + for (j = 0; j < devs[i].num_targets; j++) { |
| + ret = snprintf(p, DM_MAX_STR_SIZE - (p - str), |
| + ",%s %s %s %s", |
| + devs[i].targets[j].field[0], |
| + devs[i].targets[j].field[1], |
| + devs[i].targets[j].field[2], |
| + devs[i].targets[j].field[3]); |
| + if (ret < 0) |
| + goto out; |
| + p += ret; |
| + } |
| + if (i < num_devs - 1) { |
| + ret = snprintf(p, DM_MAX_STR_SIZE - (p - str), ";"); |
| + if (ret < 0) |
| + goto out; |
| + p += ret; |
| + } |
| + } |
| + |
| + return str; |
| + |
| +out: |
| + kfree(str); |
| + return ERR_PTR(ret); |
| +} |
| + |
| +/** |
| + * dm_chrome_shim - convert old dm= format used in chromeos to the new |
| + * upstream format. |
| + * |
| + * ChromeOS old format |
| + * ------------------- |
| + * <device> ::= [<num>] <device-mapper>+ |
| + * <device-mapper> ::= <head> "," <target>+ |
| + * <head> ::= <name> <uuid> <mode> [<num>] |
| + * <target> ::= <start> <length> <type> <options> "," |
| + * <mode> ::= "ro" | "rw" |
| + * <uuid> ::= xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | "none" |
| + * <type> ::= "verity" | "bootcache" | ... |
| + * |
| + * Example: |
| + * 2 vboot none ro 1, |
| + * 0 1768000 bootcache |
| + * device=aa55b119-2a47-8c45-946a-5ac57765011f+1 |
| + * signature=76e9be054b15884a9fa85973e9cb274c93afadb6 |
| + * cache_start=1768000 max_blocks=100000 size_limit=23 max_trace=20000, |
| + * vroot none ro 1, |
| + * 0 1740800 verity payload=254:0 hashtree=254:0 hashstart=1740800 alg=sha1 |
| + * root_hexdigest=76e9be054b15884a9fa85973e9cb274c93afadb6 |
| + * salt=5b3549d54d6c7a3837b9b81ed72e49463a64c03680c47835bef94d768e5646fe |
| + * |
| + * Notes: |
| + * 1. uuid is a label for the device and we set it to "none". |
| + * 2. The <num> field will be optional initially and assumed to be 1. |
| + * Once all the scripts that set these fields have been set, it will |
| + * be made mandatory. |
| + */ |
| + |
| +static char *chrome_create; |
| + |
| +static int __init dm_chrome_shim(char *arg) { |
| + if (!arg || create) |
| + return -EINVAL; |
| + chrome_create = arg; |
| + return 0; |
| +} |
| + |
| +static int __init dm_chrome_parse_devices(void) |
| +{ |
| + struct dm_chrome_dev *devs; |
| + unsigned int num_devs, i; |
| + char *next, *base_str; |
| + int ret = 0; |
| + |
| + /* Verify if dm-mod.create was not used */ |
| + if (!chrome_create || create) |
| + return -EINVAL; |
| + |
| + if (strlen(chrome_create) >= DM_MAX_STR_SIZE) { |
| + DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE); |
| + return -EINVAL; |
| + } |
| + |
| + base_str = kstrdup(chrome_create, GFP_KERNEL); |
| + if (!base_str) |
| + return -ENOMEM; |
| + |
| + next = str_field_delimit(&base_str, ' '); |
| + if (!next) { |
| + ret = -EINVAL; |
| + goto out_str; |
| + } |
| + |
| + /* if first field is not the optional <num> field */ |
| + if (kstrtouint(base_str, 0, &num_devs)) { |
| + num_devs = 1; |
| + /* rewind next pointer */ |
| + next = base_str; |
| + } |
| + |
| + if (num_devs > DM_MAX_DEVICES) { |
| + DMERR("too many devices %u > %d", num_devs, DM_MAX_DEVICES); |
| + ret = -EINVAL; |
| + goto out_str; |
| + } |
| + |
| + devs = kcalloc(num_devs, sizeof(*devs), GFP_KERNEL); |
| + if (!devs) |
| + return -ENOMEM; |
| + |
| + /* restore string */ |
| + strcpy(base_str, chrome_create); |
| + |
| + /* parse devices */ |
| + for (i = 0; i < num_devs; i++) { |
| + next = dm_chrome_parse_dev(next, &devs[i]); |
| + if (IS_ERR(next)) { |
| + DMERR("couldn't parse device"); |
| + ret = PTR_ERR(next); |
| + goto out_devs; |
| + } |
| + } |
| + |
| + create = dm_chrome_convert(devs, num_devs); |
| + if (IS_ERR(create)) { |
| + ret = PTR_ERR(create); |
| + goto out_devs; |
| + } |
| + |
| + DMDEBUG("Converting:\n\tdm=\"%s\"\n\tdm-mod.create=\"%s\"\n", |
| + chrome_create, create); |
| + |
| + /* Call upstream code */ |
| + dm_init_init(); |
| + |
| + kfree(create); |
| + |
| +out_devs: |
| + create = NULL; |
| + kfree(devs); |
| +out_str: |
| + kfree(base_str); |
| + |
| + return ret; |
| +} |
| + |
| +late_initcall(dm_chrome_parse_devices); |
| + |
| +__setup("dm=", dm_chrome_shim); |
| -- |
| 2.39.0.314.g84b9a713c41-goog |
| |