xref: /dragonfly/contrib/lvm2/dist/lib/label/label.c (revision 548a3528)
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 
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 
61 static void _free_li(struct labeller_i *li)
62 {
63 	dm_free(li);
64 }
65 
66 int label_init(void)
67 {
68 	dm_list_init(&_labellers);
69 	return 1;
70 }
71 
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 
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 
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 
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? */
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 
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, &sector, 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! */
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 */
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, &sector, 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 
378 void label_destroy(struct label *label)
379 {
380 	label->labeller->ops->destroy_label(label->labeller, label);
381 	dm_free(label);
382 }
383 
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