master - dev_cache: clean up scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=c0973e70a58e7e14e9c...
Commit: c0973e70a58e7e14e9cca29a0f8ad12719ea554f
Parent: 89c65d4f71e51c2db4fcba176546d2474e3451bd
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Apr 9 11:13:43 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
dev_cache: clean up scan
Pull out all of the twisted logic and simply call dev_cache_scan
at the start of the command prior to label scan.
---
daemons/clvmd/lvm-functions.c | 1 -
lib/cache/lvmcache.c | 5 +--
lib/commands/toolcontext.c | 1 -
lib/device/dev-cache.c | 40 ++++----------------------------------
lib/device/dev-cache.h | 6 +---
lib/filters/filter-persistent.c | 13 ------------
lib/label/label.c | 2 +-
lib/misc/lvm-globals.c | 11 ----------
lib/misc/lvm-globals.h | 2 -
tools/lvmcmdline.c | 1 -
tools/polldaemon.c | 9 +++----
tools/pvscan.c | 4 +-
tools/toollib.c | 2 -
tools/vgimportclone.c | 1 -
14 files changed, 16 insertions(+), 82 deletions(-)
diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
index 64bdab3..c278692 100644
--- a/daemons/clvmd/lvm-functions.c
+++ b/daemons/clvmd/lvm-functions.c
@@ -661,7 +661,6 @@ int do_refresh_cache(void)
return -1;
}
- init_full_scan_done(0);
init_ignore_suspended_devices(1);
lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 78665bf..ef180b9 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -157,6 +157,8 @@ void lvmcache_seed_infos_from_lvmetad(struct cmd_context *cmd)
if (!lvmetad_used() || _has_scanned)
return;
+ dev_cache_scan();
+
if (!lvmetad_pv_list_to_lvmcache(cmd)) {
stack;
return;
@@ -357,9 +359,6 @@ void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
_drop_metadata(FMT_LVM1_ORPHAN_VG_NAME, 0);
_drop_metadata(FMT_POOL_ORPHAN_VG_NAME, 0);
-
- /* Indicate that PVs could now be missing from the cache */
- init_full_scan_done(0);
} else
_drop_metadata(vgname, drop_precommitted);
}
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index 3dc3e2d..a54f4d7 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -1648,7 +1648,6 @@ static void _init_rand(struct cmd_context *cmd)
static void _init_globals(struct cmd_context *cmd)
{
- init_full_scan_done(0);
init_mirror_in_sync(0);
}
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index e72ffd6..52edad8 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -1077,12 +1077,11 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
-static void _full_scan(int dev_scan)
+void dev_cache_scan(void)
{
struct dir_list *dl;
- if (_cache.has_scanned && !dev_scan)
- return;
+ _cache.has_scanned = 1;
_insert_dirs(&_cache.dirs);
@@ -1090,9 +1089,6 @@ static void _full_scan(int dev_scan)
dm_list_iterate_items(dl, &_cache.files)
_insert_file(dl->dir);
-
- _cache.has_scanned = 1;
- init_full_scan_done(1);
}
int dev_cache_has_scanned(void)
@@ -1100,14 +1096,6 @@ int dev_cache_has_scanned(void)
return _cache.has_scanned;
}
-void dev_cache_scan(int do_scan)
-{
- if (!do_scan)
- _cache.has_scanned = 1;
- else
- _full_scan(1);
-}
-
static int _init_preferred_names(struct cmd_context *cmd)
{
const struct dm_config_node *cn;
@@ -1171,7 +1159,6 @@ out:
int dev_cache_init(struct cmd_context *cmd)
{
_cache.names = NULL;
- _cache.has_scanned = 0;
if (!(_cache.mem = dm_pool_create("dev_cache", 10 * 1024)))
return_0;
@@ -1413,7 +1400,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
_insert(name, info_available ? &buf : NULL, 0, obtain_device_list_from_udev());
d = (struct device *) dm_hash_lookup(_cache.names, name);
if (!d) {
- _full_scan(0);
+ dev_cache_scan();
d = (struct device *) dm_hash_lookup(_cache.names, name);
}
}
@@ -1469,7 +1456,7 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
}
}
- _full_scan(0);
+ dev_cache_scan();
d = _dev_cache_seek_devt(dev);
}
@@ -1477,17 +1464,7 @@ struct device *dev_cache_get_by_devt(dev_t dev, struct dev_filter *f)
f->passes_filter(f, d))) ? d : NULL;
}
-void dev_cache_full_scan(struct dev_filter *f)
-{
- if (f && f->wipe) {
- f->wipe(f); /* might call _full_scan(1) */
- if (!full_scan_done())
- _full_scan(1);
- } else
- _full_scan(1);
-}
-
-struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
+struct dev_iter *dev_iter_create(struct dev_filter *f, int unused)
{
struct dev_iter *di = dm_malloc(sizeof(*di));
@@ -1496,13 +1473,6 @@ struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
return NULL;
}
- if (dev_scan && !trust_cache()) {
- /* Flag gets reset between each command */
- if (!full_scan_done())
- dev_cache_full_scan(f);
- } else
- _full_scan(0);
-
di->current = btree_first(_cache.devices);
di->filter = f;
if (di->filter)
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 546b1fe..4797274 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -46,10 +46,8 @@ int dev_cache_exit(void);
*/
int dev_cache_check_for_open_devices(void);
-/* Trigger(1) or avoid(0) a scan */
-void dev_cache_scan(int do_scan);
+void dev_cache_scan(void);
int dev_cache_has_scanned(void);
-void dev_cache_full_scan(struct dev_filter *f);
int dev_cache_add_dir(const char *path);
int dev_cache_add_loopfile(const char *path);
@@ -66,7 +64,7 @@ void dev_set_preferred_name(struct dm_str_list *sl, struct device *dev);
* Object for iterating through the cache.
*/
struct dev_iter;
-struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
+struct dev_iter *dev_iter_create(struct dev_filter *f, int unused);
void dev_iter_destroy(struct dev_iter *iter);
struct device *dev_iter_get(struct dev_iter *iter);
diff --git a/lib/filters/filter-persistent.c b/lib/filters/filter-persistent.c
index 5bc0861..a4151c2 100644
--- a/lib/filters/filter-persistent.c
+++ b/lib/filters/filter-persistent.c
@@ -48,11 +48,7 @@ static void _persistent_filter_wipe(struct dev_filter *f)
{
struct pfilter *pf = (struct pfilter *) f->private;
- log_verbose("Wiping cache of LVM-capable devices");
dm_hash_wipe(pf->devices);
-
- /* Trigger complete device scan */
- dev_cache_scan(1);
}
static int _read_array(struct pfilter *pf, struct dm_config_tree *cft,
@@ -126,15 +122,6 @@ int persistent_filter_load(struct dev_filter *f, struct dm_config_tree **cft_out
/* _read_array(pf, cft, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE); */
- /* Did we find anything? */
- if (dm_hash_get_num_entries(pf->devices)) {
- /* We populated dev_cache ourselves */
- dev_cache_scan(0);
- if (!dev_cache_index_devs())
- stack;
- r = 1;
- }
-
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
diff --git a/lib/label/label.c b/lib/label/label.c
index 6c3be05..c11a040 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -631,7 +631,7 @@ int label_scan(struct cmd_context *cmd)
* on it. This info will be used by the vg_read() phase of the
* command.
*/
- dev_cache_full_scan(cmd->full_filter);
+ dev_cache_scan();
if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
log_error("Scanning failed to get devices.");
diff --git a/lib/misc/lvm-globals.c b/lib/misc/lvm-globals.c
index 0f384bb..9941489 100644
--- a/lib/misc/lvm-globals.c
+++ b/lib/misc/lvm-globals.c
@@ -28,7 +28,6 @@ static int _md_filtering = 0;
static int _internal_filtering = 0;
static int _fwraid_filtering = 0;
static int _pvmove = 0;
-static int _full_scan_done = 0; /* Restrict to one full scan during each cmd */
static int _obtain_device_list_from_udev = DEFAULT_OBTAIN_DEVICE_LIST_FROM_UDEV;
static enum dev_ext_e _external_device_info_source = DEV_EXT_NONE;
static int _trust_cache = 0; /* Don't scan when incomplete VGs encountered */
@@ -92,11 +91,6 @@ void init_pvmove(int level)
_pvmove = level;
}
-void init_full_scan_done(int level)
-{
- _full_scan_done = level;
-}
-
void init_obtain_device_list_from_udev(int device_list_from_udev)
{
_obtain_device_list_from_udev = device_list_from_udev;
@@ -253,11 +247,6 @@ int pvmove_mode(void)
return _pvmove;
}
-int full_scan_done(void)
-{
- return _full_scan_done;
-}
-
int obtain_device_list_from_udev(void)
{
return _obtain_device_list_from_udev;
diff --git a/lib/misc/lvm-globals.h b/lib/misc/lvm-globals.h
index e23d598..b383891 100644
--- a/lib/misc/lvm-globals.h
+++ b/lib/misc/lvm-globals.h
@@ -29,7 +29,6 @@ void init_md_filtering(int level);
void init_internal_filtering(int level);
void init_fwraid_filtering(int level);
void init_pvmove(int level);
-void init_full_scan_done(int level);
void init_external_device_info_source(enum dev_ext_e src);
void init_obtain_device_list_from_udev(int device_list_from_udev);
void init_trust_cache(int trustcache);
@@ -63,7 +62,6 @@ int md_filtering(void);
int internal_filtering(void);
int fwraid_filtering(void);
int pvmove_mode(void);
-int full_scan_done(void);
int obtain_device_list_from_udev(void);
enum dev_ext_e external_device_info_source(void);
int trust_cache(void);
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index bcb2c53..c7ac4b6 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2446,7 +2446,6 @@ static void _apply_current_settings(struct cmd_context *cmd)
_apply_current_output_settings(cmd);
init_test(cmd->current_settings.test);
- init_full_scan_done(0);
init_mirror_in_sync(0);
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
index d69284d..cf7a947 100644
--- a/tools/polldaemon.c
+++ b/tools/polldaemon.c
@@ -123,13 +123,12 @@ static void _nanosleep(unsigned secs, unsigned allow_zero_time)
while (!nanosleep(&wtime, &wtime) && errno == EINTR) {}
}
-static void _sleep_and_rescan_devices(struct daemon_parms *parms)
+static void _sleep_and_rescan_devices(struct cmd_context *cmd, struct daemon_parms *parms)
{
if (parms->interval && !parms->aborting) {
dev_close_all();
_nanosleep(parms->interval, 1);
- /* Devices might have changed while we slept */
- init_full_scan_done(0);
+ lvmcache_label_scan(cmd);
}
}
@@ -145,7 +144,7 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
/* Poll for completion */
while (!finished) {
if (parms->wait_before_testing)
- _sleep_and_rescan_devices(parms);
+ _sleep_and_rescan_devices(cmd, parms);
/*
* An ex VG lock is needed because the check can call finish_copy
@@ -218,7 +217,7 @@ int wait_for_single_lv(struct cmd_context *cmd, struct poll_operation_id *id,
* continue polling an LV that doesn't have a "status".
*/
if (!parms->wait_before_testing && !finished)
- _sleep_and_rescan_devices(parms);
+ _sleep_and_rescan_devices(cmd, parms);
}
return 1;
diff --git a/tools/pvscan.c b/tools/pvscan.c
index ab6ea0b..1fcf606 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -288,8 +288,6 @@ static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params
pp->refresh_all = 1;
}
- dev_cache_full_scan(cmd->full_filter);
-
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, 0, 0, handle, _pvscan_autoactivate_single);
destroy_processing_handle(cmd, handle);
@@ -495,6 +493,7 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
if (!dm_list_empty(&single_devs)) {
+ dev_cache_scan();
label_scan_devs(cmd, &single_devs);
dm_list_iterate_items(devl, &single_devs) {
@@ -540,6 +539,7 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
if (!dm_list_empty(&single_devs)) {
+ dev_cache_scan();
label_scan_devs(cmd, &single_devs);
dm_list_iterate_items(devl, &single_devs) {
diff --git a/tools/toollib.c b/tools/toollib.c
index 7e3b021..fabf2dc 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -5503,8 +5503,6 @@ int pvcreate_each_device(struct cmd_context *cmd,
return 0;
}
- dev_cache_full_scan(cmd->full_filter);
-
lvmcache_label_scan(cmd);
/*
diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c
index 146d3b4..224d0b5 100644
--- a/tools/vgimportclone.c
+++ b/tools/vgimportclone.c
@@ -332,7 +332,6 @@ retry_name:
dm_list_iterate_items(vd, &vp.arg_import)
internal_filter_allow(cmd->mem, vd->dev);
lvmcache_destroy(cmd, 1, 0);
- dev_cache_full_scan(cmd->full_filter);
log_debug("Changing VG %s to %s.", vp.old_vgname, vp.new_vgname);
6 years
master - label_scan: fix independent metadata areas
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d9ef9eb330bdc66dd6d...
Commit: d9ef9eb330bdc66dd6d9b45713d5c0b25d645ac0
Parent: 748f29b42a61e05fb696a86e04b4b589d70d6d79
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Oct 25 13:39:46 2017 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:41 2018 -0500
label_scan: fix independent metadata areas
This fixes the use of lvmcache_label_rescan_vg() in the previous
commit for the special case of independent metadata areas.
label scan is about discovering VG name to device associations
using information from disks, but devices in VGs with
independent metadata areas have no information on disk, so
the label scan does nothing for these VGs/devices.
With independent metadata areas, only the VG metadata found
in files is used. This metadata is found and read in
vg_read in the processing phase.
lvmcache_label_rescan_vg() drops lvmcache info for the VG devices
before repeating the label scan on them. In the case of
independent metadata areas, there is no metadata on devices, so the
label scan of the devices will find nothing, so will not recreate
the necessary vginfo/info data in lvmcache for the VG. Fix this
by setting a flag in the lvmcache vginfo struct indicating that
the VG uses independent metadata areas, and label rescanning should
be skipped.
In the case of independent metadata areas, it is the metadata
processing in the vg_read phase that sets up the lvmcache
vginfo/info information, and label scan has no role.
---
lib/format_text/format-text.c | 24 +++++++++++++++++++++++-
1 files changed, 23 insertions(+), 1 deletions(-)
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 6c13346..8c12c82 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1141,6 +1141,9 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
dir_list = &((struct mda_lists *) fmt->private)->dirs;
+ if (!dm_list_empty(dir_list))
+ log_debug_metadata("Scanning independent files for %s", vgname ? vgname : "VGs");
+
dm_list_iterate_items(dl, dir_list) {
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
@@ -1173,10 +1176,14 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
stack;
break;
}
+
+ log_debug_metadata("Scanning independent file %s for VG %s", path, scanned_vgname);
+
if ((vg = _vg_read_file_name(fid, scanned_vgname,
path))) {
/* FIXME Store creation host in vg */
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
release_vg(vg);
}
}
@@ -1302,6 +1309,8 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 1;
}
+/* used for independent_metadata_areas */
+
static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused)))
{
struct raw_list *rl;
@@ -1313,11 +1322,16 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
raw_list = &((struct mda_lists *) fmt->private)->raws;
+ if (!dm_list_empty(raw_list))
+ log_debug_metadata("Scanning independent raw locations for %s", vgname ? vgname : "VGs");
+
fid.fmt = fmt;
dm_list_init(&fid.metadata_areas_in_use);
dm_list_init(&fid.metadata_areas_ignored);
dm_list_iterate_items(rl, raw_list) {
+ log_debug_metadata("Scanning independent dev %s", dev_name(rl->dev_area.dev));
+
/* FIXME We're reading mdah twice here... */
if (!dev_open_readonly(rl->dev_area.dev)) {
stack;
@@ -1331,8 +1345,10 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0, 0);
- if (vg)
+ if (vg) {
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
+ }
}
close_dev:
if (!dev_close(rl->dev_area.dev))
@@ -1342,6 +1358,8 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
return 1;
}
+/* used for independent_metadata_areas */
+
static int _text_scan(const struct format_type *fmt, const char *vgname)
{
return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname));
@@ -1796,6 +1814,8 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
.mda_import_text = _mda_import_text_raw
};
+/* used only for sending info to lvmetad */
+
static int _mda_export_text_raw(struct metadata_area *mda,
struct dm_config_tree *cft,
struct dm_config_node *parent)
@@ -1820,6 +1840,8 @@ static int _mda_export_text_raw(struct metadata_area *mda,
NULL) ? 1 : 0;
}
+/* used only for receiving info from lvmetad */
+
static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn)
{
struct device *device;
6 years
master - remove unnecessary REQUIRES_FULL_LABEL_SCAN
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=89c65d4f71e51c2db4f...
Commit: 89c65d4f71e51c2db4fcba176546d2474e3451bd
Parent: 45e5e702c1d488df4898a41db0c00ead63c5f6ee
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 6 13:18:03 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
remove unnecessary REQUIRES_FULL_LABEL_SCAN
we always scan all devices
---
tools/command.c | 3 +--
tools/commands.h | 2 +-
tools/lvmcmdline.c | 7 +------
tools/tools.h | 7 ++-----
tools/vgrename.c | 5 -----
5 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/tools/command.c b/tools/command.c
index 8944399..f3b5d82 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -134,13 +134,12 @@ static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused))
#define ALLOW_UUID_AS_NAME 0x00000010
#define LOCKD_VG_SH 0x00000020
#define NO_METADATA_PROCESSING 0x00000040
-#define REQUIRES_FULL_LABEL_SCAN 0x00000080
+#define IGNORE_PERSISTENT_FILTER 0x00000080
#define MUST_USE_ALL_ARGS 0x00000100
#define NO_LVMETAD_AUTOSCAN 0x00000200
#define ENABLE_DUPLICATE_DEVS 0x00000400
#define DISALLOW_TAG_ARGS 0x00000800
#define GET_VGNAME_FROM_OPTIONS 0x00001000
-#define IGNORE_PERSISTENT_FILTER 0x00002000
/* create foo_CMD enums for command def ID's in command-lines.in */
diff --git a/tools/commands.h b/tools/commands.h
index cbd527b..3d142c3 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -225,7 +225,7 @@ xx(vgremove,
xx(vgrename,
"Rename a volume group",
- ALLOW_UUID_AS_NAME | REQUIRES_FULL_LABEL_SCAN)
+ ALLOW_UUID_AS_NAME)
xx(vgs,
"Display information about volume groups",
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 3774014..bcb2c53 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -2727,11 +2727,6 @@ static int _cmd_no_lvmetad_autoscan(struct cmd_context *cmd)
return cmd->cname->flags & NO_LVMETAD_AUTOSCAN;
}
-static int _cmd_requires_full_label_scan(struct cmd_context *cmd)
-{
- return cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN;
-}
-
static int _cmd_ignores_persistent_filter(struct cmd_context *cmd)
{
return cmd->cname->flags & IGNORE_PERSISTENT_FILTER;
@@ -2865,7 +2860,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
* Similarly ignore the persistent cache if the command is going to discard it regardless.
*/
if (!cmd->initialized.filters && !_cmd_no_meta_proc(cmd) &&
- !init_filters(cmd, !(refresh_done || _cmd_requires_full_label_scan(cmd) || _cmd_ignores_persistent_filter(cmd))))
+ !init_filters(cmd, !(refresh_done || _cmd_ignores_persistent_filter(cmd))))
return_ECMD_FAILED;
if (arg_is_set(cmd, readonly_ARG))
diff --git a/tools/tools.h b/tools/tools.h
index 0886551..d4d2fb2 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -124,8 +124,8 @@ struct arg_value_group_list {
#define LOCKD_VG_SH 0x00000020
/* Command does not process any metadata. */
#define NO_METADATA_PROCESSING 0x00000040
-/* Command wants to scan for new devices and force labels to be read from them all. */
-#define REQUIRES_FULL_LABEL_SCAN 0x00000080
+/* Command must not load the contents saved by the persistent filter */
+#define IGNORE_PERSISTENT_FILTER 0x00000080
/* Command must use all specified arg names and fail if all cannot be used. */
#define MUST_USE_ALL_ARGS 0x00000100
/* Command wants to control the device scan for lvmetad itself. */
@@ -136,9 +136,6 @@ struct arg_value_group_list {
#define DISALLOW_TAG_ARGS 0x00000800
/* Command may need to find VG name in an option value. */
#define GET_VGNAME_FROM_OPTIONS 0x00001000
-/* Command must not load the contents saved by the persistent filter */
-#define IGNORE_PERSISTENT_FILTER 0x00002000
-
void usage(const char *name);
/* the argument verify/normalise functions */
diff --git a/tools/vgrename.c b/tools/vgrename.c
index 5c69faf..4f2a08b 100644
--- a/tools/vgrename.c
+++ b/tools/vgrename.c
@@ -59,11 +59,6 @@ static int _vgrename_single(struct cmd_context *cmd, const char *vg_name,
/*
* Check if a VG already exists with the new VG name.
*
- * When not using lvmetad, it's essential that a full scan has
- * been done to ensure we see all existing VG names, so we
- * do not use an existing name. This has been done by
- * process_each_vg REQUIRES_FULL_LABEL_SCAN.
- *
* (FIXME: We could look for the new name in the list of all
* VGs that process_each_vg created, but we don't have access
* to that list here, so we have to look in lvmcache.
6 years
master - scan: do scanning at the start of a command
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=748f29b42a61e05fb69...
Commit: 748f29b42a61e05fb696a86e04b4b589d70d6d79
Parent: 4507ba3596a549697733e1b839f25af454ccf878
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 7 13:26:37 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:38 2018 -0500
scan: do scanning at the start of a command
Move the location of scans to make it clearer and avoid
unnecessary repeated scanning. There should be one scan
at the start of a command which is then used through the
rest of command processing.
Previously, the initial label scan was called as a side effect
from various utility functions. This would lead to it being called
unnecessarily. It is an expensive operation, and should only be
called when necessary. Also, this is a primary step in the
function of the command, and as such it should be called prominently
at the top level of command processing, not as a hidden side effect
of a utility function. lvm knows exactly where and when the
label scan needs to be done. Because of this, move the label scan
calls from the internal functions to the top level of processing.
Other specific instances of lvmcache_label_scan() are still called
unnecessarily or unclearly by specific commands that do not use
the common process_each functions. These will be improved in
future commits.
During the processing phase, rescanning labels for devices in a VG
needs to be done after the VG lock is acquired in case things have
changed since the initial label scan. This was being done by way
of rescanning devices that had the INVALID flag set in lvmcache.
This usually approximated the right set of devices, but it was not
exact, and obfuscated the real requirement. Correct this by using
a new function that rescans the devices in the VG:
lvmcache_label_rescan_vg().
Apart from being inexact, the rescanning was extremely well hidden.
_vg_read() would call ->create_instance(), _text_create_text_instance(),
_create_vg_text_instance() which would call lvmcache_label_scan()
which would call _scan_invalid() which repeats the label scan on
devices flagged INVALID. lvmcache_label_rescan_vg() is now called
prominently by _vg_read() directly.
---
lib/cache/lvmcache.c | 2 -
lib/format_text/format-text.c | 16 ----------
lib/metadata/metadata.c | 62 +++++++++++++++++++++++++++++++++--------
tools/toollib.c | 27 ++++++++++++-----
tools/vgcfgrestore.c | 2 +
5 files changed, 71 insertions(+), 38 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index c0b2202..47058cc 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1436,8 +1436,6 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct vgnameid_list *vgnl;
struct lvmcache_vginfo *vginfo;
- lvmcache_label_scan(cmd);
-
dm_list_iterate_items(vginfo, &_vginfos) {
if (!include_internal && is_orphan_vg(vginfo->vgname))
continue;
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index c438b2d..6c13346 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -2049,22 +2049,6 @@ static int _create_vg_text_instance(struct format_instance *fid,
}
if (type & FMT_INSTANCE_MDAS) {
- /*
- * TODO in theory, this function should be never reached
- * while in critical_section(), because lvmcache's
- * cached_vg should be valid. However, this assumption
- * sometimes fails (possibly due to inconsistent
- * (precommit) metadata and/or missing devices), and
- * calling lvmcache_label_scan inside the critical
- * section may be fatal (i.e. deadlock).
- */
- if (!critical_section())
- /* Scan PVs in VG for any further MDAs */
- /*
- * FIXME Only scan PVs believed to be in the VG.
- */
- lvmcache_label_scan(fid->fmt->cmd);
-
if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id)))
goto_out;
if (!lvmcache_fid_add_mdas_vg(vginfo, fid))
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 00b7737..b4ee204 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3859,20 +3859,28 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
correct_vg = NULL;
}
+ /*
+ * Rescan the devices that are associated with this vg in lvmcache.
+ * This repeats what was done by the command's initial label scan,
+ * but only the devices associated with this VG.
+ *
+ * The lvmcache info about these devs is from the initial label scan
+ * performed by the command before the vg lock was held. Now the VG
+ * lock is held, so we rescan all the info from the devs in case
+ * something changed between the initial scan and now that the lock
+ * is held.
+ */
+ log_debug_metadata("Reading VG rereading labels for %s", vgname);
- /* Find the vgname in the cache */
- /* If it's not there we must do full scan to be completely sure */
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
+ if (!lvmcache_label_rescan_vg(cmd, vgname, vgid)) {
+ /* The VG wasn't found, so force a full label scan. */
+ lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
- /* Independent MDAs aren't supported under low memory */
- if (!cmd->independent_metadata_areas && prioritized_section())
- return_NULL;
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
- return_NULL;
- }
+ }
+
+ if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) {
+ log_debug_metadata("Cache did not find fmt for vgname %s", vgname);
+ return_NULL;
}
/* Now determine the correct vgname if none was supplied */
@@ -3890,6 +3898,36 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
use_precommitted = 0;
+ /*
+ * A "format instance" is an abstraction for a VG location,
+ * i.e. where a VG's metadata exists on disk.
+ *
+ * An fic (format_instance_ctx) is a temporary struct used
+ * to create an fid (format_instance). The fid hangs around
+ * and is used to create a 'vg' to which it connected (vg->fid).
+ *
+ * The 'fic' describes a VG in terms of fmt/name/id.
+ *
+ * The 'fid' describes a VG in more detail than the fic,
+ * holding information about where to find the VG metadata.
+ *
+ * The 'vg' describes the VG in the most detail representing
+ * all the VG metadata.
+ *
+ * The fic and fid are set up by create_instance() to describe
+ * the VG location. This happens before the VG metadata is
+ * assembled into the more familiar struct volume_group "vg".
+ *
+ * The fid has one main purpose: to keep track of the metadata
+ * locations for a given VG. It does this by putting 'mda'
+ * structs on fid->metadata_areas_in_use, which specify where
+ * metadata is located on disk. It gets this information
+ * (metadata locations for a specific VG) from the command's
+ * initial label scan. The info is passed indirectly via
+ * lvmcache info/vginfo structs, which are created by the
+ * label scan and then copied into fid by create_instance().
+ */
+
/* create format instance with appropriate metadata area */
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vgname;
diff --git a/tools/toollib.c b/tools/toollib.c
index 451f24d..1c216d8 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2228,14 +2228,10 @@ int process_each_vg(struct cmd_context *cmd,
}
/*
- * First rescan for available devices, then force the next
- * label scan to be done. get_vgnameids() will scan labels
- * (when not using lvmetad).
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
*/
- if (cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN) {
- dev_cache_full_scan(cmd->full_filter);
- lvmcache_force_next_label_scan();
- }
+ lvmcache_label_scan(cmd);
/*
* A list of all VGs on the system is needed when:
@@ -3745,6 +3741,12 @@ int process_each_lv(struct cmd_context *cmd,
}
/*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
+
+ /*
* A list of all VGs on the system is needed when:
* . processing all VGs on the system
* . A VG name is specified which may refer to one
@@ -4453,7 +4455,12 @@ int process_each_pv(struct cmd_context *cmd,
if (!trust_cache() && !orphans_locked) {
log_debug("Scanning for available devices");
lvmcache_destroy(cmd, 1, 0);
- dev_cache_full_scan(cmd->full_filter);
+
+ /*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
}
if (!get_vgnameids(cmd, &all_vgnameids, only_this_vgname, 1)) {
@@ -5467,6 +5474,8 @@ int pvcreate_each_device(struct cmd_context *cmd,
dev_cache_full_scan(cmd->full_filter);
+ lvmcache_label_scan(cmd);
+
/*
* Translate arg names into struct device's.
*/
@@ -5621,6 +5630,8 @@ int pvcreate_each_device(struct cmd_context *cmd,
goto out;
}
+ lvmcache_label_scan(cmd);
+
/*
* The device args began on the arg_devices list, then the first check
* loop moved those entries to arg_process as they were found. Devices
diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c
index b5a2add..e9f1a4c 100644
--- a/tools/vgcfgrestore.c
+++ b/tools/vgcfgrestore.c
@@ -74,6 +74,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ lvmcache_label_scan(cmd);
+
cmd->handles_unknown_segments = 1;
if (!(arg_is_set(cmd, file_ARG) ?
6 years
master - scan: use new label_scan for lvmcache_label_scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4507ba3596a54969773...
Commit: 4507ba3596a549697733e1b839f25af454ccf878
Parent: a7cb76ae94a90c89b86a810ceb4b6a91bab3441e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 7 13:14:08 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:19:32 2018 -0500
scan: use new label_scan for lvmcache_label_scan
To do label scanning, lvm code calls lvmcache_label_scan().
Change lvmcache_label_scan() to use the new label_scan()
based on bcache.
Also add lvmcache_label_rescan_vg() which calls the new
label_scan_devs() which does label scanning on only the
specified devices. This is for a subsequent commit and
is not yet used.
---
lib/cache/lvmcache.c | 234 ++++++++++++++++++++++++++++------------
lib/cache/lvmcache.h | 12 ++-
lib/format_text/format-text.c | 2 +-
lib/format_text/import_vsn1.c | 3 +-
lib/metadata/metadata-liblvm.c | 2 +-
5 files changed, 174 insertions(+), 79 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index fb81002..c0b2202 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -72,6 +72,7 @@ struct lvmcache_vginfo {
unsigned vg_use_count; /* Counter of vg reusage */
unsigned precommitted; /* Is vgmetadata live or precommitted? */
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
+ int independent_metadata_location; /* metadata read from independent areas */
};
static struct dm_hash_table *_pvid_hash = NULL;
@@ -542,7 +543,6 @@ const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
{
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
- struct label *label;
struct dm_list *devh, *tmp;
struct dm_list devs;
struct device_list *devl;
@@ -587,7 +587,7 @@ const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
dm_list_iterate_safe(devh, tmp, &devs) {
devl = dm_list_item(devh, struct device_list);
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
dm_list_del(&devl->list);
dm_free(devl);
}
@@ -750,7 +750,7 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
struct lvmcache_info *info;
char *vgname;
- if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) {
+ if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL)) {
log_error("Couldn't find device with uuid %s.", pvid);
return NULL;
}
@@ -766,19 +766,42 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
return vgname;
}
-static void _rescan_entry(struct lvmcache_info *info)
+/*
+ * FIXME: get rid of the CACHE_INVALID state and rescanning
+ * infos with that flag. The code should just know which devices
+ * need scanning and when.
+ */
+static int _label_scan_invalid(struct cmd_context *cmd)
{
- struct label *label;
+ struct dm_list devs;
+ struct dm_hash_node *n;
+ struct device_list *devl;
+ struct lvmcache_info *info;
+ int dev_count = 0;
+ int ret;
- if (info->status & CACHE_INVALID)
- (void) label_read(info->dev, &label, UINT64_C(0));
-}
+ dm_list_init(&devs);
-static int _scan_invalid(void)
-{
- dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
+ dm_hash_iterate(n, _pvid_hash) {
+ if (!(info = dm_hash_get_data(_pvid_hash, n)))
+ continue;
- return 1;
+ if (!(info->status & CACHE_INVALID))
+ continue;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ dev_count++;
+ }
+
+ log_debug_cache("Scanning %d devs with invalid info.", dev_count);
+
+ ret = label_scan_devs(cmd, &devs);
+
+ return ret;
}
/*
@@ -1093,17 +1116,89 @@ next:
goto next;
}
+/*
+ * The initial label_scan at the start of the command is done without
+ * holding VG locks. Then for each VG identified during the label_scan,
+ * vg_read(vgname) is called while holding the VG lock. The labels
+ * and metadata on this VG's devices could have changed between the
+ * initial unlocked label_scan and the current vg_read(). So, we reread
+ * the labels/metadata for each device in the VG now that we hold the
+ * lock, and use this for processing the VG.
+ *
+ * FIXME: In some cases, the data read by label_scan may be fine, and not
+ * need to be reread here. e.g. a reporting command, possibly with a
+ * special option, could skip this second reread. Or, we could look
+ * at the VG seqno in each copy of the metadata read in the first label
+ * scan, and if they all match, consider it good enough to use for
+ * reporting without rereading it. (A command modifying the VG would
+ * always want to reread while the lock is held before modifying.)
+ *
+ * A label scan is ultimately creating associations between devices
+ * and VGs so that when vg_read wants to get VG metadata, it knows
+ * which devices to read. In the special case where VG metadata is
+ * stored in files on the file system (configured in lvm.conf), the
+ * vginfo->independent_metadata_location flag is set during label scan.
+ * When we get here to rescan, we are revalidating the device to VG
+ * mapping from label scan by repeating the label scan on a subset of
+ * devices. If we see independent_metadata_location is set from the
+ * initial label scan, we know that there is nothing to do because
+ * there is no device to VG mapping to revalidate, since the VG metadata
+ * comes directly from files.
+ */
+
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct dm_list devs;
+ struct device_list *devl;
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info;
+
+ if (lvmetad_used())
+ return 1;
+
+ dm_list_init(&devs);
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+ return_0;
+
+ /*
+ * When the VG metadata is from an independent location,
+ * then rescanning the devices in the VG won't find the
+ * metadata, and will destroy the vginfo/info associations
+ * that were created during label scan when the
+ * independent locations were read.
+ */
+ if (vginfo->independent_metadata_location)
+ return 1;
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_malloc(sizeof(*devl)))) {
+ log_error("device_list element allocation failed");
+ return 0;
+ }
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ }
+
+ label_scan_devs(cmd, &devs);
+
+ /*
+ * TODO: grab vginfo again, and compare vginfo->infos
+ * to what was found above before rereading labels.
+ * If there are any info->devs now that were not in the
+ * first devs list, then do label_read on those also.
+ */
+
+ return 1;
+}
+
int lvmcache_label_scan(struct cmd_context *cmd)
{
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct lvmcache_info *info;
struct device_list *devl;
- struct label *label;
- struct dev_iter *iter;
- struct device *dev;
struct format_type *fmt;
- int dev_count = 0;
int r = 0;
@@ -1121,34 +1216,40 @@ int lvmcache_label_scan(struct cmd_context *cmd)
goto out;
}
+ /*
+ * Scan devices whose info struct has the INVALID flag set.
+ * When scanning has read the pv_header, mda_header and
+ * mda locations, it will clear the INVALID flag (via
+ * lvmcache_make_valid).
+ */
if (_has_scanned && !_force_label_scan) {
- r = _scan_invalid();
+ r = _label_scan_invalid(cmd);
goto out;
}
if (_force_label_scan && (cmd->full_filter && !cmd->full_filter->use_count) && !refresh_filters(cmd))
goto_out;
- if (!cmd->full_filter || !(iter = dev_iter_create(cmd->full_filter, _force_label_scan))) {
- log_error("dev_iter creation failed");
+ if (!cmd->full_filter) {
+ log_error("label scan is missing full filter");
goto out;
}
- log_very_verbose("Scanning device labels");
-
/*
* Duplicates found during this label scan are added to _found_duplicate_devs().
*/
_destroy_duplicate_device_list(&_found_duplicate_devs);
- while ((dev = dev_iter_get(iter))) {
- (void) label_read(dev, &label, UINT64_C(0));
- dev_count++;
- }
-
- dev_iter_destroy(iter);
-
- log_very_verbose("Scanned %d device labels", dev_count);
+ /*
+ * Do the actual scanning. This populates lvmcache
+ * with infos/vginfos based on reading headers from
+ * each device, and a vg summary from each mda.
+ *
+ * Note that this will *skip* scanning a device if
+ * an info struct already exists in lvmcache for
+ * the device.
+ */
+ label_scan(cmd);
/*
* _choose_preferred_devs() returns:
@@ -1182,7 +1283,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_iterate_items(devl, &add_cache_devs) {
log_debug_cache("Rescan preferred device %s for lvmcache", dev_name(devl->dev));
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
}
dm_list_splice(&_unused_duplicate_devs, &del_cache_devs);
@@ -1441,61 +1542,45 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
return pvids;
}
-static struct device *_device_from_pvid(const struct id *pvid,
- uint64_t *label_sector)
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs)
{
struct lvmcache_info *info;
- struct label *label;
+ struct device_list *devl;
- if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
- if (lvmetad_used()) {
- if (info->label && label_sector)
- *label_sector = info->label->sector;
- return info->dev;
- }
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
- if (label_read(info->dev, &label, UINT64_C(0))) {
- info = (struct lvmcache_info *) label->info;
- if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
- if (label_sector)
- *label_sector = label->sector;
- return info->dev;
- }
- }
+ devl->dev = info->dev;
+ dm_list_add(devs, &devl->list);
}
- return NULL;
+ return 1;
}
-struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
- unsigned *scan_done_once, uint64_t *label_sector)
+static struct device *_device_from_pvid(const struct id *pvid, uint64_t *label_sector)
{
- struct device *dev;
-
- /* Already cached ? */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
-
- lvmcache_label_scan(cmd);
+ struct lvmcache_info *info;
- /* Try again */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
+ if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
+ if (info->label && label_sector)
+ *label_sector = info->label->sector;
+ return info->dev;
+ }
- if (critical_section() || (scan_done_once && *scan_done_once))
- return NULL;
+ return NULL;
+}
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (scan_done_once)
- *scan_done_once = 1;
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector)
+{
+ struct device *dev;
- /* Try again */
dev = _device_from_pvid(pvid, label_sector);
if (dev)
return dev;
+ log_debug_devs("No device with uuid %s.", (const char *)pvid);
return NULL;
}
@@ -1503,7 +1588,6 @@ const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
const char *devname)
{
struct device *dev;
- struct label *label;
if (!(dev = dev_cache_get(devname, cmd->filter))) {
log_error("%s: Couldn't find device. Check your filters?",
@@ -1511,7 +1595,7 @@ const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
return NULL;
}
- if (!(label_read(dev, &label, UINT64_C(0))))
+ if (!(label_read(dev, NULL, UINT64_C(0))))
return NULL;
return dev->pvid;
@@ -2657,6 +2741,14 @@ int lvmcache_vgid_is_cached(const char *vgid) {
return 1;
}
+void lvmcache_set_independent_location(const char *vgname)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if ((vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ vginfo->independent_metadata_location = 1;
+}
+
/*
* Return true iff it is impossible to find out from this info alone whether the
* PV in question is or is not an orphan.
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 847c208..826e91e 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -74,6 +74,7 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
*/
void lvmcache_force_next_label_scan(void);
int lvmcache_label_scan(struct cmd_context *cmd);
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
@@ -105,10 +106,8 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
-struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
- unsigned *scan_done_once, uint64_t *label_sector);
-const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
- const char *devname);
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
+const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
@@ -215,4 +214,9 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs);
+void lvmcache_set_independent_location(const char *vgname);
+
#endif
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index e9a34e6..c438b2d 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -2534,7 +2534,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
return 0;
}
- if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL, NULL))) {
+ if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&id, buffer, sizeof(buffer)))
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index d51397a..b41d83c 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -216,8 +216,7 @@ static int _read_pv(struct format_instance *fid,
/*
* Convert the uuid into a device.
*/
- if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once,
- &pv->label_sector))) {
+ if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, &pv->label_sector))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
diff --git a/lib/metadata/metadata-liblvm.c b/lib/metadata/metadata-liblvm.c
index a4284bc..388e8d9 100644
--- a/lib/metadata/metadata-liblvm.c
+++ b/lib/metadata/metadata-liblvm.c
@@ -314,7 +314,7 @@ struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_nam
}
if (pp->pva.idp) {
- if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL, NULL)) &&
+ if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL)) &&
(dev != dev_cache_get(pv_name, cmd->full_filter))) {
if (!id_write_format((const struct id*)&pp->pva.idp->uuid,
buffer, sizeof(buffer)))
6 years
master - scan: use bcache for label scan and vg read
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a7cb76ae94a90c89b86...
Commit: a7cb76ae94a90c89b86a810ceb4b6a91bab3441e
Parent: 697fa7aa1dbcc2ed8e141d9d13118cb38d609161
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 6 15:18:11 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:19:24 2018 -0500
scan: use bcache for label scan and vg read
New label_scan function populates bcache for each device
on the system.
The two read paths are updated to get data from bcache.
The bcache is not yet used for writing. bcache blocks
for a device are invalidated when the device is written.
---
lib/commands/toolcontext.c | 2 +
lib/config/config.c | 10 +-
lib/device/bcache.c | 6 +-
lib/device/device.h | 1 +
lib/format_text/archive.c | 2 +-
lib/format_text/archiver.c | 2 +-
lib/format_text/format-text.c | 217 ++++++++------
lib/format_text/import-export.h | 8 +-
lib/format_text/import.c | 70 ++++--
lib/format_text/import_vsn1.c | 51 +---
lib/format_text/layout.h | 2 +-
lib/format_text/text_label.c | 15 +-
lib/label/label.c | 583 +++++++++++++++++++++++++++++---------
lib/label/label.h | 15 +-
lib/metadata/metadata-exported.h | 13 +
lib/metadata/metadata.c | 12 +-
lib/metadata/metadata.h | 8 +-
17 files changed, 713 insertions(+), 304 deletions(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index c998495..fe6b8a3 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -2124,6 +2124,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
activation_release();
lvmcache_destroy(cmd, 0, 0);
+ label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
@@ -2243,6 +2244,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
archive_exit(cmd);
backup_exit(cmd);
lvmcache_destroy(cmd, 0, 0);
+ label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
diff --git a/lib/config/config.c b/lib/config/config.c
index 8fca372..2d7db69 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -23,6 +23,7 @@
#include "toolcontext.h"
#include "lvm-file.h"
#include "memlock.h"
+#include "label.h"
#include <sys/stat.h>
#include <sys/mman.h>
@@ -532,10 +533,15 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
log_error("Failed to allocate circular buffer.");
return 0;
}
- if (!dev_read_circular(dev, (uint64_t) offset, size,
- (uint64_t) offset2, size2, reason, buf)) {
+
+ if (!bcache_read_bytes(scan_bcache, dev->fd, offset, size, buf))
goto out;
+
+ if (size2) {
+ if (!bcache_read_bytes(scan_bcache, dev->fd, offset2, size2, buf + size))
+ goto out;
}
+
fb = buf;
}
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 5141083..38c909c 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -223,7 +223,11 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
else if ((int) ev->res < 0)
fn(cb->context, (int) ev->res);
- else {
+ else if (ev->res >= (1 << SECTOR_SHIFT)) {
+ /* minimum acceptable read is 1 sector */
+ fn((void *) cb->context, 0);
+
+ } else {
log_warn("short io");
fn(cb->context, -ENODATA);
}
diff --git a/lib/device/device.h b/lib/device/device.h
index 503373f..d5eb00f 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -31,6 +31,7 @@
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
+#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
/*
* Support for external device info.
diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c
index 72ec40b..690bc74 100644
--- a/lib/format_text/archive.c
+++ b/lib/format_text/archive.c
@@ -320,7 +320,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
* retrieve the archive time and description.
*/
/* FIXME Use variation on _vg_read */
- if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
+ if (!(vg = text_read_metadata_file(tf, af->path, &when, &desc))) {
log_error("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 1eb6654..81b5da9 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -320,7 +320,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
}
dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
- if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL, 0)))
+ if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL)))
stack;
break;
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index be9a8b9..e9a34e6 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -317,47 +317,42 @@ static void _xlate_mdah(struct mda_header *mdah)
static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev_area, int primary_mda)
{
- if (!dev_open_readonly(dev_area->dev))
- return_0;
+ log_debug_metadata("Reading mda header sector from %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
- if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah)) {
- if (!dev_close(dev_area->dev))
- stack;
- return_0;
+ if (!bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start, MDA_HEADER_SIZE, mdah)) {
+ log_error("Failed to read metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
- if (!dev_close(dev_area->dev))
- return_0;
-
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)))) {
- log_error("Incorrect metadata area header checksum on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
+ log_error("Incorrect checksum in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
_xlate_mdah(mdah);
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
- log_error("Wrong magic number in metadata area header on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
+ log_error("Wrong magic number in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
if (mdah->version != FMTT_VERSION) {
- log_error("Incompatible metadata area header version: %d on %s"
- " at offset " FMTu64, mdah->version,
- dev_name(dev_area->dev), dev_area->start);
+ log_error("Incompatible version %u metadata area header on %s at %llu",
+ mdah->version,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
if (mdah->start != dev_area->start) {
- log_error("Incorrect start sector in metadata area header: "
- FMTu64 " on %s at offset " FMTu64, mdah->start,
- dev_name(dev_area->dev), dev_area->start);
+ log_error("Incorrect start sector %llu in metadata area header on %s at %llu",
+ (unsigned long long)mdah->start,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
@@ -390,18 +385,33 @@ static int _raw_write_mda_header(const struct format_type *fmt,
mdah->version = FMTT_VERSION;
mdah->start = start_byte;
+ label_scan_invalidate(dev);
+
+ if (!dev_open(dev))
+ return_0;
+
_xlate_mdah(mdah);
mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
- if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah))
+ if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah)) {
+ dev_close(dev);
return_0;
+ }
+
+ if (dev_close(dev))
+ stack;
return 1;
}
-static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
+/*
+ * FIXME: unify this with read_metadata_location() which is used
+ * in the label scanning path.
+ */
+
+static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
struct mda_header *mdah, int primary_mda,
const char *vgname,
int *precommitted)
@@ -446,11 +456,13 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
if (rlocn_was_ignored)
return rlocn;
- /* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
- /* FIXME Ignore if checksum incorrect!!! */
- if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
- sizeof(vgnamebuf), MDA_CONTENT_REASON(primary_mda), vgnamebuf))
- goto_bad;
+ /*
+ * Verify that the VG metadata pointed to by the rlocn
+ * begins with a valid vgname.
+ */
+ memset(vgnamebuf, 0, sizeof(vgnamebuf));
+
+ bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
@@ -505,7 +517,7 @@ static int _raw_holds_vgname(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, dev_area, 0)))
return_0;
- if (_find_vg_rlocn(dev_area, mdah, 0, vgname, &noprecommit))
+ if (_read_metadata_location_vg(dev_area, mdah, 0, vgname, &noprecommit))
r = 1;
if (!dev_close(dev_area->dev))
@@ -520,7 +532,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
int precommitted,
- int single_device, int primary_mda)
+ int primary_mda)
{
struct volume_group *vg = NULL;
struct raw_locn *rlocn;
@@ -532,7 +544,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, area, primary_mda)))
goto_out;
- if (!(rlocn = _find_vg_rlocn(area, mdah, primary_mda, vgname, &precommitted))) {
+ if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) {
log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev));
goto out;
}
@@ -546,26 +558,25 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
goto out;
}
- /* FIXME 64-bit */
- if (!(vg = text_vg_import_fd(fid, NULL, vg_fmtdata, use_previous_vg, single_device, area->dev,
- primary_mda,
- (off_t) (area->start + rlocn->offset),
- (uint32_t) (rlocn->size - wrap),
- (off_t) (area->start + MDA_HEADER_SIZE),
- wrap, calc_crc, rlocn->checksum, &when,
- &desc)) && (!use_previous_vg || !*use_previous_vg))
- goto_out;
+ vg = text_read_metadata(fid, NULL, vg_fmtdata, use_previous_vg, area->dev, primary_mda,
+ (off_t) (area->start + rlocn->offset),
+ (uint32_t) (rlocn->size - wrap),
+ (off_t) (area->start + MDA_HEADER_SIZE),
+ wrap,
+ calc_crc,
+ rlocn->checksum,
+ &when, &desc);
- if (vg)
- log_debug_metadata("Read %s %smetadata (%u) from %s at " FMTu64 " size "
- FMTu64, vg->name, precommitted ? "pre-commit " : "",
- vg->seqno, dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
- else
- log_debug_metadata("Skipped reading %smetadata from %s at " FMTu64 " size "
- FMTu64 " with matching checksum.", precommitted ? "pre-commit " : "",
- dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
+ if (!vg) {
+ /* FIXME: detect and handle errors, and distinguish from the optimization
+ that skips parsing the metadata which also returns NULL. */
+ }
+
+ log_debug_metadata("Found metadata on %s at %"FMTu64" size %"FMTu64" for VG %s",
+ dev_name(area->dev),
+ area->start + rlocn->offset,
+ rlocn->size,
+ vgname);
if (vg && precommitted)
vg->status |= PRECOMMITTED;
@@ -578,8 +589,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg,
- int single_device)
+ unsigned *use_previous_vg)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct volume_group *vg;
@@ -587,7 +597,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
if (!dev_open_readonly(mdac->area.dev))
return_NULL;
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, single_device, mda_is_primary(mda));
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
if (!dev_close(mdac->area.dev))
stack;
@@ -607,7 +617,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
if (!dev_open_readonly(mdac->area.dev))
return_NULL;
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, 0, mda_is_primary(mda));
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
if (!dev_close(mdac->area.dev))
stack;
@@ -655,7 +665,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
- rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
+ rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
mdac->rlocn.size = fidtc->raw_metadata_buf_size;
@@ -681,6 +691,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
vg->name, dev_name(mdac->area.dev), mdac->area.start +
mdac->rlocn.offset, mdac->rlocn.size - new_wrap, mdac->rlocn.size);
+ label_scan_invalidate(mdac->area.dev);
+
/* Write text out, circularly */
if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
(size_t) (mdac->rlocn.size - new_wrap), MDA_CONTENT_REASON(mda_is_primary(mda)),
@@ -752,7 +764,7 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
mdah->raw_locns[0].offset = 0;
mdah->raw_locns[0].size = 0;
mdah->raw_locns[0].checksum = 0;
@@ -872,7 +884,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
rlocn = &mdah->raw_locns[0];
mdah->raw_locns[1].offset = 0;
}
@@ -906,8 +918,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
time_t when;
char *desc;
- if (!(vg = text_vg_import_file(fid, read_path, &when, &desc)))
- return_NULL;
+ if (!(vg = text_read_metadata_file(fid, read_path, &when, &desc))) {
+ log_error("Failed to read VG %s from %s", vgname, read_path);
+ return NULL;
+ }
/*
* Currently you can only have a single volume group per
@@ -931,8 +945,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg __attribute__((unused)),
- int single_device __attribute__((unused)))
+ unsigned *use_previous_vg __attribute__((unused)))
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
@@ -1175,7 +1188,7 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
return 1;
}
-int vgname_from_mda(const struct format_type *fmt,
+int read_metadata_location_summary(const struct format_type *fmt,
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
{
@@ -1184,13 +1197,12 @@ int vgname_from_mda(const struct format_type *fmt,
unsigned int len = 0;
char buf[NAME_LEN + 1] __attribute__((aligned(8)));
uint64_t buffer_size, current_usage;
- unsigned used_cached_metadata = 0;
if (mda_free_sectors)
*mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
if (!mdah) {
- log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header");
+ log_error(INTERNAL_ERROR "read_metadata_location_summary called with NULL pointer for mda_header");
return 0;
}
@@ -1201,15 +1213,12 @@ int vgname_from_mda(const struct format_type *fmt,
* If no valid offset, do not try to search for vgname
*/
if (!rlocn->offset) {
- log_debug("%s: found metadata with offset 0.",
- dev_name(dev_area->dev));
+ log_debug_metadata("Metadata location on %s at %"FMTu64" has offset 0.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return 0;
}
- /* Do quick check for a vgname */
- if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
- NAME_LEN, MDA_CONTENT_REASON(primary_mda), buf))
- return_0;
+ bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start + rlocn->offset, NAME_LEN, buf);
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
len < (NAME_LEN - 1))
@@ -1218,47 +1227,66 @@ int vgname_from_mda(const struct format_type *fmt,
buf[len] = '\0';
/* Ignore this entry if the characters aren't permissible */
- if (!validate_name(buf))
+ if (!validate_name(buf)) {
+ log_error("Metadata location on %s at %"FMTu64" begins with invalid VG name.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return_0;
+ }
/* We found a VG - now check the metadata */
if (rlocn->offset + rlocn->size > mdah->size)
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
if (wrap > rlocn->offset) {
- log_error("%s: metadata (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes)",
- dev_name(dev_area->dev), rlocn->size, mdah->size - MDA_HEADER_SIZE);
+ log_error("Metadata location on %s at %"FMTu64" is too large for circular buffer.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return 0;
}
- /* Did we see this metadata before? */
+ /*
+ * Did we see this metadata before?
+ * Look in lvmcache to see if there is vg info matching
+ * the checksum/size that we see in the mda_header (rlocn)
+ * on this device. If so, then vgsummary->name is is set
+ * and controls if the "checksum_only" flag passed to
+ * text_read_metadata_summary() is 1 or 0.
+ *
+ * If checksum_only = 1, then text_read_metadata_summary()
+ * will read the metadata from this device, and run the
+ * checksum function on it. If the calculated checksum
+ * of the metadata matches the checksum in the mda_header,
+ * which also matches the checksum saved in vginfo from
+ * another device, then it skips parsing the metadata into
+ * a config tree, which saves considerable cpu time.
+ */
+
vgsummary->mda_checksum = rlocn->checksum;
vgsummary->mda_size = rlocn->size;
+ lvmcache_lookup_mda(vgsummary);
- if (lvmcache_lookup_mda(vgsummary))
- used_cached_metadata = 1;
-
- /* FIXME 64-bit */
- if (!text_vgsummary_import(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
+ if (!text_read_metadata_summary(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
(off_t) (dev_area->start + rlocn->offset),
(uint32_t) (rlocn->size - wrap),
(off_t) (dev_area->start + MDA_HEADER_SIZE),
wrap, calc_crc, vgsummary->vgname ? 1 : 0,
- vgsummary))
- return_0;
+ vgsummary)) {
+ log_error("Metadata location on %s at %"FMTu64" has invalid summary for VG.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
+ return 0;
+ }
/* Ignore this entry if the characters aren't permissible */
- if (!validate_name(vgsummary->vgname))
- return_0;
+ if (!validate_name(vgsummary->vgname)) {
+ log_error("Metadata location on %s at %"FMTu64" has invalid VG name.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
+ return 0;
+ }
- log_debug_metadata("%s: %s metadata at " FMTu64 " size " FMTu64
- " (in area at " FMTu64 " size " FMTu64
- ") for %s (" FMTVGID ")",
+ log_debug_metadata("Found metadata summary on %s at %"FMTu64" size %"FMTu64" for VG %s",
dev_name(dev_area->dev),
- used_cached_metadata ? "Using cached" : "Found",
dev_area->start + rlocn->offset,
- rlocn->size, dev_area->start, dev_area->size, vgsummary->vgname,
- (char *)&vgsummary->vgid);
+ rlocn->size,
+ vgsummary->vgname);
if (mda_free_sectors) {
current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
@@ -1301,8 +1329,7 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
goto close_dev;
}
- /* TODO: caching as in vgname_from_mda() (trigger this code?) */
- if (vgname_from_mda(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
+ if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0, 0);
if (vg)
lvmcache_update_vg(vg, 0);
@@ -1776,7 +1803,13 @@ static int _mda_export_text_raw(struct metadata_area *mda,
struct mda_context *mdc = (struct mda_context *) mda->metadata_locn;
char mdah[MDA_HEADER_SIZE]; /* temporary */
- if (!mdc || !_raw_read_mda_header((struct mda_header *)mdah, &mdc->area, mda_is_primary(mda)))
+ if (!mdc) {
+ log_error(INTERNAL_ERROR "mda_export_text_raw no mdc");
+ return 1; /* pretend the MDA does not exist */
+ }
+
+ /* FIXME: why aren't ignore,start,size,free_sectors available? */
+ if (!_raw_read_mda_header((struct mda_header *)mdah, &mdc->area, mda_is_primary(mda)))
return 1; /* pretend the MDA does not exist */
return config_make_nodes(cft, parent, NULL,
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index 894d881..920eb3e 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -49,7 +49,6 @@ struct text_vg_version_ops {
int (*check_version) (const struct dm_config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
const struct dm_config_tree *cf,
- unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions);
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
time_t *when, char **desc);
@@ -68,14 +67,13 @@ int read_segtype_lvflags(uint64_t *status, char *segtype_str);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
-struct volume_group *text_vg_import_file(struct format_instance *fid,
+struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);
-struct volume_group *text_vg_import_fd(struct format_instance *fid,
+struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
- int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -83,7 +81,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
uint32_t checksum,
time_t *when, char **desc);
-int text_vgsummary_import(const struct format_type *fmt,
+int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index da4cefd..4b34485 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -35,7 +35,7 @@ static void _init_text_import(void)
/*
* Find out vgname on a given device.
*/
-int text_vgsummary_import(const struct format_type *fmt,
+int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -52,17 +52,29 @@ int text_vgsummary_import(const struct format_type *fmt,
if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
return_0;
- if ((!dev && !config_file_read(cft)) ||
- (dev && !config_file_read_fd(cft, dev, reason, offset, size,
+ if (dev) {
+ log_debug_metadata("Reading metadata summary from %s at %llu size %d (+%d)",
+ dev_name(dev), (unsigned long long)offset,
+ size, size2);
+
+ if (!config_file_read_fd(cft, dev, reason, offset, size,
offset2, size2, checksum_fn,
vgsummary->mda_checksum,
- checksum_only, 1))) {
- log_error("Couldn't read volume group metadata.");
- goto out;
+ checksum_only, 1)) {
+ /* FIXME: handle errors */
+ log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
+ goto out;
+ }
+ } else {
+ if (!config_file_read(cft)) {
+ log_error("Couldn't read volume group metadata from file.");
+ goto out;
+ }
}
if (checksum_only) {
/* Checksum matches already-cached content - no need to reparse. */
+ log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
r = 1;
goto out;
}
@@ -91,11 +103,10 @@ struct cached_vg_fmtdata {
size_t cached_mda_size;
};
-struct volume_group *text_vg_import_fd(struct format_instance *fid,
+struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
- int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -108,6 +119,15 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
struct text_vg_version_ops **vsn;
int skip_parse;
+ /*
+ * This struct holds the checksum and size of the VG metadata
+ * that was read from a previous device. When we read the VG
+ * metadata from this device, we can skip parsing it into a
+ * cft (saving time) if the checksum of the metadata buffer
+ * we read from this device matches the size/checksum saved in
+ * the mda_header/rlocn struct on this device, and matches the
+ * size/checksum from the previous device.
+ */
if (vg_fmtdata && !*vg_fmtdata &&
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
log_error("Failed to allocate VG fmtdata for text format.");
@@ -127,15 +147,30 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
((*vg_fmtdata)->cached_mda_size == (size + size2));
- if ((!dev && !config_file_read(cft)) ||
- (dev && !config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
+
+ if (dev) {
+ log_debug_metadata("Reading metadata from %s at %llu size %d (+%d)",
+ dev_name(dev), (unsigned long long)offset,
+ size, size2);
+
+ if (!config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
offset2, size2, checksum_fn, checksum,
- skip_parse, 1)))
- goto_out;
+ skip_parse, 1)) {
+ /* FIXME: handle errors */
+ log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
+ goto out;
+ }
+ } else {
+ if (!config_file_read(cft)) {
+ log_error("Couldn't read volume group metadata from file.");
+ goto out;
+ }
+ }
if (skip_parse) {
if (use_previous_vg)
*use_previous_vg = 1;
+ log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
goto out;
}
@@ -146,7 +181,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
if (!(*vsn)->check_version(cft))
continue;
- if (!(vg = (*vsn)->read_vg(fid, cft, single_device, 0)))
+ if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
goto_out;
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
@@ -166,12 +201,13 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
return vg;
}
-struct volume_group *text_vg_import_file(struct format_instance *fid,
+struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc)
{
- return text_vg_import_fd(fid, file, NULL, NULL, 0, NULL, 0, (off_t)0, 0, (off_t)0, 0, NULL, 0,
- when, desc);
+ return text_read_metadata(fid, file, NULL, NULL, NULL, 0,
+ (off_t)0, 0, (off_t)0, 0, NULL, 0,
+ when, desc);
}
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
@@ -191,7 +227,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
* The only path to this point uses cached vgmetadata,
* so it can use cached PV state too.
*/
- if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
+ if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
stack;
else if ((vg_missing = vg_missing_pv_count(vg))) {
log_verbose("There are %d physical volumes missing.",
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index 9267d45..d51397a 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -32,9 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid,
struct volume_group * vg, const struct dm_config_node * pvn,
const struct dm_config_node * vgn,
struct dm_hash_table * pv_hash,
- struct dm_hash_table * lv_hash,
- unsigned *scan_done_once,
- unsigned report_missing_devices);
+ struct dm_hash_table * lv_hash);
#define _read_int32(root, path, result) \
dm_config_get_uint32(root, path, (uint32_t *) (result))
@@ -180,9 +178,7 @@ static int _read_pv(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once,
- unsigned report_missing_devices)
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct physical_volume *pv;
@@ -226,10 +222,7 @@ static int _read_pv(struct format_instance *fid,
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
buffer[0] = '\0';
- if (report_missing_devices)
- log_error_once("Couldn't find device with uuid %s.", buffer);
- else
- log_very_verbose("Couldn't find device with uuid %s.", buffer);
+ log_error_once("Couldn't find device with uuid %s.", buffer);
}
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@@ -574,9 +567,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash,
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct logical_volume *lv;
@@ -731,9 +722,7 @@ static int _read_historical_lvnames(struct format_instance *fid __attribute__((u
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct generic_logical_volume *glv;
@@ -802,9 +791,7 @@ static int _read_historical_lvnames_interconnections(struct format_instance *fid
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
const char *historical_lv_name, *origin_name = NULL;
@@ -914,9 +901,7 @@ static int _read_lvsegs(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
- struct dm_hash_table *lv_hash,
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash)
{
struct logical_volume *lv;
@@ -977,12 +962,9 @@ static int _read_sections(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *vgn,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash,
- int optional,
- unsigned *scan_done_once)
+ int optional)
{
const struct dm_config_node *n;
- /* Only report missing devices when doing a scan */
- unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1;
if (!dm_config_get_section(vgn, section, &n)) {
if (!optional) {
@@ -994,8 +976,7 @@ static int _read_sections(struct format_instance *fid,
}
for (n = n->child; n; n = n->sib) {
- if (!fn(fid, vg, n, vgn, pv_hash, lv_hash,
- scan_done_once, report_missing_devices))
+ if (!fn(fid, vg, n, vgn, pv_hash, lv_hash))
return_0;
}
@@ -1004,7 +985,6 @@ static int _read_sections(struct format_instance *fid,
static struct volume_group *_read_vg(struct format_instance *fid,
const struct dm_config_tree *cft,
- unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions)
{
const struct dm_config_node *vgn;
@@ -1012,7 +992,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
const char *str, *format_str, *system_id;
struct volume_group *vg;
struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
- unsigned scan_done_once = use_cached_pvs;
uint64_t vgstatus;
/* skip any top-level values */
@@ -1167,7 +1146,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "physical_volumes", _read_pv, vg,
- vgn, pv_hash, lv_hash, 0, &scan_done_once)) {
+ vgn, pv_hash, lv_hash, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
@@ -1175,7 +1154,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
if (allow_lvmetad_extensions)
_read_sections(fid, "outdated_pvs", _read_pv, vg,
- vgn, pv_hash, lv_hash, 1, &scan_done_once);
+ vgn, pv_hash, lv_hash, 1);
else if (dm_config_has_node(vgn, "outdated_pvs"))
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
@@ -1187,28 +1166,28 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "logical_volumes", _read_lvnames, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volume names for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all historical logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "logical_volumes", _read_lvsegs, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volumes for "
"volume group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames_interconnections,
- vg, vgn, pv_hash, lv_hash, 1, NULL)) {
+ vg, vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all removed logical volume interconnections "
"for volume group %s.", vg->name);
goto bad;
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 1746b9c..2671bbf 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -104,7 +104,7 @@ struct mda_context {
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
-int vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
+int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
uint64_t *mda_free_sectors);
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index 7058f70..1c322dd 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -323,7 +323,7 @@ struct _update_mda_baton {
struct label *label;
};
-static int _update_mda(struct metadata_area *mda, void *baton)
+static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
{
struct _update_mda_baton *p = baton;
const struct format_type *fmt = p->label->labeller->fmt;
@@ -360,7 +360,7 @@ static int _update_mda(struct metadata_area *mda, void *baton)
return 1;
}
- if (vgname_from_mda(fmt, mdah, mda_is_primary(mda), &mdac->area, &vgsummary,
+ if (read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area, &vgsummary,
&mdac->free_sectors) &&
!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
if (!dev_close(mdac->area.dev))
@@ -375,10 +375,10 @@ close_dev:
return 1;
}
-static int _text_read(struct labeller *l, struct device *dev, void *buf,
- struct label **label)
+static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
+ struct label **label)
{
- struct label_header *lh = (struct label_header *) buf;
+ struct label_header *lh = (struct label_header *) label_buf;
struct pv_header *pvhdr;
struct pv_header_extension *pvhdr_ext;
struct lvmcache_info *info;
@@ -390,7 +390,7 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf,
/*
* PV header base
*/
- pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
+ pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
FMT_TEXT_ORPHAN_VG_NAME,
@@ -447,8 +447,7 @@ out:
baton.info = info;
baton.label = *label;
- if (!lvmcache_foreach_mda(info, _update_mda, &baton))
- return_0;
+ lvmcache_foreach_mda(info, _read_mda_header_and_metadata, &baton);
lvmcache_make_valid(info);
diff --git a/lib/label/label.c b/lib/label/label.c
index 46dd667..57d5248 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -18,10 +18,14 @@
#include "crc.h"
#include "xlate.h"
#include "lvmcache.h"
+#include "bcache.h"
+#include "toolcontext.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/time.h>
+
/* FIXME Allow for larger labels? Restricted to single sector currently */
@@ -96,101 +100,6 @@ struct labeller *label_get_handler(const char *name)
return NULL;
}
-static void _update_lvmcache_orphan(struct lvmcache_info *info)
-{
- struct lvmcache_vgsummary vgsummary_orphan = {
- .vgname = lvmcache_fmt(info)->orphan_vg_name,
- };
-
- memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
-
- if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
- stack;
-}
-
-static struct labeller *_find_labeller(struct device *dev, char *buf,
- uint64_t *label_sector,
- uint64_t scan_sector)
-{
- struct labeller_i *li;
- struct labeller *r = NULL;
- struct label_header *lh;
- struct lvmcache_info *info;
- uint64_t sector;
- int found = 0;
- char readbuf[LABEL_SCAN_SIZE] __attribute__((aligned(8)));
-
- if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
- LABEL_SCAN_SIZE, DEV_IO_LABEL, readbuf)) {
- log_debug_devs("%s: Failed to read label area", dev_name(dev));
- goto out;
- }
-
- /* Scan a few sectors for a valid label */
- for (sector = 0; sector < LABEL_SCAN_SECTORS;
- sector += LABEL_SIZE >> SECTOR_SHIFT) {
- lh = (struct label_header *) (readbuf +
- (sector << SECTOR_SHIFT));
-
- if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
- if (found) {
- log_error("Ignoring additional label on %s at "
- "sector %" PRIu64, dev_name(dev),
- sector + scan_sector);
- }
- if (xlate64(lh->sector_xl) != sector + scan_sector) {
- log_very_verbose("%s: Label for sector %" PRIu64
- " found at sector %" PRIu64
- " - ignoring", dev_name(dev),
- (uint64_t)xlate64(lh->sector_xl),
- sector + scan_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)) {
- log_very_verbose("Label checksum incorrect on %s - "
- "ignoring", dev_name(dev));
- continue;
- }
- if (found)
- continue;
- }
-
- dm_list_iterate_items(li, &_labellers) {
- if (li->l->ops->can_handle(li->l, (char *) lh,
- sector + scan_sector)) {
- log_very_verbose("%s: %s label detected at "
- "sector %" PRIu64,
- dev_name(dev), li->name,
- sector + scan_sector);
- if (found) {
- log_error("Ignoring additional label "
- "on %s at sector %" PRIu64,
- dev_name(dev),
- sector + scan_sector);
- continue;
- }
- r = li->l;
- memcpy(buf, lh, LABEL_SIZE);
- if (label_sector)
- *label_sector = sector + scan_sector;
- found = 1;
- break;
- }
- }
- }
-
- out:
- if (!found) {
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
- _update_lvmcache_orphan(info);
- log_very_verbose("%s: No label detected", dev_name(dev));
- }
-
- return r;
-}
-
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev)
{
@@ -216,6 +125,8 @@ int label_remove(struct device *dev)
*/
dev_flush(dev);
+ label_scan_invalidate(dev);
+
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, DEV_IO_LABEL, readbuf)) {
log_debug_devs("%s: Failed to read label area", dev_name(dev));
goto out;
@@ -267,44 +178,6 @@ int label_remove(struct device *dev)
return r;
}
-int label_read(struct device *dev, struct label **result,
- uint64_t scan_sector)
-{
- char buf[LABEL_SIZE] __attribute__((aligned(8)));
- struct labeller *l;
- uint64_t sector;
- struct lvmcache_info *info;
- int r = 0;
-
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 1))) {
- log_debug_devs("Reading label from lvmcache for %s", dev_name(dev));
- *result = lvmcache_get_label(info);
- return 1;
- }
-
- log_debug_devs("Reading label from device %s", dev_name(dev));
-
- if (!dev_open_readonly(dev)) {
- stack;
-
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
- _update_lvmcache_orphan(info);
-
- return r;
- }
-
- if ((l = _find_labeller(dev, buf, §or, scan_sector)))
- if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result) {
- (*result)->dev = dev;
- (*result)->sector = sector;
- }
-
- if (!dev_close(dev))
- stack;
-
- return r;
-}
-
/* Caller may need to use label_get_handler to create label struct! */
int label_write(struct device *dev, struct label *label)
{
@@ -323,6 +196,8 @@ int label_write(struct device *dev, struct label *label)
return 0;
}
+ label_scan_invalidate(dev);
+
memset(buf, 0, LABEL_SIZE);
strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
@@ -373,3 +248,445 @@ struct label *label_create(struct labeller *labeller)
return label;
}
+
+
+/* global variable for accessing the bcache populated by label scan */
+struct bcache *scan_bcache;
+
+#define BCACHE_BLOCK_SIZE_IN_SECTORS 2048 /* 1MB */
+
+static bool _in_bcache(struct device *dev)
+{
+ return (dev->flags & DEV_IN_BCACHE) ? true : false;
+}
+
+static struct labeller *_find_lvm_header(struct device *dev,
+ char *scan_buf,
+ char *label_buf,
+ uint64_t *label_sector,
+ uint64_t scan_sector)
+{
+ struct labeller_i *li;
+ struct labeller *labeller_ret = NULL;
+ struct label_header *lh;
+ uint64_t sector;
+ int found = 0;
+
+ /*
+ * Find which sector in scan_buf starts with a valid label,
+ * and copy it into label_buf.
+ */
+
+ for (sector = 0; sector < LABEL_SCAN_SECTORS;
+ sector += LABEL_SIZE >> SECTOR_SHIFT) {
+ 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));
+ }
+ 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));
+ 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)) {
+ log_very_verbose("Label checksum incorrect on %s - ignoring", dev_name(dev));
+ continue;
+ }
+ if (found)
+ continue;
+ }
+
+ dm_list_iterate_items(li, &_labellers) {
+ if (li->l->ops->can_handle(li->l, (char *) lh, sector + scan_sector)) {
+ log_very_verbose("%s: %s label detected at sector %llu",
+ dev_name(dev), li->name,
+ (unsigned long long)(sector + scan_sector));
+ if (found) {
+ log_error("Ignoring additional label on %s at sector %llu",
+ dev_name(dev),
+ (unsigned long long)(sector + scan_sector));
+ continue;
+ }
+
+ labeller_ret = li->l;
+ found = 1;
+
+ memcpy(label_buf, lh, LABEL_SIZE);
+ if (label_sector)
+ *label_sector = sector + scan_sector;
+ break;
+ }
+ }
+ }
+
+ return labeller_ret;
+}
+
+/*
+ * Process/parse the headers from the data read from a device.
+ * Populates lvmcache with device / mda locations / vgname
+ * so that vg_read(vgname) will know which devices/locations
+ * to read metadata from.
+ *
+ * If during processing, headers/metadata are found to be needed
+ * beyond the range of the scanned block, then additional reads
+ * are performed in the processing functions to get that data.
+ */
+static int _process_block(struct device *dev, struct block *bb, int *is_lvm_device)
+{
+ char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
+ struct label *label = NULL;
+ struct labeller *labeller;
+ struct lvmcache_info *info;
+ uint64_t sector;
+ int ret = 0;
+
+ /*
+ * Finds the data sector containing the label and copies into label_buf.
+ * label_buf: struct label_header + struct pv_header + struct pv_header_extension
+ *
+ * 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, §or, 0))) {
+
+ /*
+ * Non-PVs exit here
+ *
+ * FIXME: check for PVs with errors that also exit here!
+ * i.e. this code cannot distinguish between a non-lvm
+ * device an an lvm device with errors.
+ */
+
+ log_very_verbose("%s: No lvm label detected", dev_name(dev));
+
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
+ /* FIXME: if this case is actually happening, fix it. */
+ log_warn("Device %s has no label, removing PV info from lvmcache.", dev_name(dev));
+ lvmcache_del(info);
+ }
+
+ *is_lvm_device = 0;
+ goto_out;
+ }
+
+ *is_lvm_device = 1;
+
+ /*
+ * This is the point where the scanning code dives into the rest of
+ * lvm. ops->read() is usually _text_read() which reads the pv_header,
+ * mda locations, mda contents. As these bits of data are read, they
+ * are saved into lvmcache as info/vginfo structs.
+ */
+
+ if ((ret = (labeller->ops->read)(labeller, dev, label_buf, &label)) && label) {
+ label->dev = dev;
+ label->sector = sector;
+ } else {
+ /* FIXME: handle errors */
+ }
+ out:
+ return ret;
+}
+
+/*
+ * Read or reread label/metadata from selected devs.
+ *
+ * Reads and looks at label_header, pv_header, pv_header_extension,
+ * mda_header, raw_locns, vg metadata from each device.
+ *
+ * Effect is populating lvmcache with latest info/vginfo (PV/VG) data
+ * from the devs. If a scanned device does not have a label_header,
+ * its info is removed from lvmcache.
+ */
+
+static int _scan_list(struct dm_list *devs)
+{
+ struct dm_list wait_devs;
+ struct dm_list done_devs;
+ struct device_list *devl, *devl2;
+ struct block *bb;
+ int scan_failed_count = 0;
+ int scan_lvm_count = 0;
+ int rem_prefetches;
+ int scan_failed;
+ int is_lvm_device;
+
+ dm_list_init(&wait_devs);
+ dm_list_init(&done_devs);
+
+ log_debug_devs("Scanning %d devices.", dm_list_size(devs));
+
+ scan_more:
+ rem_prefetches = bcache_max_prefetches(scan_bcache);
+
+ dm_list_iterate_items_safe(devl, devl2, devs) {
+
+ /*
+ * If we prefetch more devs than blocks in the cache, then the
+ * cache will wait for earlier reads to complete, toss the
+ * results, and reuse those blocks before we've had a chance to
+ * use them. So, prefetch as many as are available, wait for
+ * and process them, then repeat.
+ */
+ if (!rem_prefetches)
+ break;
+
+ /*
+ * The in-bcache flag corresponds with this dev_open.
+ * Clearing the in-bcache flag should be paired with
+ * a dev_close. (This dev may already be in bcache.)
+ */
+ if (!_in_bcache(devl->dev)) {
+ if (!dev_open_readonly(devl->dev)) {
+ log_debug_devs("%s: Failed to open device.", dev_name(devl->dev));
+ continue;
+ }
+ }
+
+ bcache_prefetch(scan_bcache, devl->dev->fd, 0);
+
+ rem_prefetches--;
+
+ dm_list_del(&devl->list);
+ dm_list_add(&wait_devs, &devl->list);
+ }
+
+ dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
+ bb = NULL;
+
+ if (!bcache_get(scan_bcache, devl->dev->fd, 0, 0, &bb)) {
+ log_debug_devs("%s: Failed to scan device.", dev_name(devl->dev));
+ scan_failed_count++;
+ scan_failed = 1;
+ } else {
+ log_debug_devs("Processing data from device %s fd %d block %p", dev_name(devl->dev), devl->dev->fd, bb);
+ _process_block(devl->dev, bb, &is_lvm_device);
+ scan_lvm_count++;
+ scan_failed = 0;
+ }
+
+ if (bb)
+ bcache_put(bb);
+
+ /*
+ * Keep the bcache block of lvm devices we have processed so
+ * that the vg_read phase can reuse it. If bcache failed to
+ * read the block, or the device does not belong to lvm, then
+ * drop it from bcache.
+ */
+ if (scan_failed || !is_lvm_device) {
+ devl->dev->flags &= ~DEV_IN_BCACHE;
+ bcache_invalidate_fd(scan_bcache, devl->dev->fd);
+ dev_close(devl->dev);
+ } else {
+ /* The device must be kept open while it's in bcache. */
+ devl->dev->flags |= DEV_IN_BCACHE;
+ }
+
+ dm_list_del(&devl->list);
+ dm_list_add(&done_devs, &devl->list);
+ }
+
+ if (!dm_list_empty(devs))
+ goto scan_more;
+
+ /* FIXME: let the caller know if some lvm devices failed to be scanned. */
+
+ log_debug_devs("Scanned %d devices: %d for lvm, %d failed.",
+ dm_list_size(&done_devs), scan_lvm_count, scan_failed_count);
+
+ return 0;
+}
+
+/*
+ * Scan and cache lvm data from all devices on the system.
+ * The cache should be empty/reset before calling this.
+ */
+
+int label_scan(struct cmd_context *cmd)
+{
+ struct dm_list all_devs;
+ struct dev_iter *iter;
+ struct device_list *devl;
+ struct device *dev;
+ struct io_engine *ioe;
+
+ log_debug_devs("Finding devices to scan");
+
+ dm_list_init(&all_devs);
+
+ /*
+ * Iterate through all the devices in dev-cache (block devs that appear
+ * under /dev that could possibly hold a PV and are not excluded by
+ * filters). Read each to see if it's an lvm device, and if so
+ * populate lvmcache with some basic info about the device and the VG
+ * on it. This info will be used by the vg_read() phase of the
+ * command.
+ */
+ dev_cache_full_scan(cmd->full_filter);
+
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ log_error("Scanning failed to get devices.");
+ return 0;
+ }
+
+ while ((dev = dev_iter_get(iter))) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return 0;
+ devl->dev = dev;
+ dm_list_add(&all_devs, &devl->list);
+
+ /*
+ * label_scan should not generally be called a second time,
+ * so this will usually not be true.
+ */
+ if (_in_bcache(dev))
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+ };
+ dev_iter_destroy(iter);
+
+ if (!scan_bcache) {
+
+ /*
+ * 100 is arbitrary, it's the max number of concurrent aio's
+ * possible, i.e, the number of devices that can be read at
+ * once. Should this be configurable?
+ */
+ if (!(ioe = create_async_io_engine(100)))
+ return 0;
+
+ /*
+ * Configure one cache block for each device on the system.
+ * We won't generally need to cache that many because some
+ * of the devs will not be lvm devices, and we don't need
+ * an entry for those. We might want to change this.
+ */
+ if (!(scan_bcache = bcache_create(BCACHE_BLOCK_SIZE_IN_SECTORS, dm_list_size(&all_devs), ioe)))
+ return 0;
+ }
+
+ return _scan_list(&all_devs);
+}
+
+/*
+ * Scan and cache lvm data from the listed devices. If a device is already
+ * scanned and cached, this replaces the previously cached lvm data for the
+ * device. This is called when vg_read() wants to guarantee that it is using
+ * the latest data from the devices in the VG (since the scan populated bcache
+ * without a lock.)
+ */
+
+int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs)
+{
+ struct device_list *devl;
+
+ dm_list_iterate_items(devl, devs) {
+ if (_in_bcache(devl->dev))
+ bcache_invalidate_fd(scan_bcache, devl->dev->fd);
+ }
+
+ return _scan_list(devs);
+}
+
+void label_scan_invalidate(struct device *dev)
+{
+ if (_in_bcache(dev)) {
+ dev->flags &= ~DEV_IN_BCACHE;
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+ dev_close(dev);
+ }
+}
+
+/*
+ * Undo label_scan()
+ *
+ * Close devices that are open because bcache is holding blocks for them.
+ * Destroy the bcache.
+ */
+
+void label_scan_destroy(struct cmd_context *cmd)
+{
+ struct dev_iter *iter;
+ struct device *dev;
+
+ if (!scan_bcache)
+ return;
+
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ return;
+ }
+
+ while ((dev = dev_iter_get(iter)))
+ label_scan_invalidate(dev);
+ dev_iter_destroy(iter);
+
+ bcache_destroy(scan_bcache);
+ scan_bcache = NULL;
+}
+
+/*
+ * Read (or re-read) and process (or re-process) the data for a device. This
+ * will reset (clear and repopulate) the bcache and lvmcache info for this
+ * device. There are only a couple odd places that want to reread a specific
+ * device, this is not a commonly used function.
+ */
+
+/* FIXME: remove unused_sector arg */
+
+int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector)
+{
+ struct dm_list one_dev;
+ struct device_list *devl;
+ int ret;
+
+ /* scanning is done by list, so make a single item list for this dev */
+ if (!(devl = dm_zalloc(sizeof(*devl))))
+ return 0;
+ devl->dev = dev;
+ dm_list_init(&one_dev);
+ dm_list_add(&one_dev, &devl->list);
+
+ if (_in_bcache(dev))
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+
+ ret = _scan_list(&one_dev);
+
+ /*
+ * FIXME: this ugliness of returning a pointer to the label is
+ * temporary until the callers can be updated to not use this.
+ */
+ if (labelp) {
+ struct lvmcache_info *info;
+
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 1);
+ if (info)
+ *labelp = lvmcache_get_label(info);
+ }
+
+ return ret;
+}
+
+/*
+ * 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, struct label **labelp, uint64_t scan_sector)
+{
+ if (scan_sector) {
+ /* TODO: not yet implemented */
+ /* When is this done? When does it make sense? Is it actually possible? */
+ return 0;
+ }
+
+ return label_read(dev, labelp, 0);
+}
+
diff --git a/lib/label/label.h b/lib/label/label.h
index ea11290..d9e36bc 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -18,6 +18,8 @@
#include "uuid.h"
#include "device.h"
+#include "bcache.h"
+#include "toolcontext.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
@@ -63,7 +65,7 @@ struct label_ops {
* Read a label from a volume.
*/
int (*read) (struct labeller * l, struct device * dev,
- void *buf, struct label ** label);
+ void *label_buf, struct label ** label);
/*
* Populate label_type etc.
@@ -94,10 +96,17 @@ int label_register_handler(struct labeller *handler);
struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
-int label_read(struct device *dev, struct label **result,
- uint64_t scan_sector);
int label_write(struct device *dev, struct label *label);
struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
+extern struct bcache *scan_bcache;
+
+int label_scan(struct cmd_context *cmd);
+int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs);
+void label_scan_invalidate(struct device *dev);
+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);
+
#endif
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 2bc7927..73041cf 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -377,6 +377,19 @@ struct pv_segment {
*/
#define FMT_INSTANCE_PRIVATE_MDAS 0x00000008U
+/*
+ * Each VG has its own fid struct. The fid for a VG describes where
+ * the metadata for that VG can be found. The lists hold mda locations.
+ *
+ * label scan finds the metadata locations (devs and offsets) for a VG,
+ * and saves this info in lvmcache vginfo/info lists.
+ *
+ * vg_read() then creates an fid for a given VG, and the mda locations
+ * from lvmcache are copied onto the fid lists. Those mda locations
+ * are read again by vg_read() to get VG metadata that is used to
+ * create the 'vg' struct.
+ */
+
struct format_instance {
unsigned ref_count; /* Refs to this fid from VG and PV structs */
struct dm_pool *mem;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 2249d2f..00b7737 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -719,6 +719,10 @@ int check_pv_dev_sizes(struct volume_group *vg)
* source file. All the following and more are only used by liblvm:
*
* . get_pvs()
+ * . get_vgids()
+ * . get_vgnames()
+ * . lvmcache_get_vgids()
+ * . lvmcache_get_vgnames()
* . the vg->pvs_to_write list and pv_to_write struct
*/
@@ -3909,12 +3913,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* Ensure contents of all metadata areas match - else do recovery */
inconsistent_mda_count=0;
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
+ struct device *mda_dev = mda_get_device(mda);
+
use_previous_vg = 0;
+ log_debug_metadata("Reading VG %s from %s", vgname, dev_name(mda_dev));
+
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
- !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
+ !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
@@ -4106,7 +4114,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
- !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
+ !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 1fa14e8..5b8d690 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -80,8 +80,7 @@ struct metadata_area_ops {
const char *vg_name,
struct metadata_area * mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg,
- int single_device);
+ unsigned *use_previous_vg);
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda,
@@ -183,6 +182,11 @@ void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored);
unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2);
struct device *mda_get_device(struct metadata_area *mda);
+/*
+ * fic is used to create an fid. It's used to pass fmt/vgname/vgid args
+ * to create_instance() which creates an fid for the specified vg.
+ */
+
struct format_instance_ctx {
uint32_t type;
union {
6 years
master - scan: improve io error checking and reporting
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=45e5e702c1d488df489...
Commit: 45e5e702c1d488df4898a41db0c00ead63c5f6ee
Parent: 6d05859862cebe79981557fe1a1005a530302f70
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 6 13:12:26 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
scan: improve io error checking and reporting
---
lib/label/label.c | 30 +++++++++++++++++++-----------
1 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index 14a7e90..6c3be05 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -466,17 +466,20 @@ static int _scan_list(struct dm_list *devs, int *failed)
struct dm_list done_devs;
struct device_list *devl, *devl2;
struct block *bb;
+ int scan_open_errors = 0;
+ int scan_read_errors = 0;
+ int scan_process_errors = 0;
int scan_failed_count = 0;
- int scan_lvm_count = 0;
int rem_prefetches;
int scan_failed;
int is_lvm_device;
+ int error;
int ret;
dm_list_init(&wait_devs);
dm_list_init(&done_devs);
- log_debug_devs("Scanning %d devices.", dm_list_size(devs));
+ log_debug_devs("Scanning %d devices for VG info", dm_list_size(devs));
scan_more:
rem_prefetches = bcache_max_prefetches(scan_bcache);
@@ -498,6 +501,7 @@ static int _scan_list(struct dm_list *devs, int *failed)
log_debug_devs("Scan failed to open %s.", dev_name(devl->dev));
dm_list_del(&devl->list);
dm_list_add(&done_devs, &devl->list);
+ scan_open_errors++;
scan_failed_count++;
continue;
}
@@ -513,11 +517,15 @@ static int _scan_list(struct dm_list *devs, int *failed)
dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
bb = NULL;
+ error = 0;
+ scan_failed = 0;
+ is_lvm_device = 0;
- if (!bcache_get(scan_bcache, devl->dev->bcache_fd, 0, 0, &bb)) {
- log_debug_devs("Scan failed to read %s.", dev_name(devl->dev));
- scan_failed_count++;
+ if (!bcache_get(scan_bcache, devl->dev->bcache_fd, 0, 0, &bb, &error)) {
+ log_debug_devs("Scan failed to read %s error %d.", dev_name(devl->dev), error);
scan_failed = 1;
+ scan_read_errors++;
+ scan_failed_count++;
lvmcache_del_dev(devl->dev);
} else {
log_debug_devs("Processing data from device %s fd %d block %p", dev_name(devl->dev), devl->dev->bcache_fd, bb);
@@ -526,12 +534,10 @@ static int _scan_list(struct dm_list *devs, int *failed)
if (!ret && is_lvm_device) {
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
- scan_failed_count++;
scan_failed = 1;
+ scan_process_errors++;
+ scan_failed_count++;
lvmcache_del_dev(devl->dev);
- } else {
- scan_lvm_count++;
- scan_failed = 0;
}
}
@@ -556,8 +562,8 @@ static int _scan_list(struct dm_list *devs, int *failed)
if (!dm_list_empty(devs))
goto scan_more;
- log_debug_devs("Scanned devices: %d lvm, %d failed.",
- scan_lvm_count, scan_failed_count);
+ log_debug_devs("Scanned devices: open errors %d read errors %d process errors %d",
+ scan_open_errors, scan_read_errors, scan_process_errors);
if (failed)
*failed = scan_failed_count;
@@ -649,6 +655,8 @@ int label_scan(struct cmd_context *cmd)
};
dev_iter_destroy(iter);
+ log_debug_devs("Found %d devices to scan", dm_list_size(&all_devs));
+
if (!scan_bcache) {
/*
* FIXME: there should probably be some max number of
6 years
master - bcache: let caller see an error
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=6d05859862cebe79981...
Commit: 6d05859862cebe79981557fe1a1005a530302f70
Parent: ae21305ee7fa60edbd85824d83ce554989161189
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 6 13:11:39 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
bcache: let caller see an error
---
lib/device/bcache.c | 21 ++++++++++++++-------
lib/device/bcache.h | 9 ++++++++-
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 9034776..ea8f702 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -234,7 +234,6 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
fn((void *) cb->context, 0);
} else {
- log_warn("short io");
fn(cb->context, -ENODATA);
}
@@ -538,10 +537,8 @@ static void _complete_io(void *context, int err)
*/
dm_list_del(&b->list);
- if (b->error) {
- log_warn("bcache io error %d fd %d", b->error, b->fd);
+ if (b->error)
memset(b->data, 0, cache->block_sectors << SECTOR_SHIFT);
- }
/* Things don't work with this block of code, but work without it. */
#if 0
@@ -583,6 +580,7 @@ static void _issue_low_level(struct block *b, enum dir d)
dm_list_add(&cache->io_pending, &b->list);
if (!cache->engine->issue(cache->engine, d, b->fd, sb, se, b->data, b)) {
+ /* FIXME: if io_submit() set an errno, return that instead of EIO? */
_complete_io(b, -EIO);
return;
}
@@ -904,7 +902,7 @@ void bcache_prefetch(struct bcache *cache, int fd, block_address index)
}
bool bcache_get(struct bcache *cache, int fd, block_address index,
- unsigned flags, struct block **result)
+ unsigned flags, struct block **result, int *error)
{
struct block *b;
@@ -916,12 +914,19 @@ bool bcache_get(struct bcache *cache, int fd, block_address index,
*result = b;
+ if (error)
+ *error = b->error;
+
if (b->error)
return false;
return true;
}
*result = NULL;
+
+ if (error)
+ *error = -BCACHE_NO_BLOCK;
+
log_error("bcache failed to get block %u fd %d", (uint32_t)index, fd);
return false;
}
@@ -1068,7 +1073,9 @@ bool bcache_read_bytes(struct bcache *cache, int fd, off_t start, size_t len, vo
bcache_prefetch(cache, fd, i);
for (i = bb; i < be; i++) {
- if (!bcache_get(cache, fd, i, 0, &b)) {
+ if (!bcache_get(cache, fd, i, 0, &b, NULL)) {
+ log_error("bcache_read failed to get block %u fd %d bb %u be %u",
+ (uint32_t)i, fd, (uint32_t)bb, (uint32_t)be);
errors++;
continue;
}
@@ -1105,7 +1112,7 @@ bool bcache_write_bytes(struct bcache *cache, int fd, off_t start, size_t len, v
bcache_prefetch(cache, fd, i);
for (i = bb; i < be; i++) {
- if (!bcache_get(cache, fd, i, 0, &b)) {
+ if (!bcache_get(cache, fd, i, 0, &b, NULL)) {
log_error("bcache_write failed to get block %u fd %d bb %u be %u",
(uint32_t)i, fd, (uint32_t)bb, (uint32_t)be);
errors++;
diff --git a/lib/device/bcache.h b/lib/device/bcache.h
index d5f6d0a..999223a 100644
--- a/lib/device/bcache.h
+++ b/lib/device/bcache.h
@@ -29,6 +29,13 @@
/*----------------------------------------------------------------*/
+/*
+ * bcache-specific error numbers
+ * These supplement standard -EXXX error numbers and
+ * should not overlap.
+ */
+#define BCACHE_NO_BLOCK 201
+
enum dir {
DIR_READ,
DIR_WRITE
@@ -120,7 +127,7 @@ void bcache_prefetch(struct bcache *cache, int fd, block_address index);
* Returns true on success.
*/
bool bcache_get(struct bcache *cache, int fd, block_address index,
- unsigned flags, struct block **result);
+ unsigned flags, struct block **result, int *error);
void bcache_put(struct block *b);
/*
6 years
master - scan: drop bcache between lvm shell commands
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=ae21305ee7fa60edbd8...
Commit: ae21305ee7fa60edbd85824d83ce554989161189
Parent: a01a8d71723740577e5fe9635412940d941b5da9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Apr 6 13:05:17 2018 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
scan: drop bcache between lvm shell commands
A running lvm shell keeps all lvm devices open
unless the bcache is dropped.
---
lib/cache/lvmcache.c | 22 ++++++++++++++++++++--
tools/lvmcmdline.c | 7 +++----
tools/toollib.c | 1 -
3 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 6479080..78665bf 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -406,7 +406,7 @@ int lvmcache_verify_lock_order(const char *vgname)
return 1;
if (!_lock_hash)
- return_0;
+ return 1;
dm_hash_iterate(n, _lock_hash) {
if (!dm_hash_get_data(_lock_hash, n))
@@ -836,6 +836,9 @@ static int _label_scan_invalid(struct cmd_context *cmd)
dev_count++;
}
+ if (dm_list_empty(&devs))
+ return 1;
+
log_debug_cache("Scanning %d devs with invalid info.", dev_count);
ret = label_scan_devs(cmd, &devs);
@@ -1236,8 +1239,10 @@ int lvmcache_label_scan(struct cmd_context *cmd)
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct lvmcache_info *info;
+ struct lvmcache_vginfo *vginfo;
struct device_list *devl;
struct format_type *fmt;
+ int vginfo_count = 0;
int r = 0;
@@ -1247,6 +1252,8 @@ int lvmcache_label_scan(struct cmd_context *cmd)
return 1;
}
+ log_debug_cache("Finding VG info");
+
/* Avoid recursion when a PVID can't be found! */
if (_scanning_in_progress)
return 0;
@@ -1315,6 +1322,8 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_init(&del_cache_devs);
dm_list_init(&add_cache_devs);
+ log_debug_cache("Resolving duplicate devices");
+
_choose_preferred_devs(cmd, &del_cache_devs, &add_cache_devs);
dm_list_iterate_items(devl, &del_cache_devs) {
@@ -1354,6 +1363,14 @@ int lvmcache_label_scan(struct cmd_context *cmd)
_scanning_in_progress = 0;
_force_label_scan = 0;
+ dm_list_iterate_items(vginfo, &_vginfos) {
+ if (is_orphan_vg(vginfo->vgname))
+ continue;
+ vginfo_count++;
+ }
+
+ log_debug_cache("Found VG info for %d VGs", vginfo_count);
+
return r;
}
@@ -2291,7 +2308,8 @@ static void _lvmcache_destroy_lockname(struct dm_hash_node *n)
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
{
struct dm_hash_node *n;
- log_verbose("Wiping internal VG cache");
+
+ log_debug_cache("Dropping VG info");
_has_scanned = 0;
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index fc96b8d..3774014 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -3013,10 +3013,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
lvmnotify_send(cmd);
out:
- if (test_mode()) {
- log_verbose("Test mode: Wiping internal cache");
- lvmcache_destroy(cmd, 1, 0);
- }
+
+ lvmcache_destroy(cmd, 1, 1);
+ label_scan_destroy(cmd);
if ((config_string_cft = remove_config_tree_by_source(cmd, CONFIG_STRING)))
dm_config_destroy(config_string_cft);
diff --git a/tools/toollib.c b/tools/toollib.c
index c8dd9d3..7e3b021 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -4508,7 +4508,6 @@ int process_each_pv(struct cmd_context *cmd,
* before process_each_pv is called.
*/
if (!trust_cache() && !orphans_locked) {
- log_debug("Scanning for available devices");
lvmcache_destroy(cmd, 1, 0);
/*
6 years
master - tests: vgck now exits with error for bad vg
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a01a8d71723740577e5...
Commit: a01a8d71723740577e5fe9635412940d941b5da9
Parent: a9b0aa5c178a6d8bb708ed35f833c648f7437ae3
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Mar 9 13:18:38 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:48 2018 -0500
tests: vgck now exits with error for bad vg
---
test/shell/vgck.sh | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/shell/vgck.sh b/test/shell/vgck.sh
index 2f3fba4..186704c 100644
--- a/test/shell/vgck.sh
+++ b/test/shell/vgck.sh
@@ -22,18 +22,18 @@ dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
# TODO: aux lvmconf "global/locking_type = 4"
-vgscan 2>&1 | tee vgscan.out
+vgscan 2>&1 | tee vgscan.out || true
if test -e LOCAL_LVMETAD; then
- not grep "Inconsistent metadata found for VG $vg" vgscan.out
+ not grep "Failed" vgscan.out
else
- grep "Inconsistent metadata found for VG $vg" vgscan.out
+ grep "Failed" vgscan.out
fi
dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
aux notify_lvmetad "$dev2"
-vgck $vg 2>&1 | tee vgck.out
+vgck $vg 2>&1 | tee vgck.out || true
grep Incorrect vgck.out
vgremove -ff $vg
6 years