Annotation of /trunk/mkinitrd-magellan/klibc/usr/kinit/do_mounts_md.c
Parent Directory | Revision Log
Revision 815 -
(hide annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 9571 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 9571 byte(s)
-updated to klibc-1.5.15
1 | niro | 532 | /* |
2 | * Handle autoconfiguration of md devices. This is ugly, partially since | ||
3 | * it still relies on a sizable kernel component. | ||
4 | * | ||
5 | * This file is derived from the Linux kernel. | ||
6 | */ | ||
7 | |||
8 | #include <ctype.h> | ||
9 | #include <errno.h> | ||
10 | #include <fcntl.h> | ||
11 | #include <sys/mount.h> | ||
12 | #include <sys/stat.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <string.h> | ||
16 | #include <unistd.h> | ||
17 | #include <alloca.h> | ||
18 | #include <inttypes.h> | ||
19 | #include <sys/sysmacros.h> | ||
20 | #include <sys/md.h> | ||
21 | #include <linux/major.h> | ||
22 | |||
23 | niro | 815 | #include "kinit.h" |
24 | niro | 532 | #include "do_mounts.h" |
25 | |||
26 | #define LEVEL_NONE (-1000000) | ||
27 | |||
28 | /* | ||
29 | * When md (and any require personalities) are compiled into the kernel | ||
30 | * (not a module), arrays can be assembles are boot time using with AUTODETECT | ||
31 | * where specially marked partitions are registered with md_autodetect_dev(), | ||
32 | * and with MD_BOOT where devices to be collected are given on the boot line | ||
33 | * with md=..... | ||
34 | * The code for that is here. | ||
35 | */ | ||
36 | |||
37 | static int raid_noautodetect, raid_autopart; | ||
38 | |||
39 | static struct { | ||
40 | int minor; | ||
41 | int partitioned; | ||
42 | int level; | ||
43 | int chunk; | ||
44 | char *device_names; | ||
45 | } md_setup_args[MAX_MD_DEVS]; | ||
46 | |||
47 | static int md_setup_ents; | ||
48 | |||
49 | /** | ||
50 | * get_option - Parse integer from an option string | ||
51 | * @str: option string | ||
52 | * @pint: (output) integer value parsed from @str | ||
53 | * | ||
54 | * Read an int from an option string; if available accept a subsequent | ||
55 | * comma as well. | ||
56 | * | ||
57 | * Return values: | ||
58 | * 0 : no int in string | ||
59 | * 1 : int found, no subsequent comma | ||
60 | * 2 : int found including a subsequent comma | ||
61 | */ | ||
62 | |||
63 | static int get_option(char **str, int *pint) | ||
64 | { | ||
65 | char *cur = *str; | ||
66 | |||
67 | if (!cur || !(*cur)) | ||
68 | return 0; | ||
69 | *pint = strtol(cur, str, 0); | ||
70 | if (cur == *str) | ||
71 | return 0; | ||
72 | if (**str == ',') { | ||
73 | (*str)++; | ||
74 | return 2; | ||
75 | } | ||
76 | |||
77 | return 1; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Find the partitioned md device major number... of course this *HAD* | ||
82 | * to be done dynamically instead of using a registered number. | ||
83 | * Sigh. Double sigh. | ||
84 | */ | ||
85 | static int mdp_major(void) | ||
86 | { | ||
87 | static int found = 0; | ||
88 | FILE *f; | ||
89 | char line[512], *p; | ||
90 | int is_blk, major_no; | ||
91 | |||
92 | if (found) | ||
93 | return found; | ||
94 | |||
95 | f = fopen("/proc/devices", "r"); | ||
96 | is_blk = 0; | ||
97 | while (fgets(line, sizeof line, f)) { | ||
98 | if (!strcmp(line, "Block devices:\n")) | ||
99 | is_blk = 1; | ||
100 | if (is_blk) { | ||
101 | major_no = strtol(line, &p, 10); | ||
102 | while (*p && isspace(*p)) | ||
103 | p++; | ||
104 | |||
105 | if (major_no == 0) /* Not a number */ | ||
106 | is_blk = 0; | ||
107 | else if (major_no > 0 && !strcmp(p, "mdp")) { | ||
108 | found = major_no; | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | fclose(f); | ||
114 | |||
115 | if (!found) { | ||
116 | fprintf(stderr, | ||
117 | "Error: mdp devices detected but no mdp device found!\n"); | ||
118 | exit(1); | ||
119 | } | ||
120 | |||
121 | return found; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Parse the command-line parameters given our kernel, but do not | ||
126 | * actually try to invoke the MD device now; that is handled by | ||
127 | * md_setup_drive after the low-level disk drivers have initialised. | ||
128 | * | ||
129 | * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which | ||
130 | * assigns the task of parsing integer arguments to the | ||
131 | * invoked program now). Added ability to initialise all | ||
132 | * the MD devices (by specifying multiple "md=" lines) | ||
133 | * instead of just one. -- KTK | ||
134 | * 18May2000: Added support for persistent-superblock arrays: | ||
135 | * md=n,0,factor,fault,device-list uses RAID0 for device n | ||
136 | * md=n,-1,factor,fault,device-list uses LINEAR for device n | ||
137 | * md=n,device-list reads a RAID superblock from the devices | ||
138 | * elements in device-list are read by name_to_kdev_t so can be | ||
139 | * a hex number or something like /dev/hda1 /dev/sdb | ||
140 | * 2001-06-03: Dave Cinege <dcinege@psychosis.com> | ||
141 | * Shifted name_to_kdev_t() and related operations to md_set_drive() | ||
142 | * for later execution. Rewrote section to make devfs compatible. | ||
143 | */ | ||
144 | static int md_setup(char *str) | ||
145 | { | ||
146 | niro | 815 | int minor_num, level, factor, fault, partitioned = 0; |
147 | niro | 532 | char *pername = ""; |
148 | char *str1; | ||
149 | int ent; | ||
150 | |||
151 | if (*str == 'd') { | ||
152 | partitioned = 1; | ||
153 | str++; | ||
154 | } | ||
155 | niro | 815 | if (get_option(&str, &minor_num) != 2) { /* MD Number */ |
156 | niro | 532 | fprintf(stderr, "md: Too few arguments supplied to md=.\n"); |
157 | return 0; | ||
158 | } | ||
159 | str1 = str; | ||
160 | niro | 815 | if (minor_num >= MAX_MD_DEVS) { |
161 | niro | 532 | fprintf(stderr, "md: md=%d, Minor device number too high.\n", |
162 | niro | 815 | minor_num); |
163 | niro | 532 | return 0; |
164 | } | ||
165 | for (ent = 0; ent < md_setup_ents; ent++) | ||
166 | niro | 815 | if (md_setup_args[ent].minor == minor_num && |
167 | niro | 532 | md_setup_args[ent].partitioned == partitioned) { |
168 | fprintf(stderr, | ||
169 | "md: md=%s%d, Specified more than once. " | ||
170 | "Replacing previous definition.\n", | ||
171 | niro | 815 | partitioned ? "d" : "", minor_num); |
172 | niro | 532 | break; |
173 | } | ||
174 | if (ent >= MAX_MD_DEVS) { | ||
175 | fprintf(stderr, "md: md=%s%d - too many md initialisations\n", | ||
176 | niro | 815 | partitioned ? "d" : "", minor_num); |
177 | niro | 532 | return 0; |
178 | } | ||
179 | if (ent >= md_setup_ents) | ||
180 | md_setup_ents++; | ||
181 | switch (get_option(&str, &level)) { /* RAID level */ | ||
182 | case 2: /* could be 0 or -1.. */ | ||
183 | if (level == 0 || level == LEVEL_LINEAR) { | ||
184 | if (get_option(&str, &factor) != 2 || /* Chunk Size */ | ||
185 | get_option(&str, &fault) != 2) { | ||
186 | fprintf(stderr, | ||
187 | "md: Too few arguments supplied to md=.\n"); | ||
188 | return 0; | ||
189 | } | ||
190 | md_setup_args[ent].level = level; | ||
191 | md_setup_args[ent].chunk = 1 << (factor + 12); | ||
192 | if (level == LEVEL_LINEAR) | ||
193 | pername = "linear"; | ||
194 | else | ||
195 | pername = "raid0"; | ||
196 | break; | ||
197 | } | ||
198 | /* FALL THROUGH */ | ||
199 | case 1: /* the first device is numeric */ | ||
200 | str = str1; | ||
201 | /* FALL THROUGH */ | ||
202 | case 0: | ||
203 | md_setup_args[ent].level = LEVEL_NONE; | ||
204 | pername = "super-block"; | ||
205 | } | ||
206 | |||
207 | fprintf(stderr, "md: Will configure md%s%d (%s) from %s, below.\n", | ||
208 | niro | 815 | partitioned?"_d":"", minor_num, pername, str); |
209 | niro | 532 | md_setup_args[ent].device_names = str; |
210 | md_setup_args[ent].partitioned = partitioned; | ||
211 | niro | 815 | md_setup_args[ent].minor = minor_num; |
212 | niro | 532 | |
213 | return 1; | ||
214 | } | ||
215 | |||
216 | #define MdpMinorShift 6 | ||
217 | |||
218 | static void md_setup_drive(void) | ||
219 | { | ||
220 | int dev_minor, i, ent, partitioned; | ||
221 | dev_t dev; | ||
222 | dev_t devices[MD_SB_DISKS + 1]; | ||
223 | |||
224 | for (ent = 0; ent < md_setup_ents; ent++) { | ||
225 | int fd; | ||
226 | int err = 0; | ||
227 | char *devname; | ||
228 | mdu_disk_info_t dinfo; | ||
229 | char name[16]; | ||
230 | niro | 815 | struct stat st_chk; |
231 | niro | 532 | |
232 | dev_minor = md_setup_args[ent].minor; | ||
233 | partitioned = md_setup_args[ent].partitioned; | ||
234 | devname = md_setup_args[ent].device_names; | ||
235 | |||
236 | snprintf(name, sizeof name, | ||
237 | "/dev/md%s%d", partitioned ? "_d" : "", dev_minor); | ||
238 | |||
239 | niro | 815 | if (stat(name, &st_chk) == 0) |
240 | continue; | ||
241 | |||
242 | niro | 532 | if (partitioned) |
243 | dev = makedev(mdp_major(), dev_minor << MdpMinorShift); | ||
244 | else | ||
245 | dev = makedev(MD_MAJOR, dev_minor); | ||
246 | create_dev(name, dev); | ||
247 | for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { | ||
248 | char *p; | ||
249 | |||
250 | p = strchr(devname, ','); | ||
251 | if (p) | ||
252 | *p++ = 0; | ||
253 | |||
254 | dev = name_to_dev_t(devname); | ||
255 | if (!dev) { | ||
256 | fprintf(stderr, "md: Unknown device name: %s\n", | ||
257 | devname); | ||
258 | break; | ||
259 | } | ||
260 | |||
261 | devices[i] = dev; | ||
262 | |||
263 | devname = p; | ||
264 | } | ||
265 | devices[i] = 0; | ||
266 | |||
267 | if (!i) | ||
268 | continue; | ||
269 | |||
270 | fprintf(stderr, "md: Loading md%s%d: %s\n", | ||
271 | partitioned ? "_d" : "", dev_minor, | ||
272 | md_setup_args[ent].device_names); | ||
273 | |||
274 | fd = open(name, 0, 0); | ||
275 | if (fd < 0) { | ||
276 | fprintf(stderr, "md: open failed - cannot start " | ||
277 | "array %s\n", name); | ||
278 | continue; | ||
279 | } | ||
280 | if (ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { | ||
281 | fprintf(stderr, | ||
282 | "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", | ||
283 | dev_minor); | ||
284 | close(fd); | ||
285 | continue; | ||
286 | } | ||
287 | |||
288 | if (md_setup_args[ent].level != LEVEL_NONE) { | ||
289 | /* non-persistent */ | ||
290 | mdu_array_info_t ainfo; | ||
291 | ainfo.level = md_setup_args[ent].level; | ||
292 | ainfo.size = 0; | ||
293 | ainfo.nr_disks = 0; | ||
294 | ainfo.raid_disks = 0; | ||
295 | while (devices[ainfo.raid_disks]) | ||
296 | ainfo.raid_disks++; | ||
297 | ainfo.md_minor = dev_minor; | ||
298 | ainfo.not_persistent = 1; | ||
299 | |||
300 | ainfo.state = (1 << MD_SB_CLEAN); | ||
301 | ainfo.layout = 0; | ||
302 | ainfo.chunk_size = md_setup_args[ent].chunk; | ||
303 | err = ioctl(fd, SET_ARRAY_INFO, &ainfo); | ||
304 | for (i = 0; !err && i <= MD_SB_DISKS; i++) { | ||
305 | dev = devices[i]; | ||
306 | if (!dev) | ||
307 | break; | ||
308 | dinfo.number = i; | ||
309 | dinfo.raid_disk = i; | ||
310 | dinfo.state = | ||
311 | (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC); | ||
312 | dinfo.major = major(dev); | ||
313 | dinfo.minor = minor(dev); | ||
314 | err = ioctl(fd, ADD_NEW_DISK, &dinfo); | ||
315 | } | ||
316 | } else { | ||
317 | /* persistent */ | ||
318 | for (i = 0; i <= MD_SB_DISKS; i++) { | ||
319 | dev = devices[i]; | ||
320 | if (!dev) | ||
321 | break; | ||
322 | dinfo.major = major(dev); | ||
323 | dinfo.minor = minor(dev); | ||
324 | ioctl(fd, ADD_NEW_DISK, &dinfo); | ||
325 | } | ||
326 | } | ||
327 | if (!err) | ||
328 | err = ioctl(fd, RUN_ARRAY, 0); | ||
329 | if (err) | ||
330 | fprintf(stderr, "md: starting md%d failed\n", | ||
331 | dev_minor); | ||
332 | else { | ||
333 | /* reread the partition table. | ||
334 | * I (neilb) and not sure why this is needed, but I cannot | ||
335 | * boot a kernel with devfs compiled in from partitioned md | ||
336 | * array without it | ||
337 | */ | ||
338 | close(fd); | ||
339 | fd = open(name, 0, 0); | ||
340 | ioctl(fd, BLKRRPART, 0); | ||
341 | } | ||
342 | close(fd); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | static int raid_setup(char *str) | ||
347 | { | ||
348 | int len, pos; | ||
349 | |||
350 | len = strlen(str) + 1; | ||
351 | pos = 0; | ||
352 | |||
353 | while (pos < len) { | ||
354 | char *comma = strchr(str + pos, ','); | ||
355 | int wlen; | ||
356 | if (comma) | ||
357 | wlen = (comma - str) - pos; | ||
358 | else | ||
359 | wlen = (len - 1) - pos; | ||
360 | |||
361 | if (!strncmp(str, "noautodetect", wlen)) | ||
362 | raid_noautodetect = 1; | ||
363 | if (strncmp(str, "partitionable", wlen) == 0) | ||
364 | raid_autopart = 1; | ||
365 | if (strncmp(str, "part", wlen) == 0) | ||
366 | raid_autopart = 1; | ||
367 | pos += wlen + 1; | ||
368 | } | ||
369 | return 1; | ||
370 | } | ||
371 | |||
372 | static void md_run_setup(void) | ||
373 | { | ||
374 | create_dev("/dev/md0", makedev(MD_MAJOR, 0)); | ||
375 | if (raid_noautodetect) | ||
376 | fprintf(stderr, | ||
377 | "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); | ||
378 | else { | ||
379 | int fd = open("/dev/md0", 0, 0); | ||
380 | if (fd >= 0) { | ||
381 | ioctl(fd, RAID_AUTORUN, | ||
382 | (void *)(intptr_t) raid_autopart); | ||
383 | close(fd); | ||
384 | } | ||
385 | } | ||
386 | md_setup_drive(); | ||
387 | } | ||
388 | |||
389 | void md_run(int argc, char *argv[]) | ||
390 | { | ||
391 | char **pp, *p; | ||
392 | |||
393 | for (pp = argv; (p = *pp); pp++) { | ||
394 | if (!strncmp(p, "raid=", 5)) | ||
395 | raid_setup(p + 5); | ||
396 | else if (!strncmp(p, "md=", 3)) | ||
397 | md_setup(p + 3); | ||
398 | } | ||
399 | |||
400 | md_run_setup(); | ||
401 | } |