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