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, §or, 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, §or, 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