mirror of
git://sourceware.org/git/lvm2.git
synced 2025-03-10 16:58:47 +03:00
label_scan: remove extra label scan and read for orphan PVs
When process_each_pv() calls vg_read() on the orphan VG, the internal implementation was doing an unnecessary lvmcache_label_scan() and two unnecessary label_read() calls on each orphan. Some of those unnecessary label scans/reads would sometimes be skipped due to caching, but the code was always doing at least one unnecessary read on each orphan. The common format_text case was also unecessarily calling into the format-specific pv_read() function which actually did nothing. By analyzing each case in which vg_read() was being called on the orphan VG, we can say that all of the label scans/reads in vg_read_orphans are unnecessary: 1. reporting commands: the information saved in lvmcache by the original label scan can be reported. There is no advantage to repeating the label scan on the orphans a second time before reporting it. 2. pvcreate/vgcreate/vgextend: these all share a common implementation in pvcreate_each_device(). That function already rescans labels after acquiring the orphan VG lock, which ensures that the command is using valid lvmcache information.
This commit is contained in:
parent
5f138f3604
commit
79c4971210
51
lib/cache/lvmcache.c
vendored
51
lib/cache/lvmcache.c
vendored
@ -2454,56 +2454,29 @@ int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_insta
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_pv_if_in_vg(struct lvmcache_info *info,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
char vgname[NAME_LEN + 1];
|
||||
char vgid[ID_LEN + 1];
|
||||
|
||||
if (info->vginfo && info->vginfo->vgname &&
|
||||
!is_orphan_vg(info->vginfo->vgname)) {
|
||||
/*
|
||||
* get_pv_from_vg_by_id() may call
|
||||
* lvmcache_label_scan() and drop cached
|
||||
* vginfo so make a local copy of string.
|
||||
*/
|
||||
(void) dm_strncpy(vgname, info->vginfo->vgname, sizeof(vgname));
|
||||
memcpy(vgid, info->vginfo->vgid, sizeof(vgid));
|
||||
|
||||
if (get_pv_from_vg_by_id(info->fmt, vgname, vgid,
|
||||
info->dev->pvid, pv))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
|
||||
struct physical_volume *pv,
|
||||
int scan_label_only)
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct data_area_list *da;
|
||||
|
||||
/* Have we already cached vgname? */
|
||||
if (!scan_label_only && _get_pv_if_in_vg(info, pv))
|
||||
return 1;
|
||||
|
||||
/* Perform full scan (just the first time) and try again */
|
||||
if (!scan_label_only && !critical_section() && !full_scan_done()) {
|
||||
lvmcache_force_next_label_scan();
|
||||
lvmcache_label_scan(info->fmt->cmd);
|
||||
|
||||
if (_get_pv_if_in_vg(info, pv))
|
||||
return 1;
|
||||
|
||||
if (!info->label) {
|
||||
log_error("No cached label for orphan PV %s", pv_dev_name(pv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Orphan */
|
||||
pv->label_sector = info->label->sector;
|
||||
pv->dev = info->dev;
|
||||
pv->fmt = info->fmt;
|
||||
pv->size = info->device_size >> SECTOR_SHIFT;
|
||||
pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
|
||||
memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
|
||||
|
||||
if (!pv->size) {
|
||||
log_error("PV %s size is zero.", dev_name(info->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Currently only support exactly one data area */
|
||||
if (dm_list_size(&info->das) != 1) {
|
||||
log_error("Must be exactly one data area (found %d) on PV %s",
|
||||
|
4
lib/cache/lvmcache.h
vendored
4
lib/cache/lvmcache.h
vendored
@ -145,8 +145,8 @@ int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fi
|
||||
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
|
||||
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
|
||||
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
|
||||
struct physical_volume *pv,
|
||||
int scan_label_only);
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv);
|
||||
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
|
||||
void lvmcache_del_mdas(struct lvmcache_info *info);
|
||||
void lvmcache_del_das(struct lvmcache_info *info);
|
||||
|
@ -1593,36 +1593,6 @@ static uint64_t _metadata_locn_offset_raw(void *metadata_locn)
|
||||
return mdac->area.start;
|
||||
}
|
||||
|
||||
static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv, int scan_label_only)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
struct device *dev;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
|
||||
return_0;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
|
||||
if (!info && !lvmetad_pv_lookup_by_dev(fmt->cmd, dev, NULL))
|
||||
return 0;
|
||||
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
|
||||
} else {
|
||||
struct label *label;
|
||||
if (!(label_read(dev, &label, UINT64_C(0))))
|
||||
return_0;
|
||||
info = label->info;
|
||||
}
|
||||
|
||||
if (!info)
|
||||
return_0;
|
||||
|
||||
if (!lvmcache_populate_pv_fields(info, pv, scan_label_only))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _text_pv_initialise(const struct format_type *fmt,
|
||||
struct pv_create_args *pva,
|
||||
struct physical_volume *pv)
|
||||
@ -2471,7 +2441,6 @@ static struct format_instance *_text_create_text_instance(const struct format_ty
|
||||
|
||||
static struct format_handler _text_handler = {
|
||||
.scan = _text_scan,
|
||||
.pv_read = _text_pv_read,
|
||||
.pv_initialise = _text_pv_initialise,
|
||||
.pv_setup = _text_pv_setup,
|
||||
.pv_add_metadata_area = _text_pv_add_metadata_area,
|
||||
|
@ -38,10 +38,9 @@
|
||||
#include <sys/param.h>
|
||||
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
struct dm_pool *pvmem,
|
||||
const char *pv_name,
|
||||
struct format_instance *fid,
|
||||
uint32_t warn_flags, int scan_label_only);
|
||||
const struct format_type *fmt,
|
||||
struct volume_group *vg,
|
||||
struct lvmcache_info *info);
|
||||
|
||||
static int _alignment_overrides_default(unsigned long data_alignment,
|
||||
unsigned long default_pe_align)
|
||||
@ -330,37 +329,6 @@ bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pv_list *pvl;
|
||||
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
|
||||
int r = 0, consistent = 0;
|
||||
|
||||
if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, warn_flags, &consistent))) {
|
||||
log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(pvl, &vg->pvs) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
|
||||
if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) {
|
||||
log_error("internal PV duplication failed");
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
release_vg(vg);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
|
||||
const char *pv_name, int enforce_pv_from_source)
|
||||
{
|
||||
@ -3246,9 +3214,7 @@ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
|
||||
struct _vg_read_orphan_baton {
|
||||
struct cmd_context *cmd;
|
||||
struct volume_group *vg;
|
||||
uint32_t warn_flags;
|
||||
int consistent;
|
||||
int repair;
|
||||
const struct format_type *fmt;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3345,8 +3311,7 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
|
||||
uint32_t ext_version;
|
||||
uint32_t ext_flags;
|
||||
|
||||
if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
|
||||
b->vg->fid, b->warn_flags, 0))) {
|
||||
if (!(pv = _pv_read(b->cmd, b->fmt, b->vg, info))) {
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
@ -3453,10 +3418,22 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
||||
vg->free_count = 0;
|
||||
|
||||
baton.cmd = cmd;
|
||||
baton.warn_flags = warn_flags;
|
||||
baton.fmt = fmt;
|
||||
baton.vg = vg;
|
||||
baton.consistent = 1;
|
||||
baton.repair = *consistent;
|
||||
|
||||
/*
|
||||
* vg_read for a normal VG will rescan labels for all the devices
|
||||
* in the VG, in case something changed on disk between the initial
|
||||
* label scan and acquiring the VG lock. We don't rescan labels
|
||||
* here because this is only called in two ways:
|
||||
*
|
||||
* 1. for reporting, in which case it doesn't matter if something
|
||||
* changed between the label scan and printing the PVs here
|
||||
*
|
||||
* 2. pvcreate_each_device() for pvcreate//vgcreate/vgextend,
|
||||
* which already does the label rescan after taking the
|
||||
* orphan lock.
|
||||
*/
|
||||
|
||||
while ((pvl = (struct pv_list *) dm_list_first(&head.list))) {
|
||||
dm_list_del(&pvl->list);
|
||||
@ -3468,7 +3445,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
|
||||
if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton))
|
||||
return_NULL;
|
||||
|
||||
*consistent = baton.consistent;
|
||||
return vg;
|
||||
}
|
||||
|
||||
@ -4686,86 +4662,40 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
|
||||
return find_vgname_from_pvid(cmd, pvid);
|
||||
}
|
||||
|
||||
/* FIXME Use label functions instead of PV functions */
|
||||
static struct physical_volume *_pv_read(struct cmd_context *cmd,
|
||||
struct dm_pool *pvmem,
|
||||
const char *pv_name,
|
||||
struct format_instance *fid,
|
||||
uint32_t warn_flags, int scan_label_only)
|
||||
const struct format_type *fmt,
|
||||
struct volume_group *vg,
|
||||
struct lvmcache_info *info)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct device *dev;
|
||||
const struct format_type *fmt;
|
||||
int found;
|
||||
struct device *dev = lvmcache_device(info);
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter)))
|
||||
return_NULL;
|
||||
|
||||
if (lvmetad_used()) {
|
||||
info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
|
||||
if (!info) {
|
||||
if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
|
||||
return_NULL;
|
||||
if (!found) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No physical volume found in lvmetad cache for %s",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No cache info in lvmetad cache for %s.",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
label = lvmcache_get_label(info);
|
||||
} else {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (warn_flags & WARN_PV_READ)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
return NULL;
|
||||
}
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
}
|
||||
|
||||
fmt = lvmcache_fmt(info);
|
||||
|
||||
pv = _alloc_pv(pvmem, dev);
|
||||
if (!pv) {
|
||||
log_error("pv allocation for '%s' failed", pv_name);
|
||||
if (!(pv = _alloc_pv(vg->vgmem, NULL))) {
|
||||
log_error("pv allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pv->label_sector = label->sector;
|
||||
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
goto bad;
|
||||
if (fmt->ops->pv_read) {
|
||||
/* format1 and pool */
|
||||
if (!(fmt->ops->pv_read(fmt, dev_name(dev), pv, 0))) {
|
||||
log_error("Failed to read existing physical volume '%s'", dev_name(dev));
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
/* format text */
|
||||
if (!lvmcache_populate_pv_fields(info, vg, pv))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
if (!pv->size)
|
||||
goto bad;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(pvmem, pv))
|
||||
if (!alloc_pv_segment_whole_pv(vg->vgmem, pv))
|
||||
goto_bad;
|
||||
|
||||
if (fid)
|
||||
lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN);
|
||||
else {
|
||||
lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN);
|
||||
pv_set_fid(pv, fmt->orphan_vg->fid);
|
||||
}
|
||||
|
||||
lvmcache_fid_add_mdas(info, vg->fid, (const char *) &pv->id, ID_LEN);
|
||||
pv_set_fid(pv, vg->fid);
|
||||
return pv;
|
||||
bad:
|
||||
free_pv_fid(pv);
|
||||
dm_pool_free(pvmem, pv);
|
||||
dm_pool_free(vg->vgmem, pv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -371,12 +371,6 @@ uint32_t vg_bad_status_bits(const struct volume_group *vg, uint64_t status);
|
||||
int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
|
||||
struct physical_volume *pv, int new_pv);
|
||||
|
||||
|
||||
/* Find a PV within a given VG */
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *vgid, const char *pvid,
|
||||
struct physical_volume *pv);
|
||||
|
||||
struct logical_volume *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
const union lvid *lvid);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user