Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/do_mounts_md.c
Parent Directory | Revision Log
Revision 815 -
(show annotations)
(download)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 9571 byte(s)
Fri Apr 24 18:32:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 9571 byte(s)
-updated to klibc-1.5.15
1 | /* |
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 | #include "kinit.h" |
24 | #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 | int minor_num, level, factor, fault, partitioned = 0; |
147 | char *pername = ""; |
148 | char *str1; |
149 | int ent; |
150 | |
151 | if (*str == 'd') { |
152 | partitioned = 1; |
153 | str++; |
154 | } |
155 | if (get_option(&str, &minor_num) != 2) { /* MD Number */ |
156 | fprintf(stderr, "md: Too few arguments supplied to md=.\n"); |
157 | return 0; |
158 | } |
159 | str1 = str; |
160 | if (minor_num >= MAX_MD_DEVS) { |
161 | fprintf(stderr, "md: md=%d, Minor device number too high.\n", |
162 | minor_num); |
163 | return 0; |
164 | } |
165 | for (ent = 0; ent < md_setup_ents; ent++) |
166 | if (md_setup_args[ent].minor == minor_num && |
167 | md_setup_args[ent].partitioned == partitioned) { |
168 | fprintf(stderr, |
169 | "md: md=%s%d, Specified more than once. " |
170 | "Replacing previous definition.\n", |
171 | partitioned ? "d" : "", minor_num); |
172 | break; |
173 | } |
174 | if (ent >= MAX_MD_DEVS) { |
175 | fprintf(stderr, "md: md=%s%d - too many md initialisations\n", |
176 | partitioned ? "d" : "", minor_num); |
177 | 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 | partitioned?"_d":"", minor_num, pername, str); |
209 | md_setup_args[ent].device_names = str; |
210 | md_setup_args[ent].partitioned = partitioned; |
211 | md_setup_args[ent].minor = minor_num; |
212 | |
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 | struct stat st_chk; |
231 | |
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 | if (stat(name, &st_chk) == 0) |
240 | continue; |
241 | |
242 | 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 | } |