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