Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/do_mounts_md.c
Parent Directory | Revision Log
Revision 1297 -
(show annotations)
(download)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 9551 byte(s)
Fri May 27 15:12:11 2011 UTC (12 years, 11 months ago) by niro
File MIME type: text/plain
File size: 9551 byte(s)
-updated to klibc-1.5.22 with mntproc definitions patch included
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 <inttypes.h> |
18 | #include <sys/sysmacros.h> |
19 | #include <sys/md.h> |
20 | #include <linux/major.h> |
21 | |
22 | #include "kinit.h" |
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_num, 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_num) != 2) { /* MD Number */ |
155 | fprintf(stderr, "md: Too few arguments supplied to md=.\n"); |
156 | return 0; |
157 | } |
158 | str1 = str; |
159 | if (minor_num >= MAX_MD_DEVS) { |
160 | fprintf(stderr, "md: md=%d, Minor device number too high.\n", |
161 | minor_num); |
162 | return 0; |
163 | } |
164 | for (ent = 0; ent < md_setup_ents; ent++) |
165 | if (md_setup_args[ent].minor == minor_num && |
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_num); |
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_num); |
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_num, pername, str); |
208 | md_setup_args[ent].device_names = str; |
209 | md_setup_args[ent].partitioned = partitioned; |
210 | md_setup_args[ent].minor = minor_num; |
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 | struct stat st_chk; |
230 | |
231 | dev_minor = md_setup_args[ent].minor; |
232 | partitioned = md_setup_args[ent].partitioned; |
233 | devname = md_setup_args[ent].device_names; |
234 | |
235 | snprintf(name, sizeof name, |
236 | "/dev/md%s%d", partitioned ? "_d" : "", dev_minor); |
237 | |
238 | if (stat(name, &st_chk) == 0) |
239 | continue; |
240 | |
241 | if (partitioned) |
242 | dev = makedev(mdp_major(), dev_minor << MdpMinorShift); |
243 | else |
244 | dev = makedev(MD_MAJOR, dev_minor); |
245 | create_dev(name, dev); |
246 | for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { |
247 | char *p; |
248 | |
249 | p = strchr(devname, ','); |
250 | if (p) |
251 | *p++ = 0; |
252 | |
253 | dev = name_to_dev_t(devname); |
254 | if (!dev) { |
255 | fprintf(stderr, "md: Unknown device name: %s\n", |
256 | devname); |
257 | break; |
258 | } |
259 | |
260 | devices[i] = dev; |
261 | |
262 | devname = p; |
263 | } |
264 | devices[i] = 0; |
265 | |
266 | if (!i) |
267 | continue; |
268 | |
269 | fprintf(stderr, "md: Loading md%s%d: %s\n", |
270 | partitioned ? "_d" : "", dev_minor, |
271 | md_setup_args[ent].device_names); |
272 | |
273 | fd = open(name, 0, 0); |
274 | if (fd < 0) { |
275 | fprintf(stderr, "md: open failed - cannot start " |
276 | "array %s\n", name); |
277 | continue; |
278 | } |
279 | if (ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { |
280 | fprintf(stderr, |
281 | "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", |
282 | dev_minor); |
283 | close(fd); |
284 | continue; |
285 | } |
286 | |
287 | if (md_setup_args[ent].level != LEVEL_NONE) { |
288 | /* non-persistent */ |
289 | mdu_array_info_t ainfo; |
290 | ainfo.level = md_setup_args[ent].level; |
291 | ainfo.size = 0; |
292 | ainfo.nr_disks = 0; |
293 | ainfo.raid_disks = 0; |
294 | while (devices[ainfo.raid_disks]) |
295 | ainfo.raid_disks++; |
296 | ainfo.md_minor = dev_minor; |
297 | ainfo.not_persistent = 1; |
298 | |
299 | ainfo.state = (1 << MD_SB_CLEAN); |
300 | ainfo.layout = 0; |
301 | ainfo.chunk_size = md_setup_args[ent].chunk; |
302 | err = ioctl(fd, SET_ARRAY_INFO, &ainfo); |
303 | for (i = 0; !err && i <= MD_SB_DISKS; i++) { |
304 | dev = devices[i]; |
305 | if (!dev) |
306 | break; |
307 | dinfo.number = i; |
308 | dinfo.raid_disk = i; |
309 | dinfo.state = |
310 | (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC); |
311 | dinfo.major = major(dev); |
312 | dinfo.minor = minor(dev); |
313 | err = ioctl(fd, ADD_NEW_DISK, &dinfo); |
314 | } |
315 | } else { |
316 | /* persistent */ |
317 | for (i = 0; i <= MD_SB_DISKS; i++) { |
318 | dev = devices[i]; |
319 | if (!dev) |
320 | break; |
321 | dinfo.major = major(dev); |
322 | dinfo.minor = minor(dev); |
323 | ioctl(fd, ADD_NEW_DISK, &dinfo); |
324 | } |
325 | } |
326 | if (!err) |
327 | err = ioctl(fd, RUN_ARRAY, 0); |
328 | if (err) |
329 | fprintf(stderr, "md: starting md%d failed\n", |
330 | dev_minor); |
331 | else { |
332 | /* reread the partition table. |
333 | * I (neilb) and not sure why this is needed, but I cannot |
334 | * boot a kernel with devfs compiled in from partitioned md |
335 | * array without it |
336 | */ |
337 | close(fd); |
338 | fd = open(name, 0, 0); |
339 | ioctl(fd, BLKRRPART, 0); |
340 | } |
341 | close(fd); |
342 | } |
343 | } |
344 | |
345 | static int raid_setup(char *str) |
346 | { |
347 | int len, pos; |
348 | |
349 | len = strlen(str) + 1; |
350 | pos = 0; |
351 | |
352 | while (pos < len) { |
353 | char *comma = strchr(str + pos, ','); |
354 | int wlen; |
355 | if (comma) |
356 | wlen = (comma - str) - pos; |
357 | else |
358 | wlen = (len - 1) - pos; |
359 | |
360 | if (!strncmp(str, "noautodetect", wlen)) |
361 | raid_noautodetect = 1; |
362 | if (strncmp(str, "partitionable", wlen) == 0) |
363 | raid_autopart = 1; |
364 | if (strncmp(str, "part", wlen) == 0) |
365 | raid_autopart = 1; |
366 | pos += wlen + 1; |
367 | } |
368 | return 1; |
369 | } |
370 | |
371 | static void md_run_setup(void) |
372 | { |
373 | create_dev("/dev/md0", makedev(MD_MAJOR, 0)); |
374 | if (raid_noautodetect) |
375 | fprintf(stderr, |
376 | "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); |
377 | else { |
378 | int fd = open("/dev/md0", 0, 0); |
379 | if (fd >= 0) { |
380 | ioctl(fd, RAID_AUTORUN, |
381 | (void *)(intptr_t) raid_autopart); |
382 | close(fd); |
383 | } |
384 | } |
385 | md_setup_drive(); |
386 | } |
387 | |
388 | void md_run(int argc, char *argv[]) |
389 | { |
390 | char **pp, *p; |
391 | |
392 | for (pp = argv; (p = *pp); pp++) { |
393 | if (!strncmp(p, "raid=", 5)) |
394 | raid_setup(p + 5); |
395 | else if (!strncmp(p, "md=", 3)) |
396 | md_setup(p + 3); |
397 | } |
398 | |
399 | md_run_setup(); |
400 | } |