Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/kinit/do_mounts_md.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show 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)
-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 }