]>
git.ipfire.org Git - thirdparty/mdadm.git/blob - mapfile.c
2 * mapfile - keep track of uuid <-> array mapping. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
5 * Copyright (C) 2006-2010 Neil Brown <neilb@suse.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Email: <neilb@suse.de>
27 * QVB Post Office, NSW 1230
31 /* The mapfile is used to track arrays being created in --incremental
32 * mode. It particularly allows lookup from UUID to array device, but
33 * also allows the array device name to be easily found.
35 * The map file is line based with space separated fields. The fields are:
36 * Device id - mdX or mdpX where X is a number.
37 * metadata - 0.90 1.0 1.1 1.2 ddf ...
38 * UUID - uuid of the array
39 * path - path where device created: /dev/md/home
41 * The best place for the mapfile is /run/mdadm/map. Distros and users
42 * which have not switched to /run yet can choose a different location
43 * at compile time via MAP_DIR and MAP_FILE.
58 MAP_DIR
"/" MAP_FILE
".new",
59 MAP_DIR
"/" MAP_FILE
".lock",
63 int mapmode
[3] = { O_RDONLY
, O_RDWR
|O_CREAT
, O_RDWR
|O_CREAT
|O_TRUNC
};
64 char *mapsmode
[3] = { "r", "w", "w"};
66 FILE *open_map(int modenum
)
69 if ((mapmode
[modenum
] & O_CREAT
))
70 /* Attempt to create directory, don't worry about
73 (void)mkdir(mapname
[MAP_DIRNAME
], 0755);
74 fd
= open(mapname
[modenum
], mapmode
[modenum
], 0600);
76 return fdopen(fd
, mapsmode
[modenum
]);
80 int map_write(struct map_ent
*mel
)
85 f
= open_map(MAP_NEW
);
89 for (; mel
; mel
= mel
->next
) {
92 fprintf(f
, "%s ", mel
->devnm
);
93 fprintf(f
, "%s ", mel
->metadata
);
94 fprintf(f
, "%08x:%08x:%08x:%08x ", mel
->uuid
[0],
95 mel
->uuid
[1], mel
->uuid
[2], mel
->uuid
[3]);
96 fprintf(f
, "%s\n", mel
->path
?:"");
105 return rename(mapname
[1],
109 static FILE *lf
= NULL
;
110 int map_lock(struct map_ent
**melp
)
114 lf
= open_map(MAP_LOCK
);
117 if (flock(fileno(lf
), LOCK_EX
) != 0) {
122 if (fstat(fileno(lf
), &buf
) != 0 ||
124 /* The owner of the lock unlinked it,
125 * so we have a lock on a stale file,
138 void map_unlock(struct map_ent
**melp
)
141 /* must unlink before closing the file,
142 * as only the owner of the lock may
155 /* We are forking, so must close the lock file.
156 * Don't risk flushing anything though.
165 void map_add(struct map_ent
**melp
,
166 char * devnm
, char *metadata
, int uuid
[4], char *path
)
168 struct map_ent
*me
= xmalloc(sizeof(*me
));
170 snprintf(me
->devnm
, sizeof(me
->devnm
), "%s", devnm
);
171 snprintf(me
->metadata
, sizeof(me
->metadata
), "%s", metadata
);
172 memcpy(me
->uuid
, uuid
, 16);
173 me
->path
= path
? xstrdup(path
) : NULL
;
179 void map_read(struct map_ent
**melp
)
190 f
= open_map(MAP_READ
);
193 f
= open_map(MAP_READ
);
198 while (fgets(buf
, sizeof(buf
), f
)) {
200 if (sscanf(buf
, " %s %s %x:%x:%x:%x %200s",
201 devnm
, metadata
, uuid
, uuid
+1,
202 uuid
+2, uuid
+3, path
) >= 7) {
203 map_add(melp
, devnm
, metadata
, uuid
, path
);
209 void map_free(struct map_ent
*map
)
212 struct map_ent
*mp
= map
;
219 int map_update(struct map_ent
**mpp
, char *devnm
, char *metadata
,
220 int uuid
[4], char *path
)
222 struct map_ent
*map
, *mp
;
230 for (mp
= map
; mp
; mp
=mp
->next
)
231 if (strcmp(mp
->devnm
, devnm
) == 0) {
232 snprintf(mp
->metadata
, sizeof(mp
->metadata
), "%s", metadata
);
233 memcpy(mp
->uuid
, uuid
, 16);
235 mp
->path
= path
? xstrdup(path
) : NULL
;
240 map_add(&map
, devnm
, metadata
, uuid
, path
);
248 void map_delete(struct map_ent
**mapp
, char *devnm
)
255 for (mp
= *mapp
; mp
; mp
= *mapp
) {
256 if (strcmp(mp
->devnm
, devnm
) == 0) {
265 void map_remove(struct map_ent
**mapp
, char *devnm
)
270 map_delete(mapp
, devnm
);
276 struct map_ent
*map_by_uuid(struct map_ent
**map
, int uuid
[4])
282 for (mp
= *map
; mp
; mp
= mp
->next
) {
283 if (memcmp(uuid
, mp
->uuid
, 16) != 0)
285 if (!mddev_busy(mp
->devnm
)) {
294 struct map_ent
*map_by_devnm(struct map_ent
**map
, char *devnm
)
304 for (mp
= *map
; mp
; mp
= mp
->next
) {
305 if (strcmp(mp
->devnm
, devnm
) != 0)
307 if (!mddev_busy(mp
->devnm
)) {
316 struct map_ent
*map_by_name(struct map_ent
**map
, char *name
)
322 for (mp
= *map
; mp
; mp
= mp
->next
) {
325 if (strncmp(mp
->path
, DEV_MD_DIR
, DEV_MD_DIR_LEN
) != 0)
327 if (strcmp(mp
->path
+ DEV_MD_DIR_LEN
, name
) != 0)
329 if (!mddev_busy(mp
->devnm
)) {
338 /* sets the proper subarray and container_dev according to the metadata
339 * version super_by_fd does this automatically, this routine is meant as
340 * a supplement for guess_super()
342 static char *get_member_info(struct mdstat_ent
*ent
)
346 if (!is_mdstat_ent_subarray(ent
))
349 subarray
= strrchr(ent
->metadata_version
, '/');
354 void RebuildMap(void)
356 struct mdstat_ent
*mdstat
= mdstat_read(0, 0);
357 struct mdstat_ent
*md
;
358 struct map_ent
*map
= NULL
;
359 int require_homehost
;
360 char sys_hostname
[256];
361 char *homehost
= conf_get_homehost(&require_homehost
);
363 if (homehost
== NULL
|| strcmp(homehost
, "<system>")==0) {
364 if (s_gethostname(sys_hostname
, sizeof(sys_hostname
)) == 0) {
365 homehost
= sys_hostname
;
369 for (md
= mdstat
; md
; md
= md
->next
) {
370 struct mdinfo
*sra
= sysfs_read(-1, md
->devnm
, GET_DEVS
);
376 for (sd
= sra
->devs
; sd
; sd
= sd
->next
) {
382 struct supertype
*st
;
383 char *subarray
= NULL
;
387 sprintf(dn
, "%d:%d", sd
->disk
.major
, sd
->disk
.minor
);
388 dfd
= dev_open(dn
, O_RDONLY
);
391 st
= guess_super(dfd
);
395 subarray
= get_member_info(md
);
396 ok
= st
->ss
->load_super(st
, dfd
, NULL
);
402 info
= st
->ss
->container_content(st
, subarray
);
404 info
= xmalloc(sizeof(*info
));
405 st
->ss
->getinfo_super(st
, info
, NULL
);
410 devid
= devnm2devid(md
->devnm
);
411 path
= map_dev(major(devid
), minor(devid
), 0);
413 strncmp(path
, DEV_MD_DIR
, DEV_MD_DIR_LEN
) != 0) {
414 /* We would really like a name that provides
415 * an MD_DEVNAME for udev.
416 * The name needs to be unique both in /dev/md/
417 * and in this mapfile.
418 * It needs to match what -I or -As would come
421 * Check if array is in mdadm.conf
423 * determine trustworthy from homehost etc
424 * find a unique name based on metadata name.
427 struct mddev_ident
*match
= conf_match(st
, info
,
431 if (match
&& match
->devname
&& match
->devname
[0] == '/') {
432 path
= match
->devname
;
433 if (path
[0] != '/') {
434 strcpy(namebuf
, DEV_MD_DIR
);
435 strcat(namebuf
, path
);
443 if ((homehost
== NULL
||
444 st
->ss
->match_home(st
, homehost
) != 1) &&
445 st
->ss
->match_home(st
, "any") != 1 &&
447 !conf_name_is_free(info
->name
)))
448 /* require a numeric suffix */
451 /* allow name to be used as-is if no conflict */
456 if (!isdigit(name
[strlen(name
)-1]) &&
462 if (strchr(name
, ':')) {
463 /* Probably a uniquifying
464 * hostname prefix. Allow
465 * without a suffix, and strip
466 * hostname if it is us.
468 if (homehost
&& unum
== -1 &&
469 strncmp(name
, homehost
,
470 strlen(homehost
)) == 0 &&
471 name
[strlen(homehost
)] == ':')
472 name
+= strlen(homehost
)+1;
478 sprintf(namebuf
, DEV_MD_DIR
"%s%s%d",
481 sprintf(namebuf
, DEV_MD_DIR
"%s",
484 if (lstat(namebuf
, &stb
) != 0 &&
486 !map_by_name(&map
, namebuf
+8)))
492 map_add(&map
, md
->devnm
,
495 st
->ss
->free_super(st
);
501 /* Only trigger a change if we wrote a new map file */
503 for (md
= mdstat
; md
; md
= md
->next
) {
504 struct mdinfo
*sra
= sysfs_read(-1, md
->devnm
,
507 sysfs_uevent(sra
, "change");