1 1.1 haad /* $NetBSD: disk-rep.c,v 1.1.1.2 2009/12/02 00:26:48 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2001-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 "disk-rep.h" 20 1.1 haad #include "xlate.h" 21 1.1 haad #include "filter.h" 22 1.1 haad #include "lvmcache.h" 23 1.1 haad 24 1.1 haad #include <fcntl.h> 25 1.1 haad 26 1.1 haad #define xx16(v) disk->v = xlate16(disk->v) 27 1.1 haad #define xx32(v) disk->v = xlate32(disk->v) 28 1.1 haad #define xx64(v) disk->v = xlate64(disk->v) 29 1.1 haad 30 1.1 haad /* 31 1.1 haad * Functions to perform the endian conversion 32 1.1 haad * between disk and core. The same code works 33 1.1 haad * both ways of course. 34 1.1 haad */ 35 1.1 haad static void _xlate_pvd(struct pv_disk *disk) 36 1.1 haad { 37 1.1 haad xx16(version); 38 1.1 haad 39 1.1 haad xx32(pv_on_disk.base); 40 1.1 haad xx32(pv_on_disk.size); 41 1.1 haad xx32(vg_on_disk.base); 42 1.1 haad xx32(vg_on_disk.size); 43 1.1 haad xx32(pv_uuidlist_on_disk.base); 44 1.1 haad xx32(pv_uuidlist_on_disk.size); 45 1.1 haad xx32(lv_on_disk.base); 46 1.1 haad xx32(lv_on_disk.size); 47 1.1 haad xx32(pe_on_disk.base); 48 1.1 haad xx32(pe_on_disk.size); 49 1.1 haad 50 1.1 haad xx32(pv_major); 51 1.1 haad xx32(pv_number); 52 1.1 haad xx32(pv_status); 53 1.1 haad xx32(pv_allocatable); 54 1.1 haad xx32(pv_size); 55 1.1 haad xx32(lv_cur); 56 1.1 haad xx32(pe_size); 57 1.1 haad xx32(pe_total); 58 1.1 haad xx32(pe_allocated); 59 1.1 haad xx32(pe_start); 60 1.1 haad } 61 1.1 haad 62 1.1 haad static void _xlate_lvd(struct lv_disk *disk) 63 1.1 haad { 64 1.1 haad xx32(lv_access); 65 1.1 haad xx32(lv_status); 66 1.1 haad xx32(lv_open); 67 1.1 haad xx32(lv_dev); 68 1.1 haad xx32(lv_number); 69 1.1 haad xx32(lv_mirror_copies); 70 1.1 haad xx32(lv_recovery); 71 1.1 haad xx32(lv_schedule); 72 1.1 haad xx32(lv_size); 73 1.1 haad xx32(lv_snapshot_minor); 74 1.1 haad xx16(lv_chunk_size); 75 1.1 haad xx16(dummy); 76 1.1 haad xx32(lv_allocated_le); 77 1.1 haad xx32(lv_stripes); 78 1.1 haad xx32(lv_stripesize); 79 1.1 haad xx32(lv_badblock); 80 1.1 haad xx32(lv_allocation); 81 1.1 haad xx32(lv_io_timeout); 82 1.1 haad xx32(lv_read_ahead); 83 1.1 haad } 84 1.1 haad 85 1.1 haad static void _xlate_vgd(struct vg_disk *disk) 86 1.1 haad { 87 1.1 haad xx32(vg_number); 88 1.1 haad xx32(vg_access); 89 1.1 haad xx32(vg_status); 90 1.1 haad xx32(lv_max); 91 1.1 haad xx32(lv_cur); 92 1.1 haad xx32(lv_open); 93 1.1 haad xx32(pv_max); 94 1.1 haad xx32(pv_cur); 95 1.1 haad xx32(pv_act); 96 1.1 haad xx32(dummy); 97 1.1 haad xx32(vgda); 98 1.1 haad xx32(pe_size); 99 1.1 haad xx32(pe_total); 100 1.1 haad xx32(pe_allocated); 101 1.1 haad xx32(pvg_total); 102 1.1 haad } 103 1.1 haad 104 1.1 haad static void _xlate_extents(struct pe_disk *extents, uint32_t count) 105 1.1 haad { 106 1.1 haad unsigned i; 107 1.1 haad 108 1.1 haad for (i = 0; i < count; i++) { 109 1.1 haad extents[i].lv_num = xlate16(extents[i].lv_num); 110 1.1 haad extents[i].le_num = xlate16(extents[i].le_num); 111 1.1 haad } 112 1.1 haad } 113 1.1 haad 114 1.1 haad /* 115 1.1 haad * Handle both minor metadata formats. 116 1.1 haad */ 117 1.1 haad static int _munge_formats(struct pv_disk *pvd) 118 1.1 haad { 119 1.1 haad uint32_t pe_start; 120 1.1 haad unsigned b, e; 121 1.1 haad 122 1.1 haad switch (pvd->version) { 123 1.1 haad case 1: 124 1.1 haad pvd->pe_start = ((pvd->pe_on_disk.base + 125 1.1 haad pvd->pe_on_disk.size) >> SECTOR_SHIFT); 126 1.1 haad break; 127 1.1 haad 128 1.1 haad case 2: 129 1.1 haad pvd->version = 1; 130 1.1 haad pe_start = pvd->pe_start << SECTOR_SHIFT; 131 1.1 haad pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base; 132 1.1 haad break; 133 1.1 haad 134 1.1 haad default: 135 1.1 haad return 0; 136 1.1 haad } 137 1.1 haad 138 1.1 haad /* UUID too long? */ 139 1.1 haad if (pvd->pv_uuid[ID_LEN]) { 140 1.1 haad /* Retain ID_LEN chars from end */ 141 1.1 haad for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) { 142 1.1 haad if (!pvd->pv_uuid[e]) { 143 1.1 haad e--; 144 1.1 haad break; 145 1.1 haad } 146 1.1 haad } 147 1.1 haad for (b = 0; b < ID_LEN; b++) { 148 1.1 haad pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN]; 149 1.1 haad /* FIXME Remove all invalid chars */ 150 1.1 haad if (pvd->pv_uuid[b] == '/') 151 1.1 haad pvd->pv_uuid[b] = '#'; 152 1.1 haad } 153 1.1 haad memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN); 154 1.1 haad } 155 1.1 haad 156 1.1 haad /* If UUID is missing, create one */ 157 1.1 haad if (pvd->pv_uuid[0] == '\0') { 158 1.1 haad uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number); 159 1.1 haad pvd->pv_uuid[ID_LEN] = '\0'; 160 1.1 haad } 161 1.1 haad 162 1.1 haad return 1; 163 1.1 haad } 164 1.1 haad 165 1.1 haad /* 166 1.1 haad * If exported, remove "PV_EXP" from end of VG name 167 1.1 haad */ 168 1.1 haad static void _munge_exported_vg(struct pv_disk *pvd) 169 1.1 haad { 170 1.1 haad int l; 171 1.1 haad size_t s; 172 1.1 haad 173 1.1 haad /* Return if PV not in a VG */ 174 1.1 haad if ((!*pvd->vg_name)) 175 1.1 haad return; 176 1.1 haad /* FIXME also check vgd->status & VG_EXPORTED? */ 177 1.1 haad 178 1.1 haad l = strlen((char *)pvd->vg_name); 179 1.1 haad s = sizeof(EXPORTED_TAG); 180 1.1 haad if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) { 181 1.1 haad pvd->vg_name[l - s + 1] = '\0'; 182 1.1 haad pvd->pv_status |= VG_EXPORTED; 183 1.1 haad } 184 1.1 haad } 185 1.1 haad 186 1.1 haad int munge_pvd(struct device *dev, struct pv_disk *pvd) 187 1.1 haad { 188 1.1 haad _xlate_pvd(pvd); 189 1.1 haad 190 1.1 haad if (pvd->id[0] != 'H' || pvd->id[1] != 'M') { 191 1.1 haad log_very_verbose("%s does not have a valid LVM1 PV identifier", 192 1.1 haad dev_name(dev)); 193 1.1 haad return 0; 194 1.1 haad } 195 1.1 haad 196 1.1 haad if (!_munge_formats(pvd)) { 197 1.1 haad log_very_verbose("format1: Unknown metadata version %d " 198 1.1 haad "found on %s", pvd->version, dev_name(dev)); 199 1.1 haad return 0; 200 1.1 haad } 201 1.1 haad 202 1.1 haad /* If VG is exported, set VG name back to the real name */ 203 1.1 haad _munge_exported_vg(pvd); 204 1.1 haad 205 1.1 haad return 1; 206 1.1 haad } 207 1.1 haad 208 1.1 haad static int _read_pvd(struct device *dev, struct pv_disk *pvd) 209 1.1 haad { 210 1.1 haad if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) { 211 1.1 haad log_very_verbose("Failed to read PV data from %s", 212 1.1 haad dev_name(dev)); 213 1.1 haad return 0; 214 1.1 haad } 215 1.1 haad 216 1.1 haad return munge_pvd(dev, pvd); 217 1.1 haad } 218 1.1 haad 219 1.1 haad static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) 220 1.1 haad { 221 1.1 haad if (!dev_read(dev, pos, sizeof(*disk), disk)) 222 1.1 haad return_0; 223 1.1 haad 224 1.1 haad _xlate_lvd(disk); 225 1.1 haad 226 1.1 haad return 1; 227 1.1 haad } 228 1.1 haad 229 1.1 haad int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd) 230 1.1 haad { 231 1.1 haad uint64_t pos = pvd->vg_on_disk.base; 232 1.1 haad 233 1.1 haad if (!dev_read(dev, pos, sizeof(*vgd), vgd)) 234 1.1 haad return_0; 235 1.1 haad 236 1.1 haad _xlate_vgd(vgd); 237 1.1 haad 238 1.1 haad if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV)) 239 1.1 haad return_0; 240 1.1 haad 241 1.1 haad /* If UUID is missing, create one */ 242 1.1 haad if (vgd->vg_uuid[0] == '\0') 243 1.1 haad uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number); 244 1.1 haad 245 1.1 haad return 1; 246 1.1 haad } 247 1.1 haad 248 1.1 haad static int _read_uuids(struct disk_list *data) 249 1.1 haad { 250 1.1 haad unsigned num_read = 0; 251 1.1 haad struct uuid_list *ul; 252 1.1 haad char buffer[NAME_LEN] __attribute((aligned(8))); 253 1.1 haad uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; 254 1.1 haad uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; 255 1.1 haad 256 1.1 haad while (pos < end && num_read < data->vgd.pv_cur) { 257 1.1 haad if (!dev_read(data->dev, pos, sizeof(buffer), buffer)) 258 1.1 haad return_0; 259 1.1 haad 260 1.1 haad if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul)))) 261 1.1 haad return_0; 262 1.1 haad 263 1.1 haad memcpy(ul->uuid, buffer, NAME_LEN); 264 1.1 haad ul->uuid[NAME_LEN - 1] = '\0'; 265 1.1 haad 266 1.1 haad dm_list_add(&data->uuids, &ul->list); 267 1.1 haad 268 1.1 haad pos += NAME_LEN; 269 1.1 haad num_read++; 270 1.1 haad } 271 1.1 haad 272 1.1 haad return 1; 273 1.1 haad } 274 1.1 haad 275 1.1 haad static int _check_lvd(struct lv_disk *lvd) 276 1.1 haad { 277 1.1 haad return !(lvd->lv_name[0] == '\0'); 278 1.1 haad } 279 1.1 haad 280 1.1 haad static int _read_lvs(struct disk_list *data) 281 1.1 haad { 282 1.1 haad unsigned int i, lvs_read = 0; 283 1.1 haad uint64_t pos; 284 1.1 haad struct lvd_list *ll; 285 1.1 haad struct vg_disk *vgd = &data->vgd; 286 1.1 haad 287 1.1 haad for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) { 288 1.1 haad pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); 289 1.1 haad ll = dm_pool_alloc(data->mem, sizeof(*ll)); 290 1.1 haad 291 1.1 haad if (!ll) 292 1.1 haad return_0; 293 1.1 haad 294 1.1 haad if (!_read_lvd(data->dev, pos, &ll->lvd)) 295 1.1 haad return_0; 296 1.1 haad 297 1.1 haad if (!_check_lvd(&ll->lvd)) 298 1.1 haad continue; 299 1.1 haad 300 1.1 haad lvs_read++; 301 1.1 haad dm_list_add(&data->lvds, &ll->list); 302 1.1 haad } 303 1.1 haad 304 1.1 haad return 1; 305 1.1 haad } 306 1.1 haad 307 1.1 haad static int _read_extents(struct disk_list *data) 308 1.1 haad { 309 1.1 haad size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; 310 1.1 haad struct pe_disk *extents = dm_pool_alloc(data->mem, len); 311 1.1 haad uint64_t pos = data->pvd.pe_on_disk.base; 312 1.1 haad 313 1.1 haad if (!extents) 314 1.1 haad return_0; 315 1.1 haad 316 1.1 haad if (!dev_read(data->dev, pos, len, extents)) 317 1.1 haad return_0; 318 1.1 haad 319 1.1 haad _xlate_extents(extents, data->pvd.pe_total); 320 1.1 haad data->extents = extents; 321 1.1 haad 322 1.1 haad return 1; 323 1.1 haad } 324 1.1 haad 325 1.1 haad static void __update_lvmcache(const struct format_type *fmt, 326 1.1 haad struct disk_list *dl, 327 1.1 haad struct device *dev, const char *vgid, 328 1.1 haad unsigned exported) 329 1.1 haad { 330 1.1 haad struct lvmcache_info *info; 331 1.1 haad const char *vgname = *((char *)dl->pvd.vg_name) ? 332 1.1 haad (char *)dl->pvd.vg_name : fmt->orphan_vg_name; 333 1.1 haad 334 1.1 haad if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev, 335 1.1 haad vgname, vgid, exported ? EXPORTED_VG : 0))) { 336 1.1 haad stack; 337 1.1 haad return; 338 1.1 haad } 339 1.1 haad 340 1.1 haad info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT; 341 1.1 haad dm_list_init(&info->mdas); 342 1.1 haad info->status &= ~CACHE_INVALID; 343 1.1 haad } 344 1.1 haad 345 1.1 haad static struct disk_list *__read_disk(const struct format_type *fmt, 346 1.1 haad struct device *dev, struct dm_pool *mem, 347 1.1 haad const char *vg_name) 348 1.1 haad { 349 1.1 haad struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl)); 350 1.1 haad const char *name = dev_name(dev); 351 1.1 haad 352 1.1 haad if (!dl) 353 1.1 haad return_NULL; 354 1.1 haad 355 1.1 haad dl->dev = dev; 356 1.1 haad dl->mem = mem; 357 1.1 haad dm_list_init(&dl->uuids); 358 1.1 haad dm_list_init(&dl->lvds); 359 1.1 haad 360 1.1 haad if (!_read_pvd(dev, &dl->pvd)) 361 1.1 haad goto_bad; 362 1.1 haad 363 1.1 haad /* 364 1.1 haad * is it an orphan ? 365 1.1 haad */ 366 1.1 haad if (!*dl->pvd.vg_name) { 367 1.1 haad log_very_verbose("%s is not a member of any format1 VG", name); 368 1.1 haad 369 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); 370 1.1 haad return (vg_name) ? NULL : dl; 371 1.1 haad } 372 1.1 haad 373 1.1 haad if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) { 374 1.1 haad log_error("Failed to read VG data from PV (%s)", name); 375 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); 376 1.1 haad goto bad; 377 1.1 haad } 378 1.1 haad 379 1.1 haad if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) { 380 1.1 haad log_very_verbose("%s is not a member of the VG %s", 381 1.1 haad name, vg_name); 382 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); 383 1.1 haad goto bad; 384 1.1 haad } 385 1.1 haad 386 1.1 haad __update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid, 387 1.1 haad dl->vgd.vg_status & VG_EXPORTED); 388 1.1 haad 389 1.1 haad if (!_read_uuids(dl)) { 390 1.1 haad log_error("Failed to read PV uuid list from %s", name); 391 1.1 haad goto bad; 392 1.1 haad } 393 1.1 haad 394 1.1 haad if (!_read_lvs(dl)) { 395 1.1 haad log_error("Failed to read LV's from %s", name); 396 1.1 haad goto bad; 397 1.1 haad } 398 1.1 haad 399 1.1 haad if (!_read_extents(dl)) { 400 1.1 haad log_error("Failed to read extents from %s", name); 401 1.1 haad goto bad; 402 1.1 haad } 403 1.1 haad 404 1.1 haad log_very_verbose("Found %s in %sVG %s", name, 405 1.1 haad (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "", 406 1.1 haad dl->pvd.vg_name); 407 1.1 haad 408 1.1 haad return dl; 409 1.1 haad 410 1.1 haad bad: 411 1.1 haad dm_pool_free(dl->mem, dl); 412 1.1 haad return NULL; 413 1.1 haad } 414 1.1 haad 415 1.1 haad struct disk_list *read_disk(const struct format_type *fmt, struct device *dev, 416 1.1 haad struct dm_pool *mem, const char *vg_name) 417 1.1 haad { 418 1.1 haad struct disk_list *dl; 419 1.1 haad 420 1.1 haad if (!dev_open(dev)) 421 1.1 haad return_NULL; 422 1.1 haad 423 1.1 haad dl = __read_disk(fmt, dev, mem, vg_name); 424 1.1 haad 425 1.1 haad if (!dev_close(dev)) 426 1.1 haad stack; 427 1.1 haad 428 1.1 haad return dl; 429 1.1 haad } 430 1.1 haad 431 1.1 haad static void _add_pv_to_list(struct dm_list *head, struct disk_list *data) 432 1.1 haad { 433 1.1 haad struct pv_disk *pvd; 434 1.1 haad struct disk_list *diskl; 435 1.1 haad 436 1.1 haad dm_list_iterate_items(diskl, head) { 437 1.1 haad pvd = &diskl->pvd; 438 1.1 haad if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid, 439 1.1 haad sizeof(pvd->pv_uuid))) { 440 1.1.1.2 haad if (!dev_subsystem_part_major(data->dev)) { 441 1.1 haad log_very_verbose("Ignoring duplicate PV %s on " 442 1.1 haad "%s", pvd->pv_uuid, 443 1.1 haad dev_name(data->dev)); 444 1.1 haad return; 445 1.1 haad } 446 1.1.1.2 haad log_very_verbose("Duplicate PV %s - using %s %s", 447 1.1.1.2 haad pvd->pv_uuid, dev_subsystem_name(data->dev), 448 1.1.1.2 haad dev_name(data->dev)); 449 1.1 haad dm_list_del(&diskl->list); 450 1.1 haad break; 451 1.1 haad } 452 1.1 haad } 453 1.1 haad dm_list_add(head, &data->list); 454 1.1 haad } 455 1.1 haad 456 1.1 haad /* 457 1.1 haad * Build a list of pv_d's structures, allocated from mem. 458 1.1 haad * We keep track of the first object allocated from the pool 459 1.1 haad * so we can free off all the memory if something goes wrong. 460 1.1 haad */ 461 1.1 haad int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name, 462 1.1 haad struct dev_filter *filter, struct dm_pool *mem, 463 1.1 haad struct dm_list *head) 464 1.1 haad { 465 1.1 haad struct dev_iter *iter; 466 1.1 haad struct device *dev; 467 1.1 haad struct disk_list *data = NULL; 468 1.1 haad struct lvmcache_vginfo *vginfo; 469 1.1 haad struct lvmcache_info *info; 470 1.1 haad 471 1.1 haad /* Fast path if we already saw this VG and cached the list of PVs */ 472 1.1 haad if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) && 473 1.1 haad vginfo->infos.n) { 474 1.1 haad dm_list_iterate_items(info, &vginfo->infos) { 475 1.1 haad dev = info->dev; 476 1.1 haad if (dev && !(data = read_disk(fmt, dev, mem, vg_name))) 477 1.1 haad break; 478 1.1 haad _add_pv_to_list(head, data); 479 1.1 haad } 480 1.1 haad 481 1.1 haad /* Did we find the whole VG? */ 482 1.1 haad if (!vg_name || is_orphan_vg(vg_name) || 483 1.1 haad (data && *data->pvd.vg_name && 484 1.1 haad dm_list_size(head) == data->vgd.pv_cur)) 485 1.1 haad return 1; 486 1.1 haad 487 1.1 haad /* Failed */ 488 1.1 haad dm_list_init(head); 489 1.1 haad /* vgcache_del(vg_name); */ 490 1.1 haad } 491 1.1 haad 492 1.1 haad if (!(iter = dev_iter_create(filter, 1))) { 493 1.1 haad log_error("read_pvs_in_vg: dev_iter_create failed"); 494 1.1 haad return 0; 495 1.1 haad } 496 1.1 haad 497 1.1 haad /* Otherwise do a complete scan */ 498 1.1 haad for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { 499 1.1 haad if ((data = read_disk(fmt, dev, mem, vg_name))) { 500 1.1 haad _add_pv_to_list(head, data); 501 1.1 haad } 502 1.1 haad } 503 1.1 haad dev_iter_destroy(iter); 504 1.1 haad 505 1.1 haad if (dm_list_empty(head)) 506 1.1 haad return 0; 507 1.1 haad 508 1.1 haad return 1; 509 1.1 haad } 510 1.1 haad 511 1.1 haad static int _write_vgd(struct disk_list *data) 512 1.1 haad { 513 1.1 haad struct vg_disk *vgd = &data->vgd; 514 1.1 haad uint64_t pos = data->pvd.vg_on_disk.base; 515 1.1 haad 516 1.1 haad log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t, 517 1.1 haad data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd)); 518 1.1 haad 519 1.1 haad _xlate_vgd(vgd); 520 1.1 haad if (!dev_write(data->dev, pos, sizeof(*vgd), vgd)) 521 1.1 haad return_0; 522 1.1 haad 523 1.1 haad _xlate_vgd(vgd); 524 1.1 haad 525 1.1 haad return 1; 526 1.1 haad } 527 1.1 haad 528 1.1 haad static int _write_uuids(struct disk_list *data) 529 1.1 haad { 530 1.1 haad struct uuid_list *ul; 531 1.1 haad uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; 532 1.1 haad uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; 533 1.1 haad 534 1.1 haad dm_list_iterate_items(ul, &data->uuids) { 535 1.1 haad if (pos >= end) { 536 1.1 haad log_error("Too many uuids to fit on %s", 537 1.1 haad dev_name(data->dev)); 538 1.1 haad return 0; 539 1.1 haad } 540 1.1 haad 541 1.1 haad log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %d", 542 1.1 haad data->pvd.vg_name, dev_name(data->dev), 543 1.1 haad pos, NAME_LEN); 544 1.1 haad 545 1.1 haad if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid)) 546 1.1 haad return_0; 547 1.1 haad 548 1.1 haad pos += NAME_LEN; 549 1.1 haad } 550 1.1 haad 551 1.1 haad return 1; 552 1.1 haad } 553 1.1 haad 554 1.1 haad static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk) 555 1.1 haad { 556 1.1 haad log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %" 557 1.1 haad PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev), 558 1.1 haad pos, sizeof(*disk)); 559 1.1 haad 560 1.1 haad _xlate_lvd(disk); 561 1.1 haad if (!dev_write(dev, pos, sizeof(*disk), disk)) 562 1.1 haad return_0; 563 1.1 haad 564 1.1 haad _xlate_lvd(disk); 565 1.1 haad 566 1.1 haad return 1; 567 1.1 haad } 568 1.1 haad 569 1.1 haad static int _write_lvs(struct disk_list *data) 570 1.1 haad { 571 1.1 haad struct lvd_list *ll; 572 1.1 haad uint64_t pos, offset; 573 1.1 haad 574 1.1 haad pos = data->pvd.lv_on_disk.base; 575 1.1 haad 576 1.1 haad if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) { 577 1.1 haad log_error("Couldn't zero lv area on device '%s'", 578 1.1 haad dev_name(data->dev)); 579 1.1 haad return 0; 580 1.1 haad } 581 1.1 haad 582 1.1 haad dm_list_iterate_items(ll, &data->lvds) { 583 1.1 haad offset = sizeof(struct lv_disk) * ll->lvd.lv_number; 584 1.1 haad if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) { 585 1.1 haad log_error("lv_number %d too large", ll->lvd.lv_number); 586 1.1 haad return 0; 587 1.1 haad } 588 1.1 haad 589 1.1 haad if (!_write_lvd(data->dev, pos + offset, &ll->lvd)) 590 1.1 haad return_0; 591 1.1 haad } 592 1.1 haad 593 1.1 haad return 1; 594 1.1 haad } 595 1.1 haad 596 1.1 haad static int _write_extents(struct disk_list *data) 597 1.1 haad { 598 1.1 haad size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; 599 1.1 haad struct pe_disk *extents = data->extents; 600 1.1 haad uint64_t pos = data->pvd.pe_on_disk.base; 601 1.1 haad 602 1.1 haad log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %" 603 1.1 haad PRIsize_t, data->pvd.vg_name, dev_name(data->dev), 604 1.1 haad pos, len); 605 1.1 haad 606 1.1 haad _xlate_extents(extents, data->pvd.pe_total); 607 1.1 haad if (!dev_write(data->dev, pos, len, extents)) 608 1.1 haad return_0; 609 1.1 haad 610 1.1 haad _xlate_extents(extents, data->pvd.pe_total); 611 1.1 haad 612 1.1 haad return 1; 613 1.1 haad } 614 1.1 haad 615 1.1 haad static int _write_pvd(struct disk_list *data) 616 1.1 haad { 617 1.1 haad char *buf; 618 1.1 haad uint64_t pos = data->pvd.pv_on_disk.base; 619 1.1 haad size_t size = data->pvd.pv_on_disk.size; 620 1.1 haad 621 1.1 haad if (size < sizeof(struct pv_disk)) { 622 1.1 haad log_error("Invalid PV structure size."); 623 1.1 haad return 0; 624 1.1 haad } 625 1.1 haad 626 1.1 haad /* Make sure that the gap between the PV structure and 627 1.1 haad the next one is zeroed in order to make non LVM tools 628 1.1 haad happy (idea from AED) */ 629 1.1 haad buf = dm_malloc(size); 630 1.1 haad if (!buf) { 631 1.1.1.2 haad log_error("Couldn't allocate temporary PV buffer."); 632 1.1 haad return 0; 633 1.1 haad } 634 1.1 haad 635 1.1 haad memset(buf, 0, size); 636 1.1 haad memcpy(buf, &data->pvd, sizeof(struct pv_disk)); 637 1.1 haad 638 1.1 haad log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %" 639 1.1 haad PRIsize_t, data->pvd.vg_name, dev_name(data->dev), 640 1.1 haad pos, size); 641 1.1 haad 642 1.1 haad _xlate_pvd((struct pv_disk *) buf); 643 1.1 haad if (!dev_write(data->dev, pos, size, buf)) { 644 1.1 haad dm_free(buf); 645 1.1 haad return_0; 646 1.1 haad } 647 1.1 haad 648 1.1 haad dm_free(buf); 649 1.1 haad return 1; 650 1.1 haad } 651 1.1 haad 652 1.1 haad /* 653 1.1 haad * assumes the device has been opened. 654 1.1 haad */ 655 1.1 haad static int __write_all_pvd(const struct format_type *fmt __attribute((unused)), 656 1.1 haad struct disk_list *data) 657 1.1 haad { 658 1.1 haad const char *pv_name = dev_name(data->dev); 659 1.1 haad 660 1.1 haad if (!_write_pvd(data)) { 661 1.1 haad log_error("Failed to write PV structure onto %s", pv_name); 662 1.1 haad return 0; 663 1.1 haad } 664 1.1 haad 665 1.1 haad /* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */ 666 1.1 haad /* 667 1.1 haad * Stop here for orphan pv's. 668 1.1 haad */ 669 1.1 haad if (data->pvd.vg_name[0] == '\0') { 670 1.1 haad /* if (!test_mode()) 671 1.1 haad vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */ 672 1.1 haad return 1; 673 1.1 haad } 674 1.1 haad 675 1.1 haad /* if (!test_mode()) 676 1.1 haad vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, 677 1.1 haad fmt); */ 678 1.1 haad 679 1.1 haad if (!_write_vgd(data)) { 680 1.1 haad log_error("Failed to write VG data to %s", pv_name); 681 1.1 haad return 0; 682 1.1 haad } 683 1.1 haad 684 1.1 haad if (!_write_uuids(data)) { 685 1.1 haad log_error("Failed to write PV uuid list to %s", pv_name); 686 1.1 haad return 0; 687 1.1 haad } 688 1.1 haad 689 1.1 haad if (!_write_lvs(data)) { 690 1.1 haad log_error("Failed to write LV's to %s", pv_name); 691 1.1 haad return 0; 692 1.1 haad } 693 1.1 haad 694 1.1 haad if (!_write_extents(data)) { 695 1.1 haad log_error("Failed to write extents to %s", pv_name); 696 1.1 haad return 0; 697 1.1 haad } 698 1.1 haad 699 1.1 haad return 1; 700 1.1 haad } 701 1.1 haad 702 1.1 haad /* 703 1.1 haad * opens the device and hands to the above fn. 704 1.1 haad */ 705 1.1 haad static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data) 706 1.1 haad { 707 1.1 haad int r; 708 1.1 haad 709 1.1 haad if (!dev_open(data->dev)) 710 1.1 haad return_0; 711 1.1 haad 712 1.1 haad r = __write_all_pvd(fmt, data); 713 1.1 haad 714 1.1 haad if (!dev_close(data->dev)) 715 1.1 haad stack; 716 1.1 haad 717 1.1 haad return r; 718 1.1 haad } 719 1.1 haad 720 1.1 haad /* 721 1.1 haad * Writes all the given pv's to disk. Does very 722 1.1 haad * little sanity checking, so make sure correct 723 1.1 haad * data is passed to here. 724 1.1 haad */ 725 1.1 haad int write_disks(const struct format_type *fmt, struct dm_list *pvs) 726 1.1 haad { 727 1.1 haad struct disk_list *dl; 728 1.1 haad 729 1.1 haad dm_list_iterate_items(dl, pvs) { 730 1.1 haad if (!(_write_all_pvd(fmt, dl))) 731 1.1 haad return_0; 732 1.1 haad 733 1.1 haad log_very_verbose("Successfully wrote data to %s", 734 1.1 haad dev_name(dl->dev)); 735 1.1 haad } 736 1.1 haad 737 1.1 haad return 1; 738 1.1 haad } 739