1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

pvck: allow checking at user specified offsets

with the --labelsector option.  We probably don't
need all this code to support any value for this
option; it's unclear how, when, why it would be
used.
This commit is contained in:
David Teigland 2018-05-10 16:27:34 -05:00
parent 413488edc6
commit 228ed56455
3 changed files with 99 additions and 36 deletions

View File

@ -251,9 +251,11 @@ static bool _in_bcache(struct device *dev)
static struct labeller *_find_lvm_header(struct device *dev,
char *scan_buf,
uint32_t scan_buf_sectors,
char *label_buf,
uint64_t *label_sector,
uint64_t scan_sector)
uint64_t block_sector,
uint64_t start_sector)
{
struct labeller_i *li;
struct labeller *labeller_ret = NULL;
@ -266,25 +268,34 @@ static struct labeller *_find_lvm_header(struct device *dev,
* and copy it into label_buf.
*/
for (sector = 0; sector < LABEL_SCAN_SECTORS;
for (sector = start_sector; sector < start_sector + LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
/*
* The scan_buf passed in is a bcache block, which is
* BCACHE_BLOCK_SIZE_IN_SECTORS large. So if start_sector is
* one of the last couple sectors in that buffer, we need to
* break early.
*/
if (sector >= scan_buf_sectors)
break;
lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
if (found) {
log_error("Ignoring additional label on %s at sector %llu",
dev_name(dev), (unsigned long long)(sector + scan_sector));
dev_name(dev), (unsigned long long)(block_sector + sector));
}
if (xlate64(lh->sector_xl) != sector + scan_sector) {
log_very_verbose("%s: Label for sector %llu found at sector %llu - ignoring.",
dev_name(dev),
(unsigned long long)xlate64(lh->sector_xl),
(unsigned long long)(sector + scan_sector));
if (xlate64(lh->sector_xl) != sector) {
log_warn("%s: Label for sector %llu found at sector %llu - ignoring.",
dev_name(dev),
(unsigned long long)xlate64(lh->sector_xl),
(unsigned long long)(block_sector + sector));
continue;
}
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
xlate32(lh->crc_xl)) {
if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl,
LABEL_SIZE - ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) != xlate32(lh->crc_xl)) {
log_very_verbose("Label checksum incorrect on %s - ignoring", dev_name(dev));
continue;
}
@ -293,14 +304,14 @@ static struct labeller *_find_lvm_header(struct device *dev,
}
dm_list_iterate_items(li, &_labellers) {
if (li->l->ops->can_handle(li->l, (char *) lh, sector + scan_sector)) {
if (li->l->ops->can_handle(li->l, (char *) lh, block_sector + sector)) {
log_very_verbose("%s: %s label detected at sector %llu",
dev_name(dev), li->name,
(unsigned long long)(sector + scan_sector));
(unsigned long long)(block_sector + sector));
if (found) {
log_error("Ignoring additional label on %s at sector %llu",
dev_name(dev),
(unsigned long long)(sector + scan_sector));
(unsigned long long)(block_sector + sector));
continue;
}
@ -309,7 +320,7 @@ static struct labeller *_find_lvm_header(struct device *dev,
memcpy(label_buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = sector + scan_sector;
*label_sector = block_sector + sector;
break;
}
}
@ -329,7 +340,9 @@ static struct labeller *_find_lvm_header(struct device *dev,
* are performed in the processing functions to get that data.
*/
static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
struct device *dev, struct block *bb, int *is_lvm_device)
struct device *dev, struct block *bb,
uint64_t block_sector, uint64_t start_sector,
int *is_lvm_device)
{
char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
struct label *label = NULL;
@ -345,7 +358,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
* data had been read (here). They set this flag to indicate that the
* filters should be retested now that data from the device is ready.
*/
if (cmd && (dev->flags & DEV_FILTER_AFTER_SCAN)) {
if (f && (dev->flags & DEV_FILTER_AFTER_SCAN)) {
dev->flags &= ~DEV_FILTER_AFTER_SCAN;
log_debug_devs("Scan filtering %s", dev_name(dev));
@ -374,7 +387,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
* FIXME: we don't need to copy one sector from bb->data into label_buf,
* we can just point label_buf at one sector in ld->buf.
*/
if (!(labeller = _find_lvm_header(dev, bb->data, label_buf, &sector, 0))) {
if (!(labeller = _find_lvm_header(dev, bb->data, BCACHE_BLOCK_SIZE_IN_SECTORS, label_buf, &sector, block_sector, start_sector))) {
/*
* Non-PVs exit here
@ -567,7 +580,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
} else {
log_debug_devs("Processing data from device %s fd %d block %p", dev_name(devl->dev), devl->dev->bcache_fd, bb);
ret = _process_block(cmd, f, devl->dev, bb, &is_lvm_device);
ret = _process_block(cmd, f, devl->dev, bb, 0, 0, &is_lvm_device);
if (!ret && is_lvm_device) {
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
@ -875,18 +888,58 @@ int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector
/*
* Read a label from a specfic, non-zero sector. This is used in only
* one place: pvck -> pv_analyze.
* one place: pvck/pv_analyze.
*/
int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector)
int label_read_sector(struct device *dev, uint64_t read_sector)
{
if (scan_sector) {
/* TODO: not yet implemented */
/* When is this done? When does it make sense? Is it actually possible? */
return 0;
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;
label_scan_open(dev);
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;
}
return label_read(dev, labelp, 0);
/*
* 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;
}
/*

View File

@ -110,7 +110,7 @@ void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv
void label_scan_drop(struct cmd_context *cmd);
void label_scan_destroy(struct cmd_context *cmd);
int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector);
int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector);
int label_read_sector(struct device *dev, uint64_t scan_sector);
void label_scan_confirm(struct device *dev);
int label_scan_setup_bcache(void);
int label_scan_open(struct device *dev);

View File

@ -25,17 +25,8 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
int i;
int ret_max = ECMD_PROCESSED;
/* FIXME: validate cmdline options */
/* FIXME: what does the cmdline look like? */
labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0));
if (labelsector) {
/* FIXME: see label_read_sector */
log_error("TODO: reading label from non-zero sector");
return ECMD_FAILED;
}
dm_list_init(&devs);
for (i = 0; i < argc; i++) {
@ -61,6 +52,25 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
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;