diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 3828d5f87..2831a53bd 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -121,157 +121,6 @@ static struct device *_mda_get_device_raw(struct metadata_area *mda) return mdac->area.dev; } -/* - * For circular region between region_start and region_start + region_size, - * back up one SECTOR_SIZE from 'region_ptr' and return the value. - * This allows reverse traversal through text metadata area to find old - * metadata. - * - * Parameters: - * region_start: start of the region (bytes) - * region_size: size of the region (bytes) - * region_ptr: pointer within the region (bytes) - * NOTE: region_start <= region_ptr <= region_start + region_size - */ -static uint64_t _get_prev_sector_circular(uint64_t region_start, - uint64_t region_size, - uint64_t region_ptr) -{ - if (region_ptr >= region_start + SECTOR_SIZE) - return region_ptr - SECTOR_SIZE; - - return (region_start + region_size - SECTOR_SIZE); -} - -/* - * Analyze a metadata area for old metadata records in the circular buffer. - * This function just looks through and makes a first pass at the data in - * the sectors for particular things. - * FIXME: do something with each metadata area (try to extract vg, write - * raw data to file, etc) - */ -static int _pv_analyze_mda_raw (const struct format_type * fmt, - struct metadata_area *mda) -{ - struct mda_header *mdah; - struct raw_locn *rlocn; - uint64_t area_start; - uint64_t area_size; - uint64_t prev_sector, prev_sector2; - uint64_t latest_mrec_offset; - uint64_t offset; - uint64_t offset2; - size_t size; - size_t size2; - char *buf=NULL; - struct device_area *area; - struct mda_context *mdac; - int r=0; - - mdac = (struct mda_context *) mda->metadata_locn; - - log_print("Found text metadata area: offset=" FMTu64 ", size=" - FMTu64, mdac->area.start, mdac->area.size); - area = &mdac->area; - - if (!(mdah = raw_read_mda_header(fmt, area, mda_is_primary(mda)))) - goto_out; - - rlocn = mdah->raw_locns; - - /* - * The device area includes the metadata header as well as the - * records, so remove the metadata header from the start and size - */ - area_start = area->start + MDA_HEADER_SIZE; - area_size = area->size - MDA_HEADER_SIZE; - latest_mrec_offset = rlocn->offset + area->start; - - /* - * Start searching at rlocn (point of live metadata) and go - * backwards. - */ - prev_sector = _get_prev_sector_circular(area_start, area_size, - latest_mrec_offset); - offset = prev_sector; - size = SECTOR_SIZE; - offset2 = size2 = 0; - - while (prev_sector != latest_mrec_offset) { - prev_sector2 = prev_sector; - prev_sector = _get_prev_sector_circular(area_start, area_size, - prev_sector); - if (prev_sector > prev_sector2) - goto_out; - /* - * FIXME: for some reason, the whole metadata region from - * area->start to area->start+area->size is not used. - * Only ~32KB seems to contain valid metadata records - * (LVM2 format - format_text). As a result, I end up with - * "dm_config_maybe_section" returning true when there's no valid - * metadata in a sector (sectors with all nulls). - */ - if (!(buf = malloc(size + size2))) - goto_out; - - if (!dev_read_bytes(area->dev, offset, size, buf)) { - log_error("Failed to read dev %s offset %llu size %llu", - dev_name(area->dev), - (unsigned long long)offset, - (unsigned long long)size); - goto out; - } - - if (size2) { - if (!dev_read_bytes(area->dev, offset2, size2, buf + size)) { - log_error("Failed to read dev %s offset %llu size %llu", - dev_name(area->dev), - (unsigned long long)offset2, - (unsigned long long)size2); - goto out; - } - } - - /* - * FIXME: We could add more sophisticated metadata detection - */ - if (dm_config_maybe_section(buf, size + size2)) { - /* FIXME: Validate region, pull out timestamp?, etc */ - /* FIXME: Do something with this region */ - log_verbose ("Found LVM2 metadata record at " - "offset=" FMTu64 ", size=" FMTsize_t ", " - "offset2=" FMTu64 " size2=" FMTsize_t, - offset, size, offset2, size2); - offset = prev_sector; - size = SECTOR_SIZE; - offset2 = size2 = 0; - } else { - /* - * Not a complete metadata record, assume we have - * metadata and just increase the size and offset. - * Start the second region if the previous sector is - * wrapping around towards the end of the disk. - */ - if (prev_sector > offset) { - offset2 = prev_sector; - size2 += SECTOR_SIZE; - } else { - offset = prev_sector; - size += SECTOR_SIZE; - } - } - free(buf); - buf = NULL; - } - - r = 1; - out: - free(buf); - return r; -} - - - static int _text_lv_setup(struct format_instance *fid __attribute__((unused)), struct logical_volume *lv) { @@ -1962,7 +1811,6 @@ static struct metadata_area_ops _metadata_text_raw_ops = { .mda_free_sectors = _mda_free_sectors_raw, .mda_total_sectors = _mda_total_sectors_raw, .mda_in_vg = _mda_in_vg_raw, - .pv_analyze_mda = _pv_analyze_mda_raw, .mda_locns_match = _mda_locns_match_raw, .mda_get_device = _mda_get_device_raw, }; diff --git a/lib/label/label.c b/lib/label/label.c index 43b05a257..10c1c4c0f 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -1198,66 +1198,6 @@ int label_read(struct device *dev) return 1; } -/* - * Read a label from a specfic, non-zero sector. This is used in only - * one place: pvck/pv_analyze. - */ - -int label_read_sector(struct device *dev, uint64_t read_sector) -{ - struct block *bb = NULL; - uint64_t block_num; - uint64_t block_sector; - uint64_t start_sector; - int is_lvm_device = 0; - int result; - int ret; - - block_num = read_sector / BCACHE_BLOCK_SIZE_IN_SECTORS; - block_sector = block_num * BCACHE_BLOCK_SIZE_IN_SECTORS; - start_sector = read_sector % BCACHE_BLOCK_SIZE_IN_SECTORS; - - if (!label_scan_open(dev)) { - log_error("Error opening device %s for prefetch %llu sector.", - dev_name(dev), (unsigned long long)block_num); - return false; - } - - bcache_prefetch(scan_bcache, dev->bcache_fd, block_num); - - if (!bcache_get(scan_bcache, dev->bcache_fd, block_num, 0, &bb)) { - log_error("Scan failed to read %s at %llu", - dev_name(dev), (unsigned long long)block_num); - ret = 0; - goto out; - } - - /* - * TODO: check if scan_sector is larger than the bcache block size. - * If it is, we need to fetch a later block from bcache. - */ - - result = _process_block(NULL, NULL, dev, bb, block_sector, start_sector, &is_lvm_device); - - if (!result && is_lvm_device) { - log_error("Scan failed to process %s", dev_name(dev)); - ret = 0; - goto out; - } - - if (!result || !is_lvm_device) { - log_error("Could not find LVM label on %s", dev_name(dev)); - ret = 0; - goto out; - } - - ret = 1; -out: - if (bb) - bcache_put(bb); - return ret; -} - int label_scan_setup_bcache(void) { if (!scan_bcache) { diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 8f6de2605..65da7e138 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -4664,41 +4664,6 @@ int is_real_vg(const char *vg_name) return (vg_name && *vg_name != '#'); } -static int _analyze_mda(struct metadata_area *mda, void *baton) -{ - const struct format_type *fmt = baton; - mda->ops->pv_analyze_mda(fmt, mda); - return 1; -} - -/* - * Returns: - * 0 - fail - * 1 - success - */ -int pv_analyze(struct cmd_context *cmd, struct device *dev, - uint64_t label_sector) -{ - struct label *label; - struct lvmcache_info *info; - - if (!(label = lvmcache_get_dev_label(dev))) { - log_error("Could not find LVM label on %s", dev_name(dev)); - return 0; - } - - log_print("Found label on %s, sector %"PRIu64", type=%.8s", - dev_name(dev), label->sector, label->type); - - /* - * Next, loop through metadata areas - */ - info = label->info; - lvmcache_foreach_mda(info, _analyze_mda, (void *)lvmcache_fmt(info)); - - return 1; -} - /* FIXME: remove / combine this with locking? */ int vg_check_write_mode(struct volume_group *vg) { diff --git a/tools/pvck.c b/tools/pvck.c index c9b833ad1..34371642a 100644 --- a/tools/pvck.c +++ b/tools/pvck.c @@ -83,13 +83,16 @@ static char *_chars_to_hexstr(void *in, void *out, int num, int max, const char return out; } -static int _check_label_header(struct label_header *lh, uint64_t labelsector) +static int _check_label_header(struct label_header *lh, uint64_t labelsector, + int *found_label) { uint32_t crc; + int good_id = 1, good_type = 1; int bad = 0; if (memcmp(lh->id, LABEL_ID, sizeof(lh->id))) { log_print("CHECK: label_header.id expected %s", LABEL_ID); + good_id = 0; bad++; } @@ -113,9 +116,14 @@ static int _check_label_header(struct label_header *lh, uint64_t labelsector) if (memcmp(lh->type, LVM2_LABEL, sizeof(lh->type))) { log_print("CHECK: label_header.type expected %s", LVM2_LABEL); + good_type = 0; bad++; } + /* Report a label is found if at least id and type are correct. */ + if (found_label && good_id && good_type) + *found_label = 1; + if (bad) return 0; return 1; @@ -140,10 +148,11 @@ static int _check_pv_header(struct pv_header *ph) * mda_offset/mda_size are from the pv_header/disk_locn and could * be incorrect. */ -static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_offset, uint64_t mda_size) +static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_offset, uint64_t mda_size, int *found_header) { char str[256]; uint32_t crc; + int good_magic = 1; int bad = 0; crc = calc_crc(INITIAL_CRC, (uint8_t *)mh->magic, @@ -156,6 +165,7 @@ static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_of if (memcmp(mh->magic, FMTT_MAGIC, sizeof(mh->magic))) { log_print("CHECK: mda_header_%d.magic expected 0x%s", mda_num, _chars_to_hexstr((void *)&FMTT_MAGIC, str, 16, 256, "mda_header.magic")); + good_magic = 0; bad++; } @@ -174,6 +184,10 @@ static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_of bad++; } + /* Report a header is found if at least magic is correct. */ + if (found_header && good_magic) + *found_header = 1; + if (bad) return 0; return 1; @@ -684,9 +698,10 @@ static int _dump_meta_text(struct device *dev, config_destroy(cft); } - log_print("metadata text at %llu crc 0x%x # vgname %s seqno %u", - (unsigned long long)(mda_offset + meta_offset), crc, - vgname ? vgname : "?", seqno); + if (print_fields || print_metadata) + log_print("metadata text at %llu crc 0x%x # vgname %s seqno %u", + (unsigned long long)(mda_offset + meta_offset), crc, + vgname ? vgname : "?", seqno); if (!print_metadata) goto out; @@ -720,6 +735,7 @@ static int _dump_meta_text(struct device *dev, static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields, struct device *dev, + int *found_label, uint64_t *mda1_offset, uint64_t *mda1_size, uint64_t *mda2_offset, uint64_t *mda2_size) { @@ -771,7 +787,7 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields, log_print("label_header.type %s", _chars_to_str(lh->type, str, 8, 256, "label_header.type")); } - if (!_check_label_header(lh, labelsector)) + if (!_check_label_header(lh, labelsector, found_label)) bad++; /* @@ -972,7 +988,8 @@ static int _dump_mda_header(struct cmd_context *cmd, const char *tofile, struct device *dev, uint64_t mda_offset, uint64_t mda_size, - uint32_t *checksum0_ret) + uint32_t *checksum0_ret, + int *found_header) { char str[256]; char *buf; @@ -1018,7 +1035,7 @@ static int _dump_mda_header(struct cmd_context *cmd, log_print("mda_header_%d.size %llu", mda_num, (unsigned long long)xlate64(mh->size)); } - if (!_check_mda_header(mh, mda_num, mda_offset, mda_size)) + if (!_check_mda_header(mh, mda_num, mda_offset, mda_size, found_header)) bad++; if (print_area) { @@ -1108,7 +1125,7 @@ static int _dump_headers(struct cmd_context *cmd, label_scan_setup_bcache(); - if (!_dump_label_and_pv_header(cmd, 1, dev, + if (!_dump_label_and_pv_header(cmd, 1, dev, NULL, &mda1_offset, &mda1_size, &mda2_offset, &mda2_size)) bad++; @@ -1125,7 +1142,7 @@ static int _dump_headers(struct cmd_context *cmd, * which may have been corrupted. */ - if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum)) + if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, NULL)) bad++; /* @@ -1136,7 +1153,7 @@ static int _dump_headers(struct cmd_context *cmd, * but there is a valid header elsewhere. */ if (mda2_offset) { - if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum)) + if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, NULL)) bad++; /* This probably indicates that one was committed and the other not. */ @@ -1181,7 +1198,7 @@ static int _dump_metadata(struct cmd_context *cmd, label_scan_setup_bcache(); - if (!_dump_label_and_pv_header(cmd, 0, dev, + if (!_dump_label_and_pv_header(cmd, 0, dev, NULL, &mda1_offset, &mda1_size, &mda2_offset, &mda2_size)) bad++; @@ -1204,14 +1221,14 @@ static int _dump_metadata(struct cmd_context *cmd, */ if (mda_num == 1) { - if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, 4096, mda1_size, &mda1_checksum)) + if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, 4096, mda1_size, &mda1_checksum, NULL)) bad++; } else if (mda_num == 2) { if (!mda2_offset) { log_print("CHECK: second mda not found"); bad++; } else { - if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, mda2_offset, mda2_size, &mda2_checksum)) + if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, mda2_offset, mda2_size, &mda2_checksum, NULL)) bad++; } } @@ -1223,16 +1240,59 @@ static int _dump_metadata(struct cmd_context *cmd, return ECMD_PROCESSED; } +static int _dump_found(struct cmd_context *cmd, struct device *dev, + uint64_t labelsector) +{ + uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0; + uint32_t mda1_checksum = 0, mda2_checksum = 0; + int found_label = 0, found_header1 = 0, found_header2 = 0; + int bad = 0; + + if (!_dump_label_and_pv_header(cmd, 0, dev, &found_label, + &mda1_offset, &mda1_size, &mda2_offset, &mda2_size)) + bad++; + + if (found_label && mda1_offset) { + if (!_dump_mda_header(cmd, 0, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, &found_header1)) + bad++; + } + + if (found_label && mda2_offset) { + if (!_dump_mda_header(cmd, 0, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, &found_header2)) + bad++; + } + + if (found_label) + log_print("Found label on %s, sector %llu, type=LVM2 001", + dev_name(dev), (unsigned long long)labelsector); + else { + log_error("Could not find LVM label on %s", dev_name(dev)); + return 0; + } + + if (found_header1) + log_print("Found text metadata area: offset=%llu, size=%llu", + (unsigned long long)mda1_offset, + (unsigned long long)mda1_size); + + if (found_header2) + log_print("Found text metadata area: offset=%llu, size=%llu", + (unsigned long long)mda2_offset, + (unsigned long long)mda2_size); + + if (bad) + return 0; + return 1; +} + int pvck(struct cmd_context *cmd, int argc, char **argv) { - struct dm_list devs; - struct device_list *devl; struct device *dev; const char *dump; const char *pv_name; - uint64_t labelsector; + uint64_t labelsector = 1; + int bad = 0; int i; - int ret_max = ECMD_PROCESSED; if (arg_is_set(cmd, dump_ARG)) { dump = arg_str_value(cmd, dump_ARG, NULL); @@ -1253,56 +1313,29 @@ int pvck(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0)); + /* + * The old/original form of pvck, which did not do much, + * but this is here to preserve the historical output. + */ - dm_list_init(&devs); + if (arg_is_set(cmd, labelsector_ARG)) + labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0)); + + label_scan_setup_bcache(); for (i = 0; i < argc; i++) { - dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); - pv_name = argv[i]; - dev = dev_cache_get(cmd, pv_name, cmd->filter); - - if (!dev) { + if (!(dev = dev_cache_get(cmd, argv[i], cmd->filter))) { log_error("Device %s %s.", pv_name, dev_cache_filtered_reason(pv_name)); continue; } - if (!(devl = zalloc(sizeof(*devl)))) - continue; - - devl->dev = dev; - dm_list_add(&devs, &devl->list); + if (!_dump_found(cmd, dev, labelsector)) + bad++; } - label_scan_setup_bcache(); - label_scan_devs(cmd, cmd->filter, &devs); - - dm_list_iterate_items(devl, &devs) { - /* - * The scan above will populate lvmcache with any info from the - * standard locations at the start of the device. Now populate - * lvmcache with any info from non-standard offsets. - * - * FIXME: is it possible for a real lvm label sector to be - * anywhere other than the first four sectors of the disk? - * If not, drop the code in label_read_sector/find_lvm_header - * that supports searching at any sector. - */ - if (labelsector) { - if (!label_read_sector(devl->dev, labelsector)) { - stack; - ret_max = ECMD_FAILED; - continue; - } - } - - if (!pv_analyze(cmd, devl->dev, labelsector)) { - stack; - ret_max = ECMD_FAILED; - } - } - - return ret_max; + if (bad) + return ECMD_FAILED; + return ECMD_PROCESSED; }