Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "label.h"
18 : : #include "crc.h"
19 : : #include "xlate.h"
20 : : #include "lvmcache.h"
21 : : #include "metadata.h"
22 : :
23 : : #include <sys/stat.h>
24 : : #include <fcntl.h>
25 : : #include <unistd.h>
26 : :
27 : : /* FIXME Allow for larger labels? Restricted to single sector currently */
28 : :
29 : : /*
30 : : * Internal labeller struct.
31 : : */
32 : : struct labeller_i {
33 : : struct dm_list list;
34 : :
35 : : struct labeller *l;
36 : : char name[0];
37 : : };
38 : :
39 : : static struct dm_list _labellers;
40 : :
41 : 9 : static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
42 : : {
43 : : struct labeller_i *li;
44 : : size_t len;
45 : :
46 : 9 : len = sizeof(*li) + strlen(name) + 1;
47 : :
48 [ - + ]: 9 : if (!(li = dm_malloc(len))) {
49 : 0 : log_error("Couldn't allocate memory for labeller list object.");
50 : 0 : return NULL;
51 : : }
52 : :
53 : 9 : li->l = l;
54 : 9 : strcpy(li->name, name);
55 : :
56 : 9 : return li;
57 : : }
58 : :
59 : 9 : static void _free_li(struct labeller_i *li)
60 : : {
61 : 9 : dm_free(li);
62 : 9 : }
63 : :
64 : 3 : int label_init(void)
65 : : {
66 : 3 : dm_list_init(&_labellers);
67 : 3 : return 1;
68 : : }
69 : :
70 : 3 : void label_exit(void)
71 : : {
72 : : struct dm_list *c, *n;
73 : : struct labeller_i *li;
74 : :
75 [ + - ][ + + ]: 12 : for (c = _labellers.n; c && c != &_labellers; c = n) {
76 : 9 : n = c->n;
77 : 9 : li = dm_list_item(c, struct labeller_i);
78 : 9 : li->l->ops->destroy(li->l);
79 : 9 : _free_li(li);
80 : : }
81 : :
82 : 3 : dm_list_init(&_labellers);
83 : 3 : }
84 : :
85 : 9 : int label_register_handler(const char *name, struct labeller *handler)
86 : : {
87 : : struct labeller_i *li;
88 : :
89 [ - + ]: 9 : if (!(li = _alloc_li(name, handler)))
90 : 0 : return_0;
91 : :
92 : 9 : dm_list_add(&_labellers, &li->list);
93 : 9 : return 1;
94 : : }
95 : :
96 : 0 : struct labeller *label_get_handler(const char *name)
97 : : {
98 : : struct labeller_i *li;
99 : :
100 [ # # ]: 0 : dm_list_iterate_items(li, &_labellers)
101 [ # # ]: 0 : if (!strcmp(li->name, name))
102 : 0 : return li->l;
103 : :
104 : 0 : return NULL;
105 : : }
106 : :
107 : 0 : static struct labeller *_find_labeller(struct device *dev, char *buf,
108 : : uint64_t *label_sector,
109 : : uint64_t scan_sector)
110 : : {
111 : : struct labeller_i *li;
112 : 0 : struct labeller *r = NULL;
113 : : struct label_header *lh;
114 : : struct lvmcache_info *info;
115 : : uint64_t sector;
116 : 0 : int found = 0;
117 : : char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
118 : :
119 [ # # ]: 0 : if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
120 : : LABEL_SCAN_SIZE, readbuf)) {
121 : 0 : log_debug("%s: Failed to read label area", dev_name(dev));
122 : 0 : goto out;
123 : : }
124 : :
125 : : /* Scan a few sectors for a valid label */
126 [ # # ]: 0 : for (sector = 0; sector < LABEL_SCAN_SECTORS;
127 : 0 : sector += LABEL_SIZE >> SECTOR_SHIFT) {
128 : 0 : lh = (struct label_header *) (readbuf +
129 : 0 : (sector << SECTOR_SHIFT));
130 : :
131 [ # # ]: 0 : if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
132 [ # # ]: 0 : if (found) {
133 : 0 : log_error("Ignoring additional label on %s at "
134 : : "sector %" PRIu64, dev_name(dev),
135 : : sector + scan_sector);
136 : : }
137 [ # # ]: 0 : if (xlate64(lh->sector_xl) != sector + scan_sector) {
138 : 0 : log_info("%s: Label for sector %" PRIu64
139 : : " found at sector %" PRIu64
140 : : " - ignoring", dev_name(dev),
141 : : (uint64_t)xlate64(lh->sector_xl),
142 : : sector + scan_sector);
143 : 0 : continue;
144 : : }
145 [ # # ]: 0 : if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
146 : : ((uintptr_t) &lh->offset_xl - (uintptr_t) lh)) !=
147 : 0 : xlate32(lh->crc_xl)) {
148 : 0 : log_info("Label checksum incorrect on %s - "
149 : : "ignoring", dev_name(dev));
150 : 0 : continue;
151 : : }
152 [ # # ]: 0 : if (found)
153 : 0 : continue;
154 : : }
155 : :
156 [ # # ]: 0 : dm_list_iterate_items(li, &_labellers) {
157 [ # # ]: 0 : if (li->l->ops->can_handle(li->l, (char *) lh,
158 : : sector + scan_sector)) {
159 : 0 : log_very_verbose("%s: %s label detected",
160 : : dev_name(dev), li->name);
161 [ # # ]: 0 : if (found) {
162 : 0 : log_error("Ignoring additional label "
163 : : "on %s at sector %" PRIu64,
164 : : dev_name(dev),
165 : : sector + scan_sector);
166 : 0 : continue;
167 : : }
168 : 0 : r = li->l;
169 : 0 : memcpy(buf, lh, LABEL_SIZE);
170 [ # # ]: 0 : if (label_sector)
171 : 0 : *label_sector = sector + scan_sector;
172 : 0 : found = 1;
173 : 0 : break;
174 : : }
175 : : }
176 : : }
177 : :
178 : : out:
179 [ # # ]: 0 : if (!found) {
180 [ # # ]: 0 : if ((info = info_from_pvid(dev->pvid, 0)))
181 : 0 : lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
182 : 0 : info->fmt->orphan_vg_name,
183 : : 0, NULL);
184 : 0 : log_very_verbose("%s: No label detected", dev_name(dev));
185 : : }
186 : :
187 : 0 : return r;
188 : : }
189 : :
190 : : /* FIXME Also wipe associated metadata area headers? */
191 : 0 : int label_remove(struct device *dev)
192 : : {
193 : : char buf[LABEL_SIZE] __attribute((aligned(8)));
194 : : char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
195 : 0 : int r = 1;
196 : : uint64_t sector;
197 : : int wipe;
198 : : struct labeller_i *li;
199 : : struct label_header *lh;
200 : :
201 : 0 : memset(buf, 0, LABEL_SIZE);
202 : :
203 : 0 : log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
204 : :
205 [ # # ]: 0 : if (!dev_open(dev))
206 : 0 : return_0;
207 : :
208 : : /*
209 : : * We flush the device just in case someone is stupid
210 : : * enough to be trying to import an open pv into lvm.
211 : : */
212 : 0 : dev_flush(dev);
213 : :
214 [ # # ]: 0 : if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
215 : 0 : log_debug("%s: Failed to read label area", dev_name(dev));
216 : 0 : goto out;
217 : : }
218 : :
219 : : /* Scan first few sectors for anything looking like a label */
220 [ # # ]: 0 : for (sector = 0; sector < LABEL_SCAN_SECTORS;
221 : 0 : sector += LABEL_SIZE >> SECTOR_SHIFT) {
222 : 0 : lh = (struct label_header *) (readbuf +
223 : 0 : (sector << SECTOR_SHIFT));
224 : :
225 : 0 : wipe = 0;
226 : :
227 [ # # ]: 0 : if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
228 [ # # ]: 0 : if (xlate64(lh->sector_xl) == sector)
229 : 0 : wipe = 1;
230 : : } else {
231 [ # # ]: 0 : dm_list_iterate_items(li, &_labellers) {
232 [ # # ]: 0 : if (li->l->ops->can_handle(li->l, (char *) lh,
233 : : sector)) {
234 : 0 : wipe = 1;
235 : 0 : break;
236 : : }
237 : : }
238 : : }
239 : :
240 [ # # ]: 0 : if (wipe) {
241 : 0 : log_info("%s: Wiping label at sector %" PRIu64,
242 : : dev_name(dev), sector);
243 [ # # ]: 0 : if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
244 : : buf)) {
245 : 0 : log_error("Failed to remove label from %s at "
246 : : "sector %" PRIu64, dev_name(dev),
247 : : sector);
248 : 0 : r = 0;
249 : : }
250 : : }
251 : : }
252 : :
253 : : out:
254 [ # # ]: 0 : if (!dev_close(dev))
255 : 0 : stack;
256 : :
257 : 0 : return r;
258 : : }
259 : :
260 : 0 : int label_read(struct device *dev, struct label **result,
261 : : uint64_t scan_sector)
262 : : {
263 : : char buf[LABEL_SIZE] __attribute((aligned(8)));
264 : : struct labeller *l;
265 : : uint64_t sector;
266 : : struct lvmcache_info *info;
267 : 0 : int r = 0;
268 : :
269 [ # # ]: 0 : if ((info = info_from_pvid(dev->pvid, 1))) {
270 : 0 : log_debug("Using cached label for %s", dev_name(dev));
271 : 0 : *result = info->label;
272 : 0 : return 1;
273 : : }
274 : :
275 [ # # ]: 0 : if (!dev_open(dev)) {
276 : 0 : stack;
277 : :
278 [ # # ]: 0 : if ((info = info_from_pvid(dev->pvid, 0)))
279 : 0 : lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
280 : 0 : info->fmt->orphan_vg_name,
281 : : 0, NULL);
282 : :
283 : 0 : return r;
284 : : }
285 : :
286 [ # # ]: 0 : if (!(l = _find_labeller(dev, buf, §or, scan_sector)))
287 : 0 : goto out;
288 : :
289 [ # # ][ # # ]: 0 : if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
[ # # ]
290 : 0 : (*result)->sector = sector;
291 : :
292 : : out:
293 [ # # ]: 0 : if (!dev_close(dev))
294 : 0 : stack;
295 : :
296 : 0 : return r;
297 : : }
298 : :
299 : : /* Caller may need to use label_get_handler to create label struct! */
300 : 0 : int label_write(struct device *dev, struct label *label)
301 : : {
302 : : char buf[LABEL_SIZE] __attribute((aligned(8)));
303 : 0 : struct label_header *lh = (struct label_header *) buf;
304 : 0 : int r = 1;
305 : :
306 [ # # ]: 0 : if (!label->labeller->ops->write) {
307 : 0 : log_error("Label handler does not support label writes");
308 : 0 : return 0;
309 : : }
310 : :
311 [ # # ]: 0 : if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
312 : 0 : log_error("Label sector %" PRIu64 " beyond range (%ld)",
313 : : label->sector, LABEL_SCAN_SECTORS);
314 : 0 : return 0;
315 : : }
316 : :
317 : 0 : memset(buf, 0, LABEL_SIZE);
318 : :
319 : 0 : strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
320 : 0 : lh->sector_xl = xlate64(label->sector);
321 : 0 : lh->offset_xl = xlate32(sizeof(*lh));
322 : :
323 [ # # ]: 0 : if (!(label->labeller->ops->write)(label, buf))
324 : 0 : return_0;
325 : :
326 : 0 : lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
327 : : ((uintptr_t) &lh->offset_xl - (uintptr_t) lh)));
328 : :
329 [ # # ]: 0 : if (!dev_open(dev))
330 : 0 : return_0;
331 : :
332 : 0 : log_info("%s: Writing label to sector %" PRIu64 " with stored offset %"
333 : : PRIu32 ".", dev_name(dev), label->sector,
334 : : xlate32(lh->offset_xl));
335 [ # # ]: 0 : if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
336 : 0 : log_debug("Failed to write label to %s", dev_name(dev));
337 : 0 : r = 0;
338 : : }
339 : :
340 [ # # ]: 0 : if (!dev_close(dev))
341 : 0 : stack;
342 : :
343 : 0 : return r;
344 : : }
345 : :
346 : : /* Unused */
347 : 0 : int label_verify(struct device *dev)
348 : : {
349 : : struct labeller *l;
350 : : char buf[LABEL_SIZE] __attribute((aligned(8)));
351 : : uint64_t sector;
352 : : struct lvmcache_info *info;
353 : 0 : int r = 0;
354 : :
355 [ # # ]: 0 : if (!dev_open(dev)) {
356 [ # # ]: 0 : if ((info = info_from_pvid(dev->pvid, 0)))
357 : 0 : lvmcache_update_vgname_and_id(info, info->fmt->orphan_vg_name,
358 : 0 : info->fmt->orphan_vg_name,
359 : : 0, NULL);
360 : :
361 : 0 : return_0;
362 : : }
363 : :
364 [ # # ]: 0 : if (!(l = _find_labeller(dev, buf, §or, UINT64_C(0))))
365 : 0 : goto out;
366 : :
367 [ # # ]: 0 : r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
368 : :
369 : : out:
370 [ # # ]: 0 : if (!dev_close(dev))
371 : 0 : stack;
372 : :
373 : 0 : return r;
374 : : }
375 : :
376 : 0 : void label_destroy(struct label *label)
377 : : {
378 : 0 : label->labeller->ops->destroy_label(label->labeller, label);
379 : 0 : dm_free(label);
380 : 0 : }
381 : :
382 : 0 : struct label *label_create(struct labeller *labeller)
383 : : {
384 : : struct label *label;
385 : :
386 [ # # ]: 0 : if (!(label = dm_malloc(sizeof(*label)))) {
387 : 0 : log_error("label allocaction failed");
388 : 0 : return NULL;
389 : : }
390 : 0 : memset(label, 0, sizeof(*label));
391 : :
392 : 0 : label->labeller = labeller;
393 : :
394 : 0 : labeller->ops->initialise_label(labeller, label);
395 : :
396 : 0 : return label;
397 : : }
|