Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1297 - (hide 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)
-updated to klibc-1.5.22 with mntproc definitions patch included
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 <inttypes.h>
18     #include <sys/sysmacros.h>
19     #include <sys/md.h>
20     #include <linux/major.h>
21    
22 niro 815 #include "kinit.h"
23 niro 532 #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 niro 815 int minor_num, level, factor, fault, partitioned = 0;
146 niro 532 char *pername = "";
147     char *str1;
148     int ent;
149    
150     if (*str == 'd') {
151     partitioned = 1;
152     str++;
153     }
154 niro 815 if (get_option(&str, &minor_num) != 2) { /* MD Number */
155 niro 532 fprintf(stderr, "md: Too few arguments supplied to md=.\n");
156     return 0;
157     }
158     str1 = str;
159 niro 815 if (minor_num >= MAX_MD_DEVS) {
160 niro 532 fprintf(stderr, "md: md=%d, Minor device number too high.\n",
161 niro 815 minor_num);
162 niro 532 return 0;
163     }
164     for (ent = 0; ent < md_setup_ents; ent++)
165 niro 815 if (md_setup_args[ent].minor == minor_num &&
166 niro 532 md_setup_args[ent].partitioned == partitioned) {
167     fprintf(stderr,
168     "md: md=%s%d, Specified more than once. "
169     "Replacing previous definition.\n",
170 niro 815 partitioned ? "d" : "", minor_num);
171 niro 532 break;
172     }
173     if (ent >= MAX_MD_DEVS) {
174     fprintf(stderr, "md: md=%s%d - too many md initialisations\n",
175 niro 815 partitioned ? "d" : "", minor_num);
176 niro 532 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 niro 815 partitioned?"_d":"", minor_num, pername, str);
208 niro 532 md_setup_args[ent].device_names = str;
209     md_setup_args[ent].partitioned = partitioned;
210 niro 815 md_setup_args[ent].minor = minor_num;
211 niro 532
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 niro 815 struct stat st_chk;
230 niro 532
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 niro 815 if (stat(name, &st_chk) == 0)
239     continue;
240    
241 niro 532 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     }