]>
git.ipfire.org Git - thirdparty/mdadm.git/blob - Dump.c
2 * mdadm - manage Linux "md" devices aka RAID arrays.
4 * Copyright (C) 2013 Neil Brown <neilb@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 * Email: <neilb@suse.de>
23 int Dump_metadata(char *dev
, char *dir
, struct context
*c
,
26 /* create a new file in 'dir' named for the basename of 'dev'.
27 * Truncate to the same size as 'dev' and ask the metadata
28 * handler to copy metadata there.
29 * For every name in /dev/disk/by-id that points to this device,
30 * create a hardlink in 'dir'.
31 * Complain if any of those hardlinks cannot be created.
34 struct stat stb
, dstb
;
37 unsigned long long size
;
41 if (stat(dir
, &stb
) != 0 ||
42 (S_IFMT
& stb
.st_mode
) != S_IFDIR
) {
43 pr_err("--dump requires an existing directory, not: %s\n",
48 fd
= dev_open(dev
, O_RDONLY
);
50 pr_err("Cannot open %s to dump metadata: %s\n",
51 dev
, strerror(errno
));
54 if (!get_dev_size(fd
, dev
, &size
)) {
60 st
= guess_super_type(fd
, guess_array
);
62 pr_err("Cannot find RAID metadata on %s\n", dev
);
67 st
->ignore_hw_compat
= 1;
68 if (st
->ss
->load_super(st
, fd
, NULL
) != 0) {
69 pr_err("No %s metadata found on %s\n",
74 if (st
->ss
->copy_metadata
== NULL
) {
75 pr_err("%s metadata on %s cannot be copied\n",
81 base
= strrchr(dev
, '/');
86 xasprintf(&fname
, "%s/%s", dir
, base
);
87 fl
= open(fname
, O_RDWR
|O_CREAT
|O_EXCL
, 0666);
89 pr_err("Cannot create dump file %s: %s\n",
90 fname
, strerror(errno
));
95 if (ftruncate(fl
, size
) < 0) {
96 pr_err("failed to set size of dump file: %s\n",
104 if (st
->ss
->copy_metadata(st
, fd
, fl
) != 0) {
105 pr_err("Failed to copy metadata from %s to %s\n",
114 printf("%s saved as %s.\n", dev
, fname
);
118 if ((dstb
.st_mode
& S_IFMT
) != S_IFBLK
) {
119 /* Not a block device, so cannot create links */
123 /* mostly done: just want to find some other names */
124 dirp
= opendir("/dev/disk/by-id");
129 while ((de
= readdir(dirp
)) != NULL
) {
131 if (de
->d_name
[0] == '.')
133 xasprintf(&p
, "/dev/disk/by-id/%s", de
->d_name
);
134 if (stat(p
, &stb
) != 0 ||
135 (stb
.st_mode
& S_IFMT
) != S_IFBLK
||
136 stb
.st_rdev
!= dstb
.st_rdev
) {
142 xasprintf(&p
, "%s/%s", dir
, de
->d_name
);
143 if (link(fname
, p
) == 0) {
145 printf("%s also saved as %s.\n",
148 pr_err("Could not save %s as %s!!\n",
158 int Restore_metadata(char *dev
, char *dir
, struct context
*c
,
159 struct supertype
*st
, int only
)
161 /* If 'dir' really is a directory we choose a name
162 * from it that matches a suitable name in /dev/disk/by-id,
163 * and copy metadata from the file to the device.
164 * If two names from by-id match and aren't both the same
165 * inode, we fail. If none match and basename of 'dev'
166 * can be found in dir, use that.
167 * If 'dir' is really a file then it is only permitted if
168 * 'only' is set (meaning there was only one device given)
169 * and the metadata is restored irrespective of file names.
172 struct stat stb
, dstb
;
174 unsigned long long size
;
176 if (stat(dir
, &stb
) != 0) {
177 pr_err("%s does not exist: cannot restore from there.\n",
180 } else if ((S_IFMT
& stb
.st_mode
) != S_IFDIR
&& !only
) {
181 pr_err("--restore requires a directory when multiple devices given\n");
185 fd
= dev_open(dev
, O_RDWR
);
187 pr_err("Cannot open %s to restore metadata: %s\n",
188 dev
, strerror(errno
));
191 if (!get_dev_size(fd
, dev
, &size
)) {
196 if ((S_IFMT
& stb
.st_mode
) == S_IFDIR
) {
197 /* choose one name from the directory. */
198 DIR *d
= opendir(dir
);
201 unsigned int chosen_inode
= 0;
205 while (d
&& (de
= readdir(d
)) != NULL
) {
206 if (de
->d_name
[0] == '.')
208 xasprintf(&fname
, "/dev/disk/by-id/%s", de
->d_name
);
209 if (stat(fname
, &stb
) != 0) {
214 if ((S_IFMT
& stb
.st_mode
) != S_IFBLK
)
216 if (stb
.st_rdev
!= dstb
.st_rdev
)
218 /* This file is a good match for our device. */
219 xasprintf(&fname
, "%s/%s", dir
, de
->d_name
);
220 if (stat(fname
, &stb
) != 0) {
225 if (chosen
== NULL
) {
227 chosen_inode
= stb
.st_ino
;
230 if (chosen_inode
== stb
.st_ino
) {
231 /* same, no need to change */
235 /* Oh dear, two names both match. Must give up. */
236 pr_err("Both %s and %s seem suitable for %s. Please choose one.\n",
246 /* One last chance: try basename of device */
247 char *base
= strrchr(dev
, '/');
252 xasprintf(&fname
, "%s/%s", dir
, base
);
253 if (stat(fname
, &stb
) == 0)
263 pr_err("Cannot find suitable file in %s for %s\n",
269 fl
= open(fname
, O_RDONLY
);
271 pr_err("Could not open %s for --restore.\n",
275 if (((unsigned long long)stb
.st_size
) != size
) {
276 pr_err("%s is not the same size as %s - cannot restore.\n",
281 st
= guess_super_type(fl
, guess_array
);
283 pr_err("Cannot find metadata on %s\n", fname
);
286 st
->ignore_hw_compat
= 1;
287 if (st
->ss
->load_super(st
, fl
, NULL
) != 0) {
288 pr_err("No %s metadata found on %s\n",
289 st
->ss
->name
, fname
);
292 if (st
->ss
->copy_metadata
== NULL
) {
293 pr_err("%s metadata on %s cannot be copied\n",
297 if (st
->ss
->copy_metadata(st
, fl
, fd
) != 0) {
298 pr_err("Failed to copy metadata from %s to %s\n",
303 printf("%s restored from %s.\n", dev
, fname
);