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