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, §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! */ 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, §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 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