From 9dbe25709e3805fbbc8024f0be68de2aae815747 Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Thu, 14 Feb 2013 16:04:35 +0100 Subject: [PATCH] pv_header_extension: add support for reading PV header extension (flags & Embedding Area) New tools with PV header extension support will read the extension if it exists and it's not an error if it does not exist (so old PVs will still work seamlessly with new tools). Old tools without PV header extension support will just ignore any extension. As for the Embedding Area location information (its start and size), there are actually two places where this is stored: - PV header extension - VG metadata The VG metadata contains a copy of what's written in the PV header extension about the Embedding Area location (NULL value is not copied): physical_volumes { pv0 { id = "AkSSRf-difg-fCCZ-NjAN-qP49-1zzg-S0Fd4T" device = "/dev/sda" # Hint only status = ["ALLOCATABLE"] flags = [] dev_size = 262144 # 128 Megabytes pe_start = 67584 pe_count = 23 # 92 Megabytes ea_start = 2048 ea_size = 65536 # 32 Megabytes } } The new metadata fields are "ea_start" and "ea_size". This is mostly useful when restoring the PV by using existing metadata backups (e.g. pvcreate --restorefile ...). New tools does not require these two fields to exist in VG metadata, they're not compulsory. Therefore, reading old VG metadata which doesn't contain any Embedding Area information will not end up with any kind of error but only a debug message that the ea_start and ea_size values were not found. Old tools just ignore these extra fields in VG metadata. --- lib/cache/lvmcache.c | 13 ++++++++++++ lib/cache/lvmetad.c | 40 +++++++++++++++++++++++++++-------- lib/format1/format1.c | 1 + lib/format_text/import_vsn1.c | 17 ++++++++++++++- lib/format_text/layout.h | 2 +- lib/format_text/text_label.c | 26 +++++++++++++++++++++++ lib/metadata/pv.c | 10 +++++++++ lib/metadata/pv.h | 2 ++ tools/pvcreate.c | 1 + 9 files changed, 101 insertions(+), 11 deletions(-) diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 4da8fe41d..13a722fde 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -1479,6 +1479,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, lvmcache_del_mdas(info); lvmcache_del_das(info); + lvmcache_del_eas(info); } else { if (existing->dev != dev) { /* Is the existing entry a duplicate pvid e.g. md ? */ @@ -1723,9 +1724,21 @@ int lvmcache_populate_pv_fields(struct lvmcache_info *info, return 0; } + /* Currently only support one embedding area at most */ + if (dm_list_size(&info->eas) > 1) { + log_error("Must be at most one embedding area (found %d) on PV %s", + dm_list_size(&info->eas), dev_name(info->dev)); + return 0; + } + dm_list_iterate_items(da, &info->das) pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT; + dm_list_iterate_items(da, &info->eas) { + pv->ea_start = da->disk_locn.offset >> SECTOR_SHIFT; + pv->ea_size = da->disk_locn.size >> SECTOR_SHIFT; + } + return 1; } diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c index 886f16397..2f9ffea49 100644 --- a/lib/cache/lvmetad.c +++ b/lib/cache/lvmetad.c @@ -280,6 +280,7 @@ static struct lvmcache_info *_pv_populate_lvmcache( lvmcache_set_device_size(info, devsize); lvmcache_del_das(info); lvmcache_del_mdas(info); + lvmcache_del_eas(info); do { sprintf(mda_id, "mda%d", i); @@ -301,6 +302,15 @@ static struct lvmcache_info *_pv_populate_lvmcache( ++i; } while (da); + i = 0; + do { + sprintf(da_id, "ea%d", i); + da = dm_config_find_node(cn->child, da_id); + if (!dm_config_get_uint64(da->child, "offset", &offset)) return_0; + if (!dm_config_get_uint64(da->child, "size", &size)) return_0; + lvmcache_add_ea(info, offset, size); + } while (da); + return info; } @@ -629,7 +639,7 @@ int lvmetad_vg_list_to_lvmcache(struct cmd_context *cmd) return 1; } -struct _extract_mda_baton { +struct _extract_dl_baton { int i; struct dm_config_tree *cft; struct dm_config_node *pre_sib; @@ -637,7 +647,7 @@ struct _extract_mda_baton { static int _extract_mda(struct metadata_area *mda, void *baton) { - struct _extract_mda_baton *b = baton; + struct _extract_dl_baton *b = baton; struct dm_config_node *cn; char id[32]; @@ -656,21 +666,21 @@ static int _extract_mda(struct metadata_area *mda, void *baton) return 1; } -static int _extract_da(struct disk_locn *da, void *baton) +static int _extract_disk_location(const char *name, struct disk_locn *dl, void *baton) { - struct _extract_mda_baton *b = baton; + struct _extract_dl_baton *b = baton; struct dm_config_node *cn; char id[32]; - if (!da) + if (!dl) return 1; - (void) dm_snprintf(id, 32, "da%d", b->i); + (void) dm_snprintf(id, 32, "name%d", b->i); if (!(cn = make_config_node(b->cft, id, b->cft->root, b->pre_sib))) return 0; if (!config_make_nodes(b->cft, cn, NULL, - "offset = %"PRId64, (int64_t) da->offset, - "size = %"PRId64, (int64_t) da->size, + "offset = %"PRId64, (int64_t) dl->offset, + "size = %"PRId64, (int64_t) dl->size, NULL)) return 0; @@ -680,16 +690,28 @@ static int _extract_da(struct disk_locn *da, void *baton) return 1; } +static int _extract_da(struct disk_locn *da, void *baton) +{ + return _extract_disk_location("da", da, baton); +} + +static int _extract_ea(struct disk_locn *ea, void *baton) +{ + return _extract_disk_location("ea", ea, baton); +} + static int _extract_mdas(struct lvmcache_info *info, struct dm_config_tree *cft, struct dm_config_node *pre_sib) { - struct _extract_mda_baton baton = { .i = 0, .cft = cft, .pre_sib = NULL }; + struct _extract_dl_baton baton = { .i = 0, .cft = cft, .pre_sib = NULL }; if (!lvmcache_foreach_mda(info, &_extract_mda, &baton)) return 0; baton.i = 0; if (!lvmcache_foreach_da(info, &_extract_da, &baton)) return 0; + if (!lvmcache_foreach_ea(info, &_extract_ea, &baton)) + return 0; return 1; } diff --git a/lib/format1/format1.c b/lib/format1/format1.c index 335a7e2f3..c90c26611 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -423,6 +423,7 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu lvmcache_update_pv(info, pv, fmt); lvmcache_del_mdas(info); lvmcache_del_das(info); + lvmcache_del_eas(info); dm_list_init(&pvs); diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index 33ad37dc9..d5b5a730d 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -165,7 +165,7 @@ static int _read_pv(struct format_instance *fid, struct physical_volume *pv; struct pv_list *pvl; const struct dm_config_value *cv; - uint64_t size; + uint64_t size, ea_start; if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) || !(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) @@ -246,6 +246,21 @@ static int _read_pv(struct format_instance *fid, return 0; } + /* Embedding area is not compulsory - just log_debug if not found. */ + ea_start = size = 0; + if (!_read_uint64(pvn, "ea_start", &ea_start)) + log_debug("PV Embedding Area start value (ea_start) not found."); + if (!_read_uint64(pvn, "ea_size", &size)) + log_debug("PV Embedding Area size (ea_size) not found."); + if ((!ea_start && size) || (ea_start && !size)) { + log_error("Incomplete embedding area specification for " + "physical volume."); + return 0; + } else { + pv->ea_start = ea_start; + pv->ea_size = size; + } + dm_list_init(&pv->tags); dm_list_init(&pv->segments); diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h index 6bd3fe472..92dc58296 100644 --- a/lib/format_text/layout.h +++ b/lib/format_text/layout.h @@ -29,7 +29,7 @@ struct pv_header_extension { uint32_t version; uint32_t flags; /* NULL-terminated list of embedding areas */ - struct disk_locn embedding_area_xl[0]; + struct disk_locn embedding_areas_xl[0]; } __attribute__ ((packed)); /* Fields with the suffix _xl should be xlate'd wherever they appear */ diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index be28f11c2..7ee902271 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -336,11 +336,16 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf, { struct label_header *lh = (struct label_header *) buf; struct pv_header *pvhdr; + struct pv_header_extension *pvhdr_ext; struct lvmcache_info *info; struct disk_locn *dlocn_xl; uint64_t offset; + uint32_t ext_version; struct _update_mda_baton baton; + /* + * PV header base + */ pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl)); if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev, @@ -354,6 +359,7 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf, lvmcache_del_das(info); lvmcache_del_mdas(info); + lvmcache_del_eas(info); /* Data areas holding the PEs */ dlocn_xl = pvhdr->disk_areas_xl; @@ -369,6 +375,25 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf, dlocn_xl++; } + dlocn_xl++; + + /* + * PV header extension + */ + pvhdr_ext = (struct pv_header_extension *) ((char *) dlocn_xl); + if (!(ext_version = xlate32(pvhdr_ext->version))) + goto out; + + log_debug("%s: PV header extension version %" PRIu32 " found", + dev_name(dev), ext_version); + + /* Embedding areas */ + dlocn_xl = pvhdr_ext->embedding_areas_xl; + while ((offset = xlate64(dlocn_xl->offset))) { + lvmcache_add_ea(info, offset, xlate64(dlocn_xl->size)); + dlocn_xl++; + } +out: baton.info = info; baton.label = *label; @@ -385,6 +410,7 @@ static void _text_destroy_label(struct labeller *l __attribute__((unused)), lvmcache_del_mdas(info); lvmcache_del_das(info); + lvmcache_del_eas(info); } static void _fmt_text_destroy(struct labeller *l) diff --git a/lib/metadata/pv.c b/lib/metadata/pv.c index 3cd06aa21..6c165a841 100644 --- a/lib/metadata/pv.c +++ b/lib/metadata/pv.c @@ -124,6 +124,16 @@ uint32_t pv_pe_size(const struct physical_volume *pv) return pv_field(pv, pe_size); } +uint64_t pv_ea_start(const struct physical_volume *pv) +{ + return pv_field(pv, ea_start); +} + +uint64_t pv_ea_size(const struct physical_volume *pv) +{ + return pv_field(pv, ea_size); +} + uint64_t pv_pe_start(const struct physical_volume *pv) { return pv_field(pv, pe_start); diff --git a/lib/metadata/pv.h b/lib/metadata/pv.h index 69d4868c1..6db9d8766 100644 --- a/lib/metadata/pv.h +++ b/lib/metadata/pv.h @@ -80,6 +80,8 @@ uint64_t pv_free(const struct physical_volume *pv); uint64_t pv_status(const struct physical_volume *pv); uint32_t pv_pe_size(const struct physical_volume *pv); uint64_t pv_pe_start(const struct physical_volume *pv); +uint64_t pv_ea_start(const struct physical_volume *pv); +uint64_t pv_ea_size(const struct physical_volume *pv); uint32_t pv_pe_count(const struct physical_volume *pv); uint32_t pv_pe_alloc_count(const struct physical_volume *pv); uint64_t pv_mda_size(const struct physical_volume *pv); diff --git a/tools/pvcreate.c b/tools/pvcreate.c index d7e7e5245..eb2fb5e7f 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -76,6 +76,7 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd, pp->rp.pe_start = pv_pe_start(existing_pvl->pv); pp->rp.extent_size = pv_pe_size(existing_pvl->pv); pp->rp.extent_count = pv_pe_count(existing_pvl->pv); + release_vg(vg); }