aboutsummaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorPraneeth Bajjuri2017-08-28 18:03:19 -0500
committerPraneeth Bajjuri2017-08-28 18:03:19 -0500
commitdda8acaf6f2d9bddce62c305edf6b3071f04c136 (patch)
tree612f8b7b18ff3a84184ddc0ce456b9b0287cace6 /init
parentb22bbe0c5fa4fd5eb4609108a750b28a744a643e (diff)
parenteabbcea7629d5f2ec91568f7bd104536614107db (diff)
downloadkernel-omap-6AM.1.3-rvc-video.tar.gz
kernel-omap-6AM.1.3-rvc-video.tar.xz
kernel-omap-6AM.1.3-rvc-video.zip
Merge branch 'p-ti-lsk-android-linux-4.4.y' of git://git.omapzoom.org/kernel/omap into 6AM.1.3-rvc-video6AM.1.3-rvc-video
* 'p-ti-lsk-android-linux-4.4.y' of git://git.omapzoom.org/kernel/omap: (2048 commits) ARM: dts: dra7: Remove deprecated PCI compatible string ARM: dts: dra76-evm: Enable x2 PCIe lanes ARM: dts: DRA72x: Use PCIe compatible specific to dra72 ARM: dts: DRA74x: Use PCIe compatible specific to dra74 ARM: dts: dra7: Add properties to enable PCIe x2 lane mode PCI: dwc: pci-dra7xx: Enable x2 mode support PCI: dwc: dra7xx: Add support for SoC specific compatible strings dt-bindings: PCI: dra7xx: Add properties to enable x2 lane in dra7 dt-bindings: PCI: dra7xx: Add SoC specific compatible strings ARM: dts: dra7-evm: Move pcie RC node to common file ARM: dts: dra76-evm: add higher speed MMC/SD modes Linux 4.4.84 usb: qmi_wwan: add D-Link DWM-222 device ID usb: optimize acpi companion search for usb port devices perf/x86: Fix LBR related crashes on Intel Atom pids: make task_tgid_nr_ns() safe Sanitize 'move_pages()' permission checks irqchip/atmel-aic: Fix unbalanced refcount in aic_common_rtc_irq_fixup() irqchip/atmel-aic: Fix unbalanced of_node_put() in aic_common_irq_fixup() x86/asm/64: Clear AC on NMI entries ... Signed-off-by: Praneeth Bajjuri <praneeth@ti.com> Conflicts: arch/arm/boot/dts/Makefile drivers/gpu/drm/omapdrm/dss/dispc.c
Diffstat (limited to 'init')
-rw-r--r--init/Kconfig1
-rw-r--r--init/do_mounts_dm.c556
2 files changed, 301 insertions, 256 deletions
diff --git a/init/Kconfig b/init/Kconfig
index acb6645ffda5..445af1262134 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -395,6 +395,7 @@ endchoice
395config SCHED_WALT 395config SCHED_WALT
396 bool "Support window based load tracking" 396 bool "Support window based load tracking"
397 depends on SMP 397 depends on SMP
398 depends on FAIR_GROUP_SCHED
398 help 399 help
399 This feature will allow the scheduler to maintain a tunable window 400 This feature will allow the scheduler to maintain a tunable window
400 based set of metrics for tasks and runqueues. These metrics can be 401 based set of metrics for tasks and runqueues. These metrics can be
diff --git a/init/do_mounts_dm.c b/init/do_mounts_dm.c
index ecda58df9a19..bce1c2fbb915 100644
--- a/init/do_mounts_dm.c
+++ b/init/do_mounts_dm.c
@@ -5,13 +5,17 @@
5 * 5 *
6 * This file is released under the GPL. 6 * This file is released under the GPL.
7 */ 7 */
8#include <linux/async.h>
9#include <linux/ctype.h>
8#include <linux/device-mapper.h> 10#include <linux/device-mapper.h>
9#include <linux/fs.h> 11#include <linux/fs.h>
10#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/delay.h>
11 14
12#include "do_mounts.h" 15#include "do_mounts.h"
13#include "../drivers/md/dm.h"
14 16
17#define DM_MAX_DEVICES 256
18#define DM_MAX_TARGETS 256
15#define DM_MAX_NAME 32 19#define DM_MAX_NAME 32
16#define DM_MAX_UUID 129 20#define DM_MAX_UUID 129
17#define DM_NO_UUID "none" 21#define DM_NO_UUID "none"
@@ -19,14 +23,47 @@
19#define DM_MSG_PREFIX "init" 23#define DM_MSG_PREFIX "init"
20 24
21/* Separators used for parsing the dm= argument. */ 25/* Separators used for parsing the dm= argument. */
22#define DM_FIELD_SEP ' ' 26#define DM_FIELD_SEP " "
23#define DM_LINE_SEP ',' 27#define DM_LINE_SEP ","
28#define DM_ANY_SEP DM_FIELD_SEP DM_LINE_SEP
24 29
25/* 30/*
26 * When the device-mapper and any targets are compiled into the kernel 31 * When the device-mapper and any targets are compiled into the kernel
27 * (not a module), one target may be created and used as the root device at 32 * (not a module), one or more device-mappers may be created and used
28 * boot time with the parameters given with the boot line dm=... 33 * as the root device at boot time with the parameters given with the
29 * The code for that is here. 34 * boot line dm=...
35 *
36 * Multiple device-mappers can be stacked specifing the number of
37 * devices. A device can have multiple targets if the the number of
38 * targets is specified.
39 *
40 * TODO(taysom:defect 32847)
41 * In the future, the <num> field will be mandatory.
42 *
43 * <device> ::= [<num>] <device-mapper>+
44 * <device-mapper> ::= <head> "," <target>+
45 * <head> ::= <name> <uuid> <mode> [<num>]
46 * <target> ::= <start> <length> <type> <options> ","
47 * <mode> ::= "ro" | "rw"
48 * <uuid> ::= xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | "none"
49 * <type> ::= "verity" | "bootcache" | ...
50 *
51 * Example:
52 * 2 vboot none ro 1,
53 * 0 1768000 bootcache
54 * device=aa55b119-2a47-8c45-946a-5ac57765011f+1
55 * signature=76e9be054b15884a9fa85973e9cb274c93afadb6
56 * cache_start=1768000 max_blocks=100000 size_limit=23 max_trace=20000,
57 * vroot none ro 1,
58 * 0 1740800 verity payload=254:0 hashtree=254:0 hashstart=1740800 alg=sha1
59 * root_hexdigest=76e9be054b15884a9fa85973e9cb274c93afadb6
60 * salt=5b3549d54d6c7a3837b9b81ed72e49463a64c03680c47835bef94d768e5646fe
61 *
62 * Notes:
63 * 1. uuid is a label for the device and we set it to "none".
64 * 2. The <num> field will be optional initially and assumed to be 1.
65 * Once all the scripts that set these fields have been set, it will
66 * be made mandatory.
30 */ 67 */
31 68
32struct dm_setup_target { 69struct dm_setup_target {
@@ -38,381 +75,388 @@ struct dm_setup_target {
38 struct dm_setup_target *next; 75 struct dm_setup_target *next;
39}; 76};
40 77
41static struct { 78struct dm_device {
42 int minor; 79 int minor;
43 int ro; 80 int ro;
44 char name[DM_MAX_NAME]; 81 char name[DM_MAX_NAME];
45 char uuid[DM_MAX_UUID]; 82 char uuid[DM_MAX_UUID];
46 char *targets; 83 unsigned long num_targets;
47 struct dm_setup_target *target; 84 struct dm_setup_target *target;
48 int target_count; 85 int target_count;
86 struct dm_device *next;
87};
88
89struct dm_option {
90 char *start;
91 char *next;
92 size_t len;
93 char delim;
94};
95
96static struct {
97 unsigned long num_devices;
98 char *str;
49} dm_setup_args __initdata; 99} dm_setup_args __initdata;
50 100
51static __initdata int dm_early_setup; 101static __initdata int dm_early_setup;
52 102
53static size_t __init get_dm_option(char *str, char **next, char sep) 103static int __init get_dm_option(struct dm_option *opt, const char *accept)
54{ 104{
55 size_t len = 0; 105 char *str = opt->next;
56 char *endp = NULL; 106 char *endp;
57 107
58 if (!str) 108 if (!str)
59 return 0; 109 return 0;
60 110
61 endp = strchr(str, sep); 111 str = skip_spaces(str);
112 opt->start = str;
113 endp = strpbrk(str, accept);
62 if (!endp) { /* act like strchrnul */ 114 if (!endp) { /* act like strchrnul */
63 len = strlen(str); 115 opt->len = strlen(str);
64 endp = str + len; 116 endp = str + opt->len;
65 } else { 117 } else {
66 len = endp - str; 118 opt->len = endp - str;
67 } 119 }
68 120 opt->delim = *endp;
69 if (endp == str)
70 return 0;
71
72 if (!next)
73 return len;
74
75 if (*endp == 0) { 121 if (*endp == 0) {
76 /* Don't advance past the nul. */ 122 /* Don't advance past the nul. */
77 *next = endp; 123 opt->next = endp;
78 } else { 124 } else {
79 *next = endp + 1; 125 opt->next = endp + 1;
80 } 126 }
81 return len; 127 return opt->len != 0;
82}
83
84static int __init dm_setup_args_init(void)
85{
86 dm_setup_args.minor = 0;
87 dm_setup_args.ro = 0;
88 dm_setup_args.target = NULL;
89 dm_setup_args.target_count = 0;
90 return 0;
91} 128}
92 129
93static int __init dm_setup_cleanup(void) 130static int __init dm_setup_cleanup(struct dm_device *devices)
94{ 131{
95 struct dm_setup_target *target = dm_setup_args.target; 132 struct dm_device *dev = devices;
96 struct dm_setup_target *old_target = NULL; 133
97 while (target) { 134 while (dev) {
98 kfree(target->type); 135 struct dm_device *old_dev = dev;
99 kfree(target->params); 136 struct dm_setup_target *target = dev->target;
100 old_target = target; 137 while (target) {
101 target = target->next; 138 struct dm_setup_target *old_target = target;
102 kfree(old_target); 139 kfree(target->type);
103 dm_setup_args.target_count--; 140 kfree(target->params);
141 target = target->next;
142 kfree(old_target);
143 dev->target_count--;
144 }
145 BUG_ON(dev->target_count);
146 dev = dev->next;
147 kfree(old_dev);
104 } 148 }
105 BUG_ON(dm_setup_args.target_count);
106 return 0; 149 return 0;
107} 150}
108 151
109static char * __init dm_setup_parse_device_args(char *str) 152static char * __init dm_parse_device(struct dm_device *dev, char *str)
110{ 153{
111 char *next = NULL; 154 struct dm_option opt;
112 size_t len = 0; 155 size_t len;
113 156
114 /* Grab the logical name of the device to be exported to udev */ 157 /* Grab the logical name of the device to be exported to udev */
115 len = get_dm_option(str, &next, DM_FIELD_SEP); 158 opt.next = str;
116 if (!len) { 159 if (!get_dm_option(&opt, DM_FIELD_SEP)) {
117 DMERR("failed to parse device name"); 160 DMERR("failed to parse device name");
118 goto parse_fail; 161 goto parse_fail;
119 } 162 }
120 len = min(len + 1, sizeof(dm_setup_args.name)); 163 len = min(opt.len + 1, sizeof(dev->name));
121 strlcpy(dm_setup_args.name, str, len); /* includes nul */ 164 strlcpy(dev->name, opt.start, len); /* includes nul */
122 str = skip_spaces(next);
123 165
124 /* Grab the UUID value or "none" */ 166 /* Grab the UUID value or "none" */
125 len = get_dm_option(str, &next, DM_FIELD_SEP); 167 if (!get_dm_option(&opt, DM_FIELD_SEP)) {
126 if (!len) {
127 DMERR("failed to parse device uuid"); 168 DMERR("failed to parse device uuid");
128 goto parse_fail; 169 goto parse_fail;
129 } 170 }
130 len = min(len + 1, sizeof(dm_setup_args.uuid)); 171 len = min(opt.len + 1, sizeof(dev->uuid));
131 strlcpy(dm_setup_args.uuid, str, len); 172 strlcpy(dev->uuid, opt.start, len);
132 str = skip_spaces(next);
133 173
134 /* Determine if the table/device will be read only or read-write */ 174 /* Determine if the table/device will be read only or read-write */
135 if (!strncmp("ro,", str, 3)) { 175 get_dm_option(&opt, DM_ANY_SEP);
136 dm_setup_args.ro = 1; 176 if (!strncmp("ro", opt.start, opt.len)) {
137 } else if (!strncmp("rw,", str, 3)) { 177 dev->ro = 1;
138 dm_setup_args.ro = 0; 178 } else if (!strncmp("rw", opt.start, opt.len)) {
179 dev->ro = 0;
139 } else { 180 } else {
140 DMERR("failed to parse table mode"); 181 DMERR("failed to parse table mode");
141 goto parse_fail; 182 goto parse_fail;
142 } 183 }
143 str = skip_spaces(str + 3);
144 184
145 return str; 185 /* Optional number field */
186 /* XXX: The <num> field will be mandatory in the next round */
187 if (opt.delim == DM_FIELD_SEP[0]) {
188 if (!get_dm_option(&opt, DM_LINE_SEP))
189 return NULL;
190 dev->num_targets = simple_strtoul(opt.start, NULL, 10);
191 } else {
192 dev->num_targets = 1;
193 }
194 if (dev->num_targets > DM_MAX_TARGETS) {
195 DMERR("too many targets %lu > %d",
196 dev->num_targets, DM_MAX_TARGETS);
197 }
198 return opt.next;
146 199
147parse_fail: 200parse_fail:
148 return NULL; 201 return NULL;
149} 202}
150 203
151static void __init dm_substitute_devices(char *str, size_t str_len) 204static char * __init dm_parse_targets(struct dm_device *dev, char *str)
152{ 205{
153 char *candidate = str; 206 struct dm_option opt;
154 char *candidate_end = str; 207 struct dm_setup_target **target = &dev->target;
155 char old_char; 208 unsigned long num_targets = dev->num_targets;
156 size_t len = 0; 209 unsigned long i;
157 dev_t dev;
158
159 if (str_len < 3)
160 return;
161
162 while (str && *str) {
163 candidate = strchr(str, '/');
164 if (!candidate)
165 break;
166
167 /* Avoid embedded slashes */
168 if (candidate != str && *(candidate - 1) != DM_FIELD_SEP) {
169 str = strchr(candidate, DM_FIELD_SEP);
170 continue;
171 }
172
173 len = get_dm_option(candidate, &candidate_end, DM_FIELD_SEP);
174 str = skip_spaces(candidate_end);
175 if (len < 3 || len > 37) /* name_to_dev_t max; maj:mix min */
176 continue;
177
178 /* Temporarily terminate with a nul */
179 if (*candidate_end)
180 candidate_end--;
181 old_char = *candidate_end;
182 *candidate_end = '\0';
183
184 DMDEBUG("converting candidate device '%s' to dev_t", candidate);
185 /* Use the boot-time specific device naming */
186 dev = name_to_dev_t(candidate);
187 *candidate_end = old_char;
188
189 DMDEBUG(" -> %u", dev);
190 /* No suitable replacement found */
191 if (!dev)
192 continue;
193
194 /* Rewrite the /dev/path as a major:minor */
195 len = snprintf(candidate, len, "%u:%u", MAJOR(dev), MINOR(dev));
196 if (!len) {
197 DMERR("error substituting device major/minor.");
198 break;
199 }
200 candidate += len;
201 /* Pad out with spaces (fixing our nul) */
202 while (candidate < candidate_end)
203 *(candidate++) = DM_FIELD_SEP;
204 }
205}
206
207static int __init dm_setup_parse_targets(char *str)
208{
209 char *next = NULL;
210 size_t len = 0;
211 struct dm_setup_target **target = NULL;
212 210
213 /* Targets are defined as per the table format but with a 211 /* Targets are defined as per the table format but with a
214 * comma as a newline separator. */ 212 * comma as a newline separator. */
215 target = &dm_setup_args.target; 213 opt.next = str;
216 while (str && *str) { 214 for (i = 0; i < num_targets; i++) {
217 *target = kzalloc(sizeof(struct dm_setup_target), GFP_KERNEL); 215 *target = kzalloc(sizeof(struct dm_setup_target), GFP_KERNEL);
218 if (!*target) { 216 if (!*target) {
219 DMERR("failed to allocate memory for target %d", 217 DMERR("failed to allocate memory for target %s<%ld>",
220 dm_setup_args.target_count); 218 dev->name, i);
221 goto parse_fail; 219 goto parse_fail;
222 } 220 }
223 dm_setup_args.target_count++; 221 dev->target_count++;
224 222
225 (*target)->begin = simple_strtoull(str, &next, 10); 223 if (!get_dm_option(&opt, DM_FIELD_SEP)) {
226 if (!next || *next != DM_FIELD_SEP) { 224 DMERR("failed to parse starting sector"
227 DMERR("failed to parse starting sector for target %d", 225 " for target %s<%ld>", dev->name, i);
228 dm_setup_args.target_count - 1);
229 goto parse_fail; 226 goto parse_fail;
230 } 227 }
231 str = skip_spaces(next + 1); 228 (*target)->begin = simple_strtoull(opt.start, NULL, 10);
232 229
233 (*target)->length = simple_strtoull(str, &next, 10); 230 if (!get_dm_option(&opt, DM_FIELD_SEP)) {
234 if (!next || *next != DM_FIELD_SEP) { 231 DMERR("failed to parse length for target %s<%ld>",
235 DMERR("failed to parse length for target %d", 232 dev->name, i);
236 dm_setup_args.target_count - 1);
237 goto parse_fail; 233 goto parse_fail;
238 } 234 }
239 str = skip_spaces(next + 1); 235 (*target)->length = simple_strtoull(opt.start, NULL, 10);
240 236
241 len = get_dm_option(str, &next, DM_FIELD_SEP); 237 if (get_dm_option(&opt, DM_FIELD_SEP))
242 if (!len || 238 (*target)->type = kstrndup(opt.start, opt.len,
243 !((*target)->type = kstrndup(str, len, GFP_KERNEL))) { 239 GFP_KERNEL);
244 DMERR("failed to parse type for target %d", 240 if (!((*target)->type)) {
245 dm_setup_args.target_count - 1); 241 DMERR("failed to parse type for target %s<%ld>",
242 dev->name, i);
246 goto parse_fail; 243 goto parse_fail;
247 } 244 }
248 str = skip_spaces(next); 245 if (get_dm_option(&opt, DM_LINE_SEP))
249 246 (*target)->params = kstrndup(opt.start, opt.len,
250 len = get_dm_option(str, &next, DM_LINE_SEP); 247 GFP_KERNEL);
251 if (!len || 248 if (!((*target)->params)) {
252 !((*target)->params = kstrndup(str, len, GFP_KERNEL))) { 249 DMERR("failed to parse params for target %s<%ld>",
253 DMERR("failed to parse params for target %d", 250 dev->name, i);
254 dm_setup_args.target_count - 1);
255 goto parse_fail; 251 goto parse_fail;
256 } 252 }
257 str = skip_spaces(next);
258
259 /* Before moving on, walk through the copied target and
260 * attempt to replace all /dev/xxx with the major:minor number.
261 * It may not be possible to resolve them traditionally at
262 * boot-time. */
263 dm_substitute_devices((*target)->params, len);
264
265 target = &((*target)->next); 253 target = &((*target)->next);
266 } 254 }
267 DMDEBUG("parsed %d targets", dm_setup_args.target_count); 255 DMDEBUG("parsed %d targets", dev->target_count);
268 256
269 return 0; 257 return opt.next;
270 258
271parse_fail: 259parse_fail:
272 return 1; 260 return NULL;
261}
262
263static struct dm_device * __init dm_parse_args(void)
264{
265 struct dm_device *devices = NULL;
266 struct dm_device **tail = &devices;
267 struct dm_device *dev;
268 char *str = dm_setup_args.str;
269 unsigned long num_devices = dm_setup_args.num_devices;
270 unsigned long i;
271
272 if (!str)
273 return NULL;
274 for (i = 0; i < num_devices; i++) {
275 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
276 if (!dev) {
277 DMERR("failed to allocated memory for dev");
278 goto error;
279 }
280 *tail = dev;
281 tail = &dev->next;
282 /*
283 * devices are given minor numbers 0 - n-1
284 * in the order they are found in the arg
285 * string.
286 */
287 dev->minor = i;
288 str = dm_parse_device(dev, str);
289 if (!str) /* NULL indicates error in parsing, bail */
290 goto error;
291
292 str = dm_parse_targets(dev, str);
293 if (!str)
294 goto error;
295 }
296 return devices;
297error:
298 dm_setup_cleanup(devices);
299 return NULL;
273} 300}
274 301
275/* 302/*
276 * Parse the command-line parameters given our kernel, but do not 303 * Parse the command-line parameters given our kernel, but do not
277 * actually try to invoke the DM device now; that is handled by 304 * actually try to invoke the DM device now; that is handled by
278 * dm_setup_drive after the low-level disk drivers have initialised. 305 * dm_setup_drives after the low-level disk drivers have initialised.
279 * dm format is as follows: 306 * dm format is described at the top of the file.
280 * dm="name uuid fmode,[table line 1],[table line 2],..." 307 *
281 * May be used with root=/dev/dm-0 as it always uses the first dm minor. 308 * Because dm minor numbers are assigned in assending order starting with 0,
309 * You can assume the first device is /dev/dm-0, the next device is /dev/dm-1,
310 * and so forth.
282 */ 311 */
283
284static int __init dm_setup(char *str) 312static int __init dm_setup(char *str)
285{ 313{
286 dm_setup_args_init(); 314 struct dm_option opt;
315 unsigned long num_devices;
287 316
288 str = dm_setup_parse_device_args(str);
289 if (!str) { 317 if (!str) {
290 DMDEBUG("str is NULL"); 318 DMDEBUG("str is NULL");
291 goto parse_fail; 319 goto parse_fail;
292 } 320 }
293 321 opt.next = str;
294 /* Target parsing is delayed until we have dynamic memory */ 322 if (!get_dm_option(&opt, DM_FIELD_SEP))
295 dm_setup_args.targets = str; 323 goto parse_fail;
296 324 if (isdigit(opt.start[0])) { /* XXX: Optional number field */
297 printk(KERN_INFO "dm: will configure '%s' on dm-%d\n", 325 num_devices = simple_strtoul(opt.start, NULL, 10);
298 dm_setup_args.name, dm_setup_args.minor); 326 str = opt.next;
299 327 } else {
328 num_devices = 1;
329 /* Don't advance str */
330 }
331 if (num_devices > DM_MAX_DEVICES) {
332 DMDEBUG("too many devices %lu > %d",
333 num_devices, DM_MAX_DEVICES);
334 }
335 dm_setup_args.str = str;
336 dm_setup_args.num_devices = num_devices;
337 DMINFO("will configure %lu devices", num_devices);
300 dm_early_setup = 1; 338 dm_early_setup = 1;
301 return 1; 339 return 1;
302 340
303parse_fail: 341parse_fail:
304 printk(KERN_WARNING "dm: Invalid arguments supplied to dm=.\n"); 342 DMWARN("Invalid arguments supplied to dm=.");
305 return 0; 343 return 0;
306} 344}
307 345
308 346static void __init dm_setup_drives(void)
309static void __init dm_setup_drive(void)
310{ 347{
311 struct mapped_device *md = NULL; 348 struct mapped_device *md = NULL;
312 struct dm_table *table = NULL; 349 struct dm_table *table = NULL;
313 struct dm_setup_target *target; 350 struct dm_setup_target *target;
314 char *uuid = dm_setup_args.uuid; 351 struct dm_device *dev;
352 char *uuid;
315 fmode_t fmode = FMODE_READ; 353 fmode_t fmode = FMODE_READ;
354 struct dm_device *devices;
316 355
317 /* Finish parsing the targets. */ 356 devices = dm_parse_args();
318 if (dm_setup_parse_targets(dm_setup_args.targets))
319 goto parse_fail;
320
321 if (dm_create(dm_setup_args.minor, &md)) {
322 DMDEBUG("failed to create the device");
323 goto dm_create_fail;
324 }
325 DMDEBUG("created device '%s'", dm_device_name(md));
326
327 /* In addition to flagging the table below, the disk must be
328 * set explicitly ro/rw. */
329 set_disk_ro(dm_disk(md), dm_setup_args.ro);
330 357
331 if (!dm_setup_args.ro) 358 for (dev = devices; dev; dev = dev->next) {
332 fmode |= FMODE_WRITE; 359 if (dm_create(dev->minor, &md)) {
333 if (dm_table_create(&table, fmode, dm_setup_args.target_count, md)) { 360 DMDEBUG("failed to create the device");
334 DMDEBUG("failed to create the table"); 361 goto dm_create_fail;
335 goto dm_table_create_fail; 362 }
336 } 363 DMDEBUG("created device '%s'", dm_device_name(md));
364
365 /*
366 * In addition to flagging the table below, the disk must be
367 * set explicitly ro/rw.
368 */
369 set_disk_ro(dm_disk(md), dev->ro);
370
371 if (!dev->ro)
372 fmode |= FMODE_WRITE;
373 if (dm_table_create(&table, fmode, dev->target_count, md)) {
374 DMDEBUG("failed to create the table");
375 goto dm_table_create_fail;
376 }
337 377
338 dm_lock_md_type(md); 378 dm_lock_md_type(md);
339 target = dm_setup_args.target; 379
340 while (target) { 380 for (target = dev->target; target; target = target->next) {
341 DMINFO("adding target '%llu %llu %s %s'", 381 DMINFO("adding target '%llu %llu %s %s'",
342 (unsigned long long) target->begin, 382 (unsigned long long) target->begin,
343 (unsigned long long) target->length, target->type, 383 (unsigned long long) target->length,
344 target->params); 384 target->type, target->params);
345 if (dm_table_add_target(table, target->type, target->begin, 385 if (dm_table_add_target(table, target->type,
346 target->length, target->params)) { 386 target->begin,
347 DMDEBUG("failed to add the target to the table"); 387 target->length,
348 goto add_target_fail; 388 target->params)) {
389 DMDEBUG("failed to add the target"
390 " to the table");
391 goto add_target_fail;
392 }
393 }
394 if (dm_table_complete(table)) {
395 DMDEBUG("failed to complete the table");
396 goto table_complete_fail;
349 } 397 }
350 target = target->next;
351 }
352 398
353 if (dm_table_complete(table)) { 399 /* Suspend the device so that we can bind it to the table. */
354 DMDEBUG("failed to complete the table"); 400 if (dm_suspend(md, 0)) {
355 goto table_complete_fail; 401 DMDEBUG("failed to suspend the device pre-bind");
356 } 402 goto suspend_fail;
403 }
357 404
358 if (dm_get_md_type(md) == DM_TYPE_NONE) { 405 /* Initial table load: acquire type of table. */
359 dm_set_md_type(md, dm_table_get_type(table)); 406 dm_set_md_type(md, dm_table_get_type(table));
407
408 /* Setup md->queue to reflect md's type. */
360 if (dm_setup_md_queue(md)) { 409 if (dm_setup_md_queue(md)) {
361 DMWARN("unable to set up device queue for new table."); 410 DMWARN("unable to set up device queue for new table.");
362 goto setup_md_queue_fail; 411 goto setup_md_queue_fail;
363 } 412 }
364 } else if (dm_get_md_type(md) != dm_table_get_type(table)) {
365 DMWARN("can't change device type after initial table load.");
366 goto setup_md_queue_fail;
367 }
368
369 /* Suspend the device so that we can bind it to the table. */
370 if (dm_suspend(md, 0)) {
371 DMDEBUG("failed to suspend the device pre-bind");
372 goto suspend_fail;
373 }
374 413
375 /* Bind the table to the device. This is the only way to associate 414 /*
376 * md->map with the table and set the disk capacity directly. */ 415 * Bind the table to the device. This is the only way
377 if (dm_swap_table(md, table)) { /* should return NULL. */ 416 * to associate md->map with the table and set the disk
378 DMDEBUG("failed to bind the device to the table"); 417 * capacity directly.
379 goto table_bind_fail; 418 */
380 } 419 if (dm_swap_table(md, table)) { /* should return NULL. */
420 DMDEBUG("failed to bind the device to the table");
421 goto table_bind_fail;
422 }
381 423
382 /* Finally, resume and the device should be ready. */ 424 /* Finally, resume and the device should be ready. */
383 if (dm_resume(md)) { 425 if (dm_resume(md)) {
384 DMDEBUG("failed to resume the device"); 426 DMDEBUG("failed to resume the device");
385 goto resume_fail; 427 goto resume_fail;
386 } 428 }
387 429
388 /* Export the dm device via the ioctl interface */ 430 /* Export the dm device via the ioctl interface */
389 if (!strcmp(DM_NO_UUID, dm_setup_args.uuid)) 431 if (!strcmp(DM_NO_UUID, dev->uuid))
390 uuid = NULL; 432 uuid = NULL;
391 if (dm_ioctl_export(md, dm_setup_args.name, uuid)) { 433 if (dm_ioctl_export(md, dev->name, uuid)) {
392 DMDEBUG("failed to export device with given name and uuid"); 434 DMDEBUG("failed to export device with given"
393 goto export_fail; 435 " name and uuid");
394 } 436 goto export_fail;
395 printk(KERN_INFO "dm: dm-%d is ready\n", dm_setup_args.minor); 437 }
396 438
397 dm_unlock_md_type(md); 439 dm_unlock_md_type(md);
398 dm_setup_cleanup(); 440
441 DMINFO("dm-%d is ready", dev->minor);
442 }
443 dm_setup_cleanup(devices);
399 return; 444 return;
400 445
401export_fail: 446export_fail:
402resume_fail: 447resume_fail:
403table_bind_fail: 448table_bind_fail:
404suspend_fail:
405setup_md_queue_fail: 449setup_md_queue_fail:
450suspend_fail:
406table_complete_fail: 451table_complete_fail:
407add_target_fail: 452add_target_fail:
408 dm_unlock_md_type(md); 453 dm_unlock_md_type(md);
409dm_table_create_fail: 454dm_table_create_fail:
410 dm_put(md); 455 dm_put(md);
411dm_create_fail: 456dm_create_fail:
412 dm_setup_cleanup(); 457 DMWARN("starting dm-%d (%s) failed",
413parse_fail: 458 dev->minor, dev->name);
414 printk(KERN_WARNING "dm: starting dm-%d (%s) failed\n", 459 dm_setup_cleanup(devices);
415 dm_setup_args.minor, dm_setup_args.name);
416} 460}
417 461
418__setup("dm=", dm_setup); 462__setup("dm=", dm_setup);
@@ -421,6 +465,6 @@ void __init dm_run_setup(void)
421{ 465{
422 if (!dm_early_setup) 466 if (!dm_early_setup)
423 return; 467 return;
424 printk(KERN_INFO "dm: attempting early device configuration.\n"); 468 DMINFO("attempting early device configuration.");
425 dm_setup_drive(); 469 dm_setup_drives();
426} 470}