]>
git.ipfire.org Git - thirdparty/mdadm.git/blob - mdopen.c
2 * mdadm - manage Linux "md" devices aka RAID arrays.
4 * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Email: <neilb@cse.unsw.edu.au>
24 * School of Computer Science and Engineering
25 * The University of New South Wales
35 void make_dev_symlink(char *dev
)
37 char *new = strdup(dev
);
40 /* /dev/md/0 -> /dev/md0
41 * /dev/md/d0 -> /dev/md_d0
47 if (symlink(dev
+5, new))
52 void make_parts(char *dev
, int cnt
, int symlinks
)
54 /* make 'cnt' partition devices for 'dev'
55 * We use the major/minor from dev and add 1..cnt
56 * If dev ends with a digit, we add "p%d" else "%d"
57 * If the name exists, we use it's owner/mode,
61 int major_num
, minor_num
;
63 int nlen
= strlen(dev
) + 20;
64 char *name
= malloc(nlen
);
65 int dig
= isdigit(dev
[strlen(dev
)-1]);
68 if (stat(dev
, &stb
)!= 0)
70 if (!S_ISBLK(stb
.st_mode
))
72 major_num
= major(stb
.st_rdev
);
73 minor_num
= minor(stb
.st_rdev
);
74 for (i
=1; i
<= cnt
; i
++) {
76 snprintf(name
, nlen
, "%s%s%d", dev
, dig
?"p":"", i
);
77 if (stat(name
, &stb2
)==0) {
78 if (!S_ISBLK(stb2
.st_mode
))
80 if (stb2
.st_rdev
== makedev(major_num
, minor_num
+i
))
86 if (mknod(name
, S_IFBLK
| 0600, makedev(major_num
, minor_num
+i
)))
88 if (chown(name
, stb2
.st_uid
, stb2
.st_gid
))
90 if (chmod(name
, stb2
.st_mode
& 07777))
92 if (symlinks
&& strncmp(name
, "/dev/md/", 8) == 0)
93 make_dev_symlink(name
);
95 add_dev(name
, &stb2
, 0, NULL
);
101 * We need a new md device to assemble/build/create an array.
102 * 'dev' is a name given us by the user (command line or mdadm.conf)
103 * It might start with /dev or /dev/md any might end with a digit
105 * If it starts with just /dev, it must be /dev/mdX or /dev/md_dX
106 * If it ends with a digit string, then it must be as above, or
107 * 'trustworthy' must be 'METADATA' and the 'dev' must be
108 * /dev/md/'name'NN or 'name'NN
109 * If it doesn't end with a digit string, it must be /dev/md/'name'
110 * or 'name' or must be NULL.
111 * If the digit string is present, it gives the minor number to use
112 * If not, we choose a high, unused minor number.
113 * If the 'dev' is a standard name, it devices whether 'md' or 'mdp'.
114 * else if the name is 'd[0-9]+' then we use mdp
115 * else if trustworthy is 'METADATA' we use md
116 * else the choice depends on 'autof'.
117 * If name is NULL it is assumed to match whatever dev provides.
118 * If both name and dev are NULL, we choose a name 'mdXX' or 'mdpXX'
120 * If 'name' is given, and 'trustworthy' is 'foreign' and name is not
121 * supported by 'dev', we add a "_%d" suffix based on the minor number
124 * If udev is configured, we create a temporary device, open it, and
126 * If not, we create the /dev/mdXX device, and is name is usable,
128 * In any case we return /dev/md/name or (if that isn't available)
129 * /dev/mdXX in 'chosen'.
131 * When we create devices, we use uid/gid/umask from config file.
134 int create_mddev(char *dev
, char *name
, int autof
, int trustworthy
,
141 struct createinfo
*ci
= conf_get_create_info();
156 strcpy(chosen
, "/dev/md/");
157 cname
= chosen
+ strlen(chosen
);
162 if (strncmp(dev
, "/dev/md/", 8) == 0) {
163 strcpy(cname
, dev
+8);
164 } else if (strncmp(dev
, "/dev/", 5) == 0) {
165 char *e
= dev
+ strlen(dev
);
166 while (e
> dev
&& isdigit(e
[-1]))
169 num
= strtoul(e
, NULL
, 10);
170 strcpy(cname
, dev
+5);
171 cname
[e
-(dev
+5)] = 0;
172 /* name *must* be mdXX or md_dXX in this context */
174 (strcmp(cname
, "md") != 0 && strcmp(cname
, "md_d") != 0)) {
175 fprintf(stderr
, Name
": %s is an invalid name "
176 "for an md device. Try /dev/md/%s\n",
180 if (strcmp(cname
, "md") == 0)
187 /* 'cname' must not contain a slash, may not start or end
188 * with a digit, and may only be empty if num is present.
190 if (strchr(cname
, '/') != NULL
||
192 (cname
[0] && isdigit(cname
[strlen(cname
)]))
194 fprintf(stderr
, Name
": %s is an invalid name "
195 "for an md device.\n", dev
);
198 if (cname
[0] == 0 && num
< 0) {
199 fprintf(stderr
, Name
": %s is an invalid name "
200 "for an md device (empty!).", dev
);
205 /* Now determine device number */
206 /* named 'METADATA' cannot use 'mdp'. */
207 if (name
&& name
[0] == 0)
209 if (name
&& trustworthy
== METADATA
&& use_mdp
== 1) {
210 fprintf(stderr
, Name
": %s is not allowed for a %s container. "
211 "Consider /dev/md%d.\n", dev
, name
, num
);
214 if (name
&& trustworthy
== METADATA
)
217 if (autof
== 4 || autof
== 6)
222 if (num
< 0 && trustworthy
== LOCAL
&& name
) {
223 /* if name is numeric, us that for num */
225 num
= strtoul(name
, &ep
, 10);
226 if (ep
== name
|| *ep
)
231 /* need to choose a free number. */
232 num
= find_free_devnum(use_mdp
);
233 if (num
== NoMdDev
) {
234 fprintf(stderr
, Name
": No avail md devices - aborting\n");
238 num
= use_mdp
? (-1-num
) : num
;
239 if (mddev_busy(num
)) {
240 fprintf(stderr
, Name
": %s is already in use.\n",
247 sprintf(devname
, "/dev/md_d%d", -1-num
);
249 sprintf(devname
, "/dev/md%d", num
);
251 if (cname
[0] == 0 && name
) {
252 /* Need to find a name if we can
253 * We don't completely trust 'name'. Truncate to
254 * reasonable length and remove '/'
257 strncpy(cname
, name
, 200);
259 while ((cp
= strchr(cname
, '/')) != NULL
)
261 if (trustworthy
== METADATA
)
262 /* always add device number to metadata */
263 sprintf(cname
+strlen(cname
), "%d", num
);
264 else if (trustworthy
== FOREIGN
&&
265 strchr(cname
, ':') == NULL
)
266 /* add _%d to FOREIGN array that don't have
269 sprintf(cname
+strlen(cname
), "_%d", num
<0?(-1-num
):num
);
272 strcpy(chosen
, devname
);
274 /* We have a device number and name.
275 * If we can detect udev, just open the device and we
278 if (stat("/dev/.udev", &stb
) != 0 ||
279 check_env("MDADM_NO_UDEV")) {
280 /* Make sure 'devname' exists and 'chosen' is a symlink to it */
281 if (lstat(devname
, &stb
) == 0) {
282 /* Must be the correct device, else error */
283 if ((stb
.st_mode
&S_IFMT
) != S_IFBLK
||
284 stb
.st_rdev
!= makedev(dev2major(num
),dev2minor(num
))) {
285 fprintf(stderr
, Name
": %s exists but looks wrong, please fix\n",
290 if (mknod(devname
, S_IFBLK
|0600,
291 makedev(dev2major(num
),dev2minor(num
))) != 0) {
292 fprintf(stderr
, Name
": failed to create %s\n",
296 if (chown(devname
, ci
->uid
, ci
->gid
))
298 if (chmod(devname
, ci
->mode
))
301 add_dev(devname
, &stb
, 0, NULL
);
303 if (strcmp(chosen
, devname
) != 0) {
305 if (mkdir("/dev/md",0700)==0) {
306 if (chown("/dev/md", ci
->uid
, ci
->gid
))
307 perror("chown /dev/md");
308 if (chmod("/dev/md", ci
->mode
| ((ci
->mode
>>2) & 0111)))
309 perror("chmod /dev/md");
312 if (dev
&& strcmp(chosen
, dev
) == 0)
313 /* We know we are allowed to use this name */
316 if (lstat(chosen
, &stb
) == 0) {
318 if ((stb
.st_mode
& S_IFMT
) != S_IFLNK
||
319 readlink(chosen
, buf
, 300) <0 ||
320 strcmp(buf
, devname
) != 0) {
321 fprintf(stderr
, Name
": %s exists - ignoring\n",
323 strcpy(chosen
, devname
);
326 symlink(devname
, chosen
);
329 mdfd
= open_dev_excl(num
);
331 fprintf(stderr
, Name
": unexpected failure opening %s\n",
337 /* Open this and check that it is an md device.
338 * On success, return filedescriptor.
339 * On failure, return -1 if it doesn't exist,
340 * or -2 if it exists but is not an md device.
342 int open_mddev(char *dev
, int report_errors
)
344 int mdfd
= open(dev
, O_RDWR
);
347 fprintf(stderr
, Name
": error opening %s: %s\n",
348 dev
, strerror(errno
));
351 if (md_get_version(mdfd
) <= 0) {
354 fprintf(stderr
, Name
": %s does not appear to be "
355 "an md device\n", dev
);
362 int create_mddev_devnum(char *devname
, int devnum
, char *name
,
363 char *chosen_name
, int parts
)
365 /* Open the md device with number 'devnum', possibly using 'devname',
366 * possibly constructing a name with 'name', but in any case, copying
367 * the name into 'chosen_name'
369 int major_num
, minor_num
;
372 struct createinfo
*ci
= conf_get_create_info();
375 strcpy(chosen_name
, devname
);
376 else if (name
&& *name
&& name
[0] && strchr(name
,'/') == NULL
) {
377 char *n
= strchr(name
, ':');
378 if (n
) n
++; else n
= name
;
379 if (isdigit(*n
) && devnum
< 0)
380 sprintf(chosen_name
, "/dev/md/d%s", n
);
382 sprintf(chosen_name
, "/dev/md/%s", n
);
385 sprintf(chosen_name
, "/dev/md%d", devnum
);
387 sprintf(chosen_name
, "/dev/md/d%d", -1-devnum
);
390 major_num
= MD_MAJOR
;
393 major_num
= get_mdp_major();
394 minor_num
= (-1-devnum
) << 6;
396 if (stat(chosen_name
, &stb
) == 0) {
397 /* It already exists. Check it is right. */
398 if ( ! S_ISBLK(stb
.st_mode
) ||
399 stb
.st_rdev
!= makedev(major_num
, minor_num
)) {
404 /* special case: if --incremental is suggesting a name
405 * in /dev/md/, we make sure the directory exists.
407 if (strncmp(chosen_name
, "/dev/md/", 8) == 0) {
408 if (mkdir("/dev/md",0700)==0) {
409 if (chown("/dev/md", ci
->uid
, ci
->gid
))
410 perror("chown /dev/md");
411 if (chmod("/dev/md", ci
->mode
|
412 ((ci
->mode
>>2) & 0111)))
413 perror("chmod /dev/md");
417 if (mknod(chosen_name
, S_IFBLK
| 0600,
418 makedev(major_num
, minor_num
)) != 0) {
421 /* FIXME chown/chmod ?? */
424 /* Simple locking to avoid --incr being called for the same
425 * array multiple times in parallel.
427 for (i
= 0; i
< 25 ; i
++) {
430 fd
= open(chosen_name
, O_RDWR
|O_EXCL
);
431 if (fd
>= 0 || errno
!= EBUSY
) {
433 make_parts(chosen_name
, parts
, ci
->symlinks
);