^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * dm-init.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2017 The Chromium OS Authors <chromium-os-dev@chromium.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This file is released under the GPLv2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/device-mapper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define DM_MSG_PREFIX "init"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define DM_MAX_DEVICES 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define DM_MAX_TARGETS 256
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define DM_MAX_STR_SIZE 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static char *create;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Format: dm-mod.create=<name>,<uuid>,<minor>,<flags>,<table>[,<table>+][;<name>,<uuid>,<minor>,<flags>,<table>[,<table>+]+]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Table format: <start_sector> <num_sectors> <target_type> <target_args>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * See Documentation/admin-guide/device-mapper/dm-init.rst for dm-mod.create="..." format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct dm_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct dm_ioctl dmi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct dm_target_spec *table[DM_MAX_TARGETS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) char *target_args_array[DM_MAX_TARGETS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) static const char * const dm_allowed_targets[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) "crypt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) "delay",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) "linear",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) "snapshot-origin",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) "striped",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) "verity",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int __init dm_verify_target_type(const char *target)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) for (i = 0; i < ARRAY_SIZE(dm_allowed_targets); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!strcmp(dm_allowed_targets[i], target))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void __init dm_setup_cleanup(struct list_head *devices)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct dm_device *dev, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) list_for_each_entry_safe(dev, tmp, devices, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) list_del(&dev->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) for (i = 0; i < dev->dmi.target_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) kfree(dev->table[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) kfree(dev->target_args_array[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) kfree(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * str_field_delimit - delimit a string based on a separator char.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * @str: the pointer to the string to delimit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * @separator: char that delimits the field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * Find a @separator and replace it by '\0'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * Remove leading and trailing spaces.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * Return the remainder string after the @separator.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static char __init *str_field_delimit(char **str, char separator)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* TODO: add support for escaped characters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *str = skip_spaces(*str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) s = strchr(*str, separator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* Delimit the field and remove trailing spaces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *s = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) *str = strim(*str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return s ? ++s : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * dm_parse_table_entry - parse a table entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * @dev: device to store the parsed information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * @str: the pointer to a string with the format:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * <start_sector> <num_sectors> <target_type> <target_args>[, ...]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * Return the remainder string after the table entry, i.e, after the comma which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * delimits the entry or NULL if reached the end of the string.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static char __init *dm_parse_table_entry(struct dm_device *dev, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) const unsigned int n = dev->dmi.target_count - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct dm_target_spec *sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* fields: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) char *field[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) char *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) field[0] = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Delimit first 3 fields that are separated by space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) for (i = 0; i < ARRAY_SIZE(field) - 1; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) field[i + 1] = str_field_delimit(&field[i], ' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (!field[i + 1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* Delimit last field that can be terminated by comma */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) next = str_field_delimit(&field[i], ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) sp = kzalloc(sizeof(*sp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dev->table[n] = sp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* start_sector */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (kstrtoull(field[0], 0, &sp->sector_start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) /* num_sector */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (kstrtoull(field[1], 0, &sp->length))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* target_type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) strscpy(sp->target_type, field[2], sizeof(sp->target_type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (dm_verify_target_type(sp->target_type)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) DMERR("invalid type \"%s\"", sp->target_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* target_args */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!dev->target_args_array[n])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * dm_parse_table - parse "dm-mod.create=" table field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * @dev: device to store the parsed information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @str: the pointer to a string with the format:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * <table>[,<table>+]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static int __init dm_parse_table(struct dm_device *dev, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) char *table_entry = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) while (table_entry) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) DMDEBUG("parsing table \"%s\"", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (++dev->dmi.target_count > DM_MAX_TARGETS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) DMERR("too many targets %u > %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) dev->dmi.target_count, DM_MAX_TARGETS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) table_entry = dm_parse_table_entry(dev, table_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (IS_ERR(table_entry)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) DMERR("couldn't parse table");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return PTR_ERR(table_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * dm_parse_device_entry - parse a device entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * @dev: device to store the parsed information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * @str: the pointer to a string with the format:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * name,uuid,minor,flags,table[; ...]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * Return the remainder string after the table entry, i.e, after the semi-colon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * which delimits the entry or NULL if reached the end of the string.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static char __init *dm_parse_device_entry(struct dm_device *dev, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* There are 5 fields: name,uuid,minor,flags,table; */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) char *field[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) char *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) field[0] = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* Delimit first 4 fields that are separated by comma */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) for (i = 0; i < ARRAY_SIZE(field) - 1; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) field[i+1] = str_field_delimit(&field[i], ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (!field[i+1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* Delimit last field that can be delimited by semi-colon */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) next = str_field_delimit(&field[i], ';');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) strscpy(dev->dmi.name, field[0], sizeof(dev->dmi.name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* uuid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) strscpy(dev->dmi.uuid, field[1], sizeof(dev->dmi.uuid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* minor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (strlen(field[2])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (kstrtoull(field[2], 0, &dev->dmi.dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) dev->dmi.flags |= DM_PERSISTENT_DEV_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /* flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (!strcmp(field[3], "ro"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) dev->dmi.flags |= DM_READONLY_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) else if (strcmp(field[3], "rw"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (dm_parse_table(dev, field[4]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * dm_parse_devices - parse "dm-mod.create=" argument
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * @devices: list of struct dm_device to store the parsed information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * @str: the pointer to a string with the format:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * <device>[;<device>+]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static int __init dm_parse_devices(struct list_head *devices, char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unsigned long ndev = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) struct dm_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) char *device = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) DMDEBUG("parsing \"%s\"", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) while (device) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) dev = kzalloc(sizeof(*dev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) list_add_tail(&dev->list, devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (++ndev > DM_MAX_DEVICES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) DMERR("too many devices %lu > %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ndev, DM_MAX_DEVICES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) device = dm_parse_device_entry(dev, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (IS_ERR(device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) DMERR("couldn't parse device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return PTR_ERR(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * dm_init_init - parse "dm-mod.create=" argument and configure drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static int __init dm_init_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct dm_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) LIST_HEAD(devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) char *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (!create)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (strlen(create) >= DM_MAX_STR_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (!str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) r = dm_parse_devices(&devices, str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) DMINFO("waiting for all devices to be available before creating mapped devices");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) wait_for_device_probe();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) list_for_each_entry(dev, &devices, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (dm_early_create(&dev->dmi, dev->table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) dev->target_args_array))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) kfree(str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dm_setup_cleanup(&devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) late_initcall(dm_init_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) module_param(create, charp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) MODULE_PARM_DESC(create, "Create a mapped device in early boot");