diff options
Diffstat (limited to 'init/do_mounts_md.c')
-rw-r--r-- | init/do_mounts_md.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c new file mode 100644 index 000000000000..3fbc3555ce96 --- /dev/null +++ b/init/do_mounts_md.c | |||
@@ -0,0 +1,290 @@ | |||
1 | |||
2 | #include <linux/raid/md.h> | ||
3 | |||
4 | #include "do_mounts.h" | ||
5 | |||
6 | /* | ||
7 | * When md (and any require personalities) are compiled into the kernel | ||
8 | * (not a module), arrays can be assembles are boot time using with AUTODETECT | ||
9 | * where specially marked partitions are registered with md_autodetect_dev(), | ||
10 | * and with MD_BOOT where devices to be collected are given on the boot line | ||
11 | * with md=..... | ||
12 | * The code for that is here. | ||
13 | */ | ||
14 | |||
15 | static int __initdata raid_noautodetect, raid_autopart; | ||
16 | |||
17 | static struct { | ||
18 | int minor; | ||
19 | int partitioned; | ||
20 | int pers; | ||
21 | int chunk; | ||
22 | char *device_names; | ||
23 | } md_setup_args[MAX_MD_DEVS] __initdata; | ||
24 | |||
25 | static int md_setup_ents __initdata; | ||
26 | |||
27 | extern int mdp_major; | ||
28 | /* | ||
29 | * Parse the command-line parameters given our kernel, but do not | ||
30 | * actually try to invoke the MD device now; that is handled by | ||
31 | * md_setup_drive after the low-level disk drivers have initialised. | ||
32 | * | ||
33 | * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which | ||
34 | * assigns the task of parsing integer arguments to the | ||
35 | * invoked program now). Added ability to initialise all | ||
36 | * the MD devices (by specifying multiple "md=" lines) | ||
37 | * instead of just one. -- KTK | ||
38 | * 18May2000: Added support for persistent-superblock arrays: | ||
39 | * md=n,0,factor,fault,device-list uses RAID0 for device n | ||
40 | * md=n,-1,factor,fault,device-list uses LINEAR for device n | ||
41 | * md=n,device-list reads a RAID superblock from the devices | ||
42 | * elements in device-list are read by name_to_kdev_t so can be | ||
43 | * a hex number or something like /dev/hda1 /dev/sdb | ||
44 | * 2001-06-03: Dave Cinege <dcinege@psychosis.com> | ||
45 | * Shifted name_to_kdev_t() and related operations to md_set_drive() | ||
46 | * for later execution. Rewrote section to make devfs compatible. | ||
47 | */ | ||
48 | static int __init md_setup(char *str) | ||
49 | { | ||
50 | int minor, level, factor, fault, pers, partitioned = 0; | ||
51 | char *pername = ""; | ||
52 | char *str1; | ||
53 | int ent; | ||
54 | |||
55 | if (*str == 'd') { | ||
56 | partitioned = 1; | ||
57 | str++; | ||
58 | } | ||
59 | if (get_option(&str, &minor) != 2) { /* MD Number */ | ||
60 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
61 | return 0; | ||
62 | } | ||
63 | str1 = str; | ||
64 | if (minor >= MAX_MD_DEVS) { | ||
65 | printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); | ||
66 | return 0; | ||
67 | } | ||
68 | for (ent=0 ; ent< md_setup_ents ; ent++) | ||
69 | if (md_setup_args[ent].minor == minor && | ||
70 | md_setup_args[ent].partitioned == partitioned) { | ||
71 | printk(KERN_WARNING "md: md=%s%d, Specified more than once. " | ||
72 | "Replacing previous definition.\n", partitioned?"d":"", minor); | ||
73 | break; | ||
74 | } | ||
75 | if (ent >= MAX_MD_DEVS) { | ||
76 | printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor); | ||
77 | return 0; | ||
78 | } | ||
79 | if (ent >= md_setup_ents) | ||
80 | md_setup_ents++; | ||
81 | switch (get_option(&str, &level)) { /* RAID Personality */ | ||
82 | case 2: /* could be 0 or -1.. */ | ||
83 | if (level == 0 || level == LEVEL_LINEAR) { | ||
84 | if (get_option(&str, &factor) != 2 || /* Chunk Size */ | ||
85 | get_option(&str, &fault) != 2) { | ||
86 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
87 | return 0; | ||
88 | } | ||
89 | md_setup_args[ent].pers = level; | ||
90 | md_setup_args[ent].chunk = 1 << (factor+12); | ||
91 | if (level == LEVEL_LINEAR) { | ||
92 | pers = LINEAR; | ||
93 | pername = "linear"; | ||
94 | } else { | ||
95 | pers = RAID0; | ||
96 | pername = "raid0"; | ||
97 | } | ||
98 | md_setup_args[ent].pers = pers; | ||
99 | break; | ||
100 | } | ||
101 | /* FALL THROUGH */ | ||
102 | case 1: /* the first device is numeric */ | ||
103 | str = str1; | ||
104 | /* FALL THROUGH */ | ||
105 | case 0: | ||
106 | md_setup_args[ent].pers = 0; | ||
107 | pername="super-block"; | ||
108 | } | ||
109 | |||
110 | printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n", | ||
111 | minor, pername, str); | ||
112 | md_setup_args[ent].device_names = str; | ||
113 | md_setup_args[ent].partitioned = partitioned; | ||
114 | md_setup_args[ent].minor = minor; | ||
115 | |||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | #define MdpMinorShift 6 | ||
120 | |||
121 | static void __init md_setup_drive(void) | ||
122 | { | ||
123 | int minor, i, ent, partitioned; | ||
124 | dev_t dev; | ||
125 | dev_t devices[MD_SB_DISKS+1]; | ||
126 | |||
127 | for (ent = 0; ent < md_setup_ents ; ent++) { | ||
128 | int fd; | ||
129 | int err = 0; | ||
130 | char *devname; | ||
131 | mdu_disk_info_t dinfo; | ||
132 | char name[16], devfs_name[16]; | ||
133 | |||
134 | minor = md_setup_args[ent].minor; | ||
135 | partitioned = md_setup_args[ent].partitioned; | ||
136 | devname = md_setup_args[ent].device_names; | ||
137 | |||
138 | sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor); | ||
139 | sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor); | ||
140 | if (partitioned) | ||
141 | dev = MKDEV(mdp_major, minor << MdpMinorShift); | ||
142 | else | ||
143 | dev = MKDEV(MD_MAJOR, minor); | ||
144 | create_dev(name, dev, devfs_name); | ||
145 | for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { | ||
146 | char *p; | ||
147 | char comp_name[64]; | ||
148 | u32 rdev; | ||
149 | |||
150 | p = strchr(devname, ','); | ||
151 | if (p) | ||
152 | *p++ = 0; | ||
153 | |||
154 | dev = name_to_dev_t(devname); | ||
155 | if (strncmp(devname, "/dev/", 5) == 0) | ||
156 | devname += 5; | ||
157 | snprintf(comp_name, 63, "/dev/%s", devname); | ||
158 | rdev = bstat(comp_name); | ||
159 | if (rdev) | ||
160 | dev = new_decode_dev(rdev); | ||
161 | if (!dev) { | ||
162 | printk(KERN_WARNING "md: Unknown device name: %s\n", devname); | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | devices[i] = dev; | ||
167 | |||
168 | devname = p; | ||
169 | } | ||
170 | devices[i] = 0; | ||
171 | |||
172 | if (!i) | ||
173 | continue; | ||
174 | |||
175 | printk(KERN_INFO "md: Loading md%s%d: %s\n", | ||
176 | partitioned ? "_d" : "", minor, | ||
177 | md_setup_args[ent].device_names); | ||
178 | |||
179 | fd = sys_open(name, 0, 0); | ||
180 | if (fd < 0) { | ||
181 | printk(KERN_ERR "md: open failed - cannot start " | ||
182 | "array %s\n", name); | ||
183 | continue; | ||
184 | } | ||
185 | if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { | ||
186 | printk(KERN_WARNING | ||
187 | "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", | ||
188 | minor); | ||
189 | sys_close(fd); | ||
190 | continue; | ||
191 | } | ||
192 | |||
193 | if (md_setup_args[ent].pers) { | ||
194 | /* non-persistent */ | ||
195 | mdu_array_info_t ainfo; | ||
196 | ainfo.level = pers_to_level(md_setup_args[ent].pers); | ||
197 | ainfo.size = 0; | ||
198 | ainfo.nr_disks =0; | ||
199 | ainfo.raid_disks =0; | ||
200 | while (devices[ainfo.raid_disks]) | ||
201 | ainfo.raid_disks++; | ||
202 | ainfo.md_minor =minor; | ||
203 | ainfo.not_persistent = 1; | ||
204 | |||
205 | ainfo.state = (1 << MD_SB_CLEAN); | ||
206 | ainfo.layout = 0; | ||
207 | ainfo.chunk_size = md_setup_args[ent].chunk; | ||
208 | err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo); | ||
209 | for (i = 0; !err && i <= MD_SB_DISKS; i++) { | ||
210 | dev = devices[i]; | ||
211 | if (!dev) | ||
212 | break; | ||
213 | dinfo.number = i; | ||
214 | dinfo.raid_disk = i; | ||
215 | dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC); | ||
216 | dinfo.major = MAJOR(dev); | ||
217 | dinfo.minor = MINOR(dev); | ||
218 | err = sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
219 | } | ||
220 | } else { | ||
221 | /* persistent */ | ||
222 | for (i = 0; i <= MD_SB_DISKS; i++) { | ||
223 | dev = devices[i]; | ||
224 | if (!dev) | ||
225 | break; | ||
226 | dinfo.major = MAJOR(dev); | ||
227 | dinfo.minor = MINOR(dev); | ||
228 | sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
229 | } | ||
230 | } | ||
231 | if (!err) | ||
232 | err = sys_ioctl(fd, RUN_ARRAY, 0); | ||
233 | if (err) | ||
234 | printk(KERN_WARNING "md: starting md%d failed\n", minor); | ||
235 | else { | ||
236 | /* reread the partition table. | ||
237 | * I (neilb) and not sure why this is needed, but I cannot | ||
238 | * boot a kernel with devfs compiled in from partitioned md | ||
239 | * array without it | ||
240 | */ | ||
241 | sys_close(fd); | ||
242 | fd = sys_open(name, 0, 0); | ||
243 | sys_ioctl(fd, BLKRRPART, 0); | ||
244 | } | ||
245 | sys_close(fd); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static int __init raid_setup(char *str) | ||
250 | { | ||
251 | int len, pos; | ||
252 | |||
253 | len = strlen(str) + 1; | ||
254 | pos = 0; | ||
255 | |||
256 | while (pos < len) { | ||
257 | char *comma = strchr(str+pos, ','); | ||
258 | int wlen; | ||
259 | if (comma) | ||
260 | wlen = (comma-str)-pos; | ||
261 | else wlen = (len-1)-pos; | ||
262 | |||
263 | if (!strncmp(str, "noautodetect", wlen)) | ||
264 | raid_noautodetect = 1; | ||
265 | if (strncmp(str, "partitionable", wlen)==0) | ||
266 | raid_autopart = 1; | ||
267 | if (strncmp(str, "part", wlen)==0) | ||
268 | raid_autopart = 1; | ||
269 | pos += wlen+1; | ||
270 | } | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | __setup("raid=", raid_setup); | ||
275 | __setup("md=", md_setup); | ||
276 | |||
277 | void __init md_run_setup(void) | ||
278 | { | ||
279 | create_dev("/dev/md0", MKDEV(MD_MAJOR, 0), "md/0"); | ||
280 | if (raid_noautodetect) | ||
281 | printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); | ||
282 | else { | ||
283 | int fd = sys_open("/dev/md0", 0, 0); | ||
284 | if (fd >= 0) { | ||
285 | sys_ioctl(fd, RAID_AUTORUN, raid_autopart); | ||
286 | sys_close(fd); | ||
287 | } | ||
288 | } | ||
289 | md_setup_drive(); | ||
290 | } | ||