Magellan Linux

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

Parent Directory Parent Directory | Revision Log 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)
-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     }