mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
add device hints to reduce scanning
Save the list of PVs in /run/lvm/hints. These hints are used to reduce scanning in a number of commands to only the PVs on the system, or only the PVs in a requested VG (rather than all devices on the system.)
This commit is contained in:
parent
81b3b71dae
commit
6620dc9475
@ -61,6 +61,7 @@ SOURCES =\
|
||||
format_text/text_label.c \
|
||||
freeseg/freeseg.c \
|
||||
label/label.c \
|
||||
label/hints.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
log/log.c \
|
||||
|
18
lib/cache/lvmcache.c
vendored
18
lib/cache/lvmcache.c
vendored
@ -69,6 +69,7 @@ static DM_LIST_INIT(_unused_duplicate_devs);
|
||||
static int _scanning_in_progress = 0;
|
||||
static int _vgs_locked = 0;
|
||||
static int _found_duplicate_pvs = 0; /* If we never see a duplicate PV we can skip checking for them later. */
|
||||
static int _found_duplicate_vgnames = 0;
|
||||
|
||||
int lvmcache_init(struct cmd_context *cmd)
|
||||
{
|
||||
@ -131,6 +132,11 @@ int lvmcache_found_duplicate_pvs(void)
|
||||
return _found_duplicate_pvs;
|
||||
}
|
||||
|
||||
int lvmcache_found_duplicate_vgnames(void)
|
||||
{
|
||||
return _found_duplicate_vgnames;
|
||||
}
|
||||
|
||||
int lvmcache_get_unused_duplicate_devs(struct cmd_context *cmd, struct dm_list *head)
|
||||
{
|
||||
struct device_list *devl, *devl2;
|
||||
@ -1225,6 +1231,8 @@ static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
|
||||
sizeof(uuid_primary)))
|
||||
return_0;
|
||||
|
||||
_found_duplicate_vgnames = 1;
|
||||
|
||||
/*
|
||||
* vginfo is kept for each VG with the same name.
|
||||
* They are saved with the vginfo->next list.
|
||||
@ -2278,3 +2286,13 @@ int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const ch
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
|
||||
dm_list_iterate_items(info, &vginfo->infos) {
|
||||
if (!strcmp(info->dev->pvid, pvid))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
3
lib/cache/lvmcache.h
vendored
3
lib/cache/lvmcache.h
vendored
@ -169,6 +169,7 @@ int lvmcache_vgid_is_cached(const char *vgid);
|
||||
uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
|
||||
|
||||
int lvmcache_found_duplicate_pvs(void);
|
||||
int lvmcache_found_duplicate_vgnames(void);
|
||||
|
||||
void lvmcache_pvscan_duplicate_check(struct cmd_context *cmd);
|
||||
|
||||
@ -198,6 +199,8 @@ void lvmcache_set_independent_location(const char *vgname);
|
||||
|
||||
int lvmcache_scan_mismatch(struct cmd_context *cmd, const char *vgname, const char *vgid);
|
||||
|
||||
int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid);
|
||||
|
||||
/*
|
||||
* These are clvmd-specific functions and are not related to lvmcache.
|
||||
* FIXME: rename these with a clvm_ prefix in place of lvmcache_
|
||||
|
@ -1484,6 +1484,7 @@ struct cmd_context *create_config_context(void)
|
||||
|
||||
dm_list_init(&cmd->config_files);
|
||||
dm_list_init(&cmd->tags);
|
||||
dm_list_init(&cmd->hints);
|
||||
|
||||
if (!_init_lvm_conf(cmd))
|
||||
goto_out;
|
||||
|
@ -172,11 +172,16 @@ struct cmd_context {
|
||||
unsigned is_clvmd:1;
|
||||
unsigned use_full_md_check:1;
|
||||
unsigned is_activating:1;
|
||||
unsigned enable_hints:1; /* hints are enabled for cmds in general */
|
||||
unsigned use_hints:1; /* if hints are enabled this cmd can use them */
|
||||
unsigned pvscan_recreate_hints:1; /* enable special case hint handling for pvscan --cache */
|
||||
unsigned scan_lvs:1;
|
||||
|
||||
/*
|
||||
* Filtering.
|
||||
* Devices and filtering.
|
||||
*/
|
||||
struct dev_filter *filter;
|
||||
struct dm_list hints;
|
||||
|
||||
/*
|
||||
* Configuration.
|
||||
|
@ -255,6 +255,20 @@ cfg(devices_external_device_info_source_CFG, "external_device_info_source", devi
|
||||
" compiled with udev support.\n"
|
||||
"#\n")
|
||||
|
||||
cfg(devices_hints_CFG, "hints", devices_CFG_SECTION, 0, CFG_TYPE_STRING, DEFAULT_HINTS, vsn(2, 3, 2), NULL, 0, NULL,
|
||||
"Use a local file to remember which devices have PVs on them.\n"
|
||||
"Some commands will use this as an optimization to reduce device\n"
|
||||
"scanning, and will only scan the listed PVs. Removing the hint file\n"
|
||||
"will cause lvm to generate a new one. Disable hints if PVs will\n"
|
||||
"be copied onto devices using non-lvm commands, like dd.\n"
|
||||
"#\n"
|
||||
"Accepted values:\n"
|
||||
" all\n"
|
||||
" Use all hints.\n"
|
||||
" none\n"
|
||||
" Use no hints.\n"
|
||||
"#\n")
|
||||
|
||||
cfg_array(devices_preferred_names_CFG, "preferred_names", devices_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED , CFG_TYPE_STRING, NULL, vsn(1, 2, 19), NULL, 0, NULL,
|
||||
"Select which path name to display for a block device.\n"
|
||||
"If multiple path names exist for a block device, and LVM needs to\n"
|
||||
|
@ -312,4 +312,6 @@
|
||||
|
||||
#define DEFAULT_SCAN_LVS 1
|
||||
|
||||
#define DEFAULT_HINTS "all"
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@ -1473,7 +1473,7 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
|
||||
return d;
|
||||
|
||||
if (f && !(d->flags & DEV_REGULAR)) {
|
||||
ret = f->passes_filter(cmd, f, d);
|
||||
ret = f->passes_filter(cmd, f, d, NULL);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by name defer filter %s", dev_name(d));
|
||||
@ -1546,7 +1546,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
|
||||
if (!f)
|
||||
return d;
|
||||
|
||||
ret = f->passes_filter(cmd, f, d);
|
||||
ret = f->passes_filter(cmd, f, d, NULL);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by number defer filter %s", dev_name(d));
|
||||
@ -1603,7 +1603,7 @@ struct device *dev_iter_get(struct cmd_context *cmd, struct dev_iter *iter)
|
||||
f = iter->filter;
|
||||
|
||||
if (f && !(d->flags & DEV_REGULAR)) {
|
||||
ret = f->passes_filter(cmd, f, d);
|
||||
ret = f->passes_filter(cmd, f, d, NULL);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
log_debug_devs("get device by iter defer filter %s", dev_name(d));
|
||||
|
@ -25,11 +25,12 @@ struct cmd_context;
|
||||
* predicate for devices.
|
||||
*/
|
||||
struct dev_filter {
|
||||
int (*passes_filter) (struct cmd_context *cmd, struct dev_filter *f, struct device *dev);
|
||||
int (*passes_filter) (struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name);
|
||||
void (*destroy) (struct dev_filter *f);
|
||||
void (*wipe) (struct dev_filter *f);
|
||||
void *private;
|
||||
unsigned use_count;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
int dev_cache_index_devs(void);
|
||||
|
@ -79,6 +79,36 @@ int dev_is_pmem(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dev_is_lv(struct device *dev)
|
||||
{
|
||||
FILE *fp;
|
||||
char path[PATH_MAX];
|
||||
char buffer[64];
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/uuid",
|
||||
dm_sysfs_dir(),
|
||||
(int) MAJOR(dev->dev),
|
||||
(int) MINOR(dev->dev)) < 0) {
|
||||
log_warn("Sysfs dm uuid path for %s is too long.", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp = fopen(path, "r")))
|
||||
return 0;
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_warn("Failed to read %s.", path);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!strncmp(buffer, "LVM-", 4))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dev_types *create_dev_types(const char *proc_dir,
|
||||
const struct dm_config_node *cn)
|
||||
{
|
||||
|
@ -95,4 +95,6 @@ int dev_is_rotational(struct dev_types *dt, struct device *dev);
|
||||
|
||||
int dev_is_pmem(struct device *dev);
|
||||
|
||||
int dev_is_lv(struct device *dev);
|
||||
|
||||
#endif
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define DEV_FILTER_AFTER_SCAN 0x00002000 /* apply filter after bcache has data */
|
||||
#define DEV_FILTER_OUT_SCAN 0x00004000 /* filtered out during label scan */
|
||||
#define DEV_BCACHE_WRITE 0x00008000 /* bcache_fd is open with RDWR */
|
||||
#define DEV_SCAN_FOUND_LABEL 0x00010000 /* label scan read dev and found label */
|
||||
|
||||
/*
|
||||
* Support for external device info.
|
||||
|
@ -18,13 +18,15 @@
|
||||
#include "lib/filters/filter.h"
|
||||
#include "lib/device/device.h"
|
||||
|
||||
static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_filter **filters;
|
||||
int ret;
|
||||
|
||||
for (filters = (struct dev_filter **) f->private; *filters; ++filters) {
|
||||
ret = (*filters)->passes_filter(cmd, *filters, dev);
|
||||
if (use_filter_name && strcmp((*filters)->name, use_filter_name))
|
||||
continue;
|
||||
ret = (*filters)->passes_filter(cmd, *filters, dev, use_filter_name);
|
||||
|
||||
if (!ret)
|
||||
return 0; /* No 'stack': a filter, not an error. */
|
||||
@ -33,12 +35,12 @@ static int _and_p(struct cmd_context *cmd, struct dev_filter *f, struct device *
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _and_p_with_dev_ext_info(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _and_p_with_dev_ext_info(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
int r;
|
||||
|
||||
dev_ext_enable(dev, external_device_info_source());
|
||||
r = _and_p(cmd, f, dev);
|
||||
r = _and_p(cmd, f, dev, use_filter_name);
|
||||
dev_ext_disable(dev);
|
||||
|
||||
return r;
|
||||
@ -93,6 +95,7 @@ struct dev_filter *composite_filter_create(int n, int use_dev_ext_info, struct d
|
||||
cft->wipe = _wipe;
|
||||
cft->use_count = 0;
|
||||
cft->private = filters_copy;
|
||||
cft->name = "composite";
|
||||
|
||||
log_debug_devs("Composite filter initialised.");
|
||||
|
||||
|
@ -65,7 +65,7 @@ static int _dev_is_fwraid(struct device *dev)
|
||||
#define MSG_SKIPPING "%s: Skipping firmware RAID component device"
|
||||
|
||||
static int _ignore_fwraid(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -113,6 +113,7 @@ struct dev_filter *fwraid_filter_create(struct dev_types *dt __attribute__((unus
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = NULL;
|
||||
f->name = "fwraid";
|
||||
|
||||
log_debug_devs("Firmware RAID filter initialised.");
|
||||
|
||||
|
@ -38,7 +38,7 @@ void internal_filter_clear(void)
|
||||
}
|
||||
|
||||
static int _passes_internal(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct device_list *devl;
|
||||
|
||||
@ -74,6 +74,7 @@ struct dev_filter *internal_filter_create(void)
|
||||
f->passes_filter = _passes_internal;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->name = "internal";
|
||||
|
||||
log_debug_devs("Internal filter initialised.");
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
||||
* that will not pass.
|
||||
*/
|
||||
|
||||
static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)), struct device *dev)
|
||||
static int _passes_md_filter(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)), struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -145,6 +145,7 @@ struct dev_filter *md_filter_create(struct cmd_context *cmd, struct dev_types *d
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "md";
|
||||
|
||||
log_debug_devs("MD filter initialised.");
|
||||
|
||||
|
@ -247,7 +247,7 @@ static int _dev_is_mpath(struct dev_filter *f, struct device *dev)
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping mpath component device"
|
||||
|
||||
static int _ignore_mpath(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _ignore_mpath(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
if (_dev_is_mpath(f, dev) == 1) {
|
||||
if (dev->ext.src == DEV_EXT_NONE)
|
||||
@ -288,6 +288,7 @@ struct dev_filter *mpath_filter_create(struct dev_types *dt)
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "mpath";
|
||||
|
||||
log_debug_devs("mpath filter initialised.");
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#define MSG_SKIPPING "%s: Skipping: Partition table signature found"
|
||||
|
||||
static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _passes_partitioned_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
int ret;
|
||||
@ -66,6 +66,7 @@ struct dev_filter *partitioned_filter_create(struct dev_types *dt)
|
||||
f->destroy = _partitioned_filter_destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "partitioned";
|
||||
|
||||
log_debug_devs("Partitioned filter initialised.");
|
||||
|
||||
|
@ -71,13 +71,16 @@ static void _persistent_filter_wipe(struct dev_filter *f)
|
||||
dm_hash_wipe(pf->devices);
|
||||
}
|
||||
|
||||
static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
void *l;
|
||||
struct dm_str_list *sl;
|
||||
int pass = 1;
|
||||
|
||||
if (use_filter_name && strcmp(f->name, use_filter_name))
|
||||
return pf->real->passes_filter(cmd, pf->real, dev, use_filter_name);
|
||||
|
||||
if (dm_list_empty(&dev->aliases)) {
|
||||
log_debug_devs("%d:%d: filter cache skipping (no name)",
|
||||
(int)MAJOR(dev->dev), (int)MINOR(dev->dev));
|
||||
@ -102,7 +105,7 @@ static int _lookup_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
if (!l) {
|
||||
dev->flags &= ~DEV_FILTER_AFTER_SCAN;
|
||||
|
||||
pass = pf->real->passes_filter(cmd, pf->real, dev);
|
||||
pass = pf->real->passes_filter(cmd, pf->real, dev, use_filter_name);
|
||||
|
||||
if (!pass) {
|
||||
/*
|
||||
@ -182,6 +185,7 @@ struct dev_filter *persistent_filter_create(struct dev_types *dt, struct dev_fil
|
||||
f->use_count = 0;
|
||||
f->private = pf;
|
||||
f->wipe = _persistent_filter_wipe;
|
||||
f->name = "persistent";
|
||||
|
||||
log_debug_devs("Persistent filter initialised.");
|
||||
|
||||
|
@ -145,7 +145,7 @@ static int _build_matcher(struct rfilter *rf, const struct dm_config_value *val)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
int m, first = 1, rejected = 0;
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
@ -212,6 +212,7 @@ struct dev_filter *regex_filter_create(const struct dm_config_value *patterns)
|
||||
f->destroy = _regex_destroy;
|
||||
f->use_count = 0;
|
||||
f->private = rf;
|
||||
f->name = "regex";
|
||||
|
||||
log_debug_devs("Regex filter initialised.");
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#define BUFSIZE 4096
|
||||
|
||||
static int _ignore_signature(struct cmd_context *cmd, struct dev_filter *f __attribute__((unused)),
|
||||
struct device *dev)
|
||||
struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
int ret = 0;
|
||||
@ -81,6 +81,7 @@ struct dev_filter *signature_filter_create(struct dev_types *dt)
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "signature";
|
||||
|
||||
log_debug_devs("signature filter initialised.");
|
||||
|
||||
|
@ -260,7 +260,7 @@ static int _init_devs(struct dev_set *ds)
|
||||
}
|
||||
|
||||
|
||||
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_set *ds = (struct dev_set *) f->private;
|
||||
|
||||
@ -323,6 +323,7 @@ struct dev_filter *sysfs_filter_create(void)
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = ds;
|
||||
f->name = "sysfs";
|
||||
|
||||
log_debug_devs("Sysfs filter initialised.");
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
|
||||
static int _passes_lvm_type_device_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _passes_lvm_type_device_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct dev_types *dt = (struct dev_types *) f->private;
|
||||
const char *name = dev_name(dev);
|
||||
@ -53,6 +53,7 @@ struct dev_filter *lvm_type_filter_create(struct dev_types *dt)
|
||||
f->destroy = _lvm_type_filter_destroy;
|
||||
f->use_count = 0;
|
||||
f->private = dt;
|
||||
f->name = "type";
|
||||
|
||||
log_debug_devs("LVM type filter initialised.");
|
||||
|
||||
|
@ -105,7 +105,7 @@ static int _check_pv_min_size(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev)
|
||||
static int _passes_usable_filter(struct cmd_context *cmd, struct dev_filter *f, struct device *dev, const char *use_filter_name)
|
||||
{
|
||||
struct filter_data *data = f->private;
|
||||
filter_mode_t mode = data->mode;
|
||||
@ -185,6 +185,7 @@ struct dev_filter *usable_filter_create(struct cmd_context *cmd, struct dev_type
|
||||
f->passes_filter = _passes_usable_filter;
|
||||
f->destroy = _usable_filter_destroy;
|
||||
f->use_count = 0;
|
||||
f->name = "usable";
|
||||
|
||||
if (!(data = zalloc(sizeof(struct filter_data)))) {
|
||||
log_error("Usable device filter mode allocation failed");
|
||||
|
1241
lib/label/hints.c
Normal file
1241
lib/label/hints.c
Normal file
File diff suppressed because it is too large
Load Diff
37
lib/label/hints.h
Normal file
37
lib/label/hints.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2018 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_HINTS_H
|
||||
#define _LVM_HINTS_H
|
||||
|
||||
struct hint {
|
||||
struct dm_list list;
|
||||
char name[PATH_MAX];
|
||||
char pvid[ID_LEN + 1];
|
||||
char vgname[NAME_LEN];
|
||||
dev_t devt;
|
||||
unsigned chosen:1; /* this hint's dev was chosen for scanning */
|
||||
};
|
||||
|
||||
int write_hint_file(struct cmd_context *cmd, int newhints);
|
||||
|
||||
void clear_hint_file(struct cmd_context *cmd);
|
||||
|
||||
int get_hints(struct cmd_context *cmd, struct dm_list *hints, int *newhints,
|
||||
struct dm_list *devs_in, struct dm_list *devs_out);
|
||||
|
||||
int validate_hints(struct cmd_context *cmd, struct dm_list *hints);
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "lib/device/bcache.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/label/hints.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@ -358,6 +359,8 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
int ret = 0;
|
||||
int pass;
|
||||
|
||||
dev->flags &= ~DEV_SCAN_FOUND_LABEL;
|
||||
|
||||
/*
|
||||
* The device may have signatures that exclude it from being processed.
|
||||
* If filters were applied before bcache data was available, some
|
||||
@ -370,7 +373,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
|
||||
log_debug_devs("Scan filtering %s", dev_name(dev));
|
||||
|
||||
pass = f->passes_filter(cmd, f, dev);
|
||||
pass = f->passes_filter(cmd, f, dev, NULL);
|
||||
|
||||
if ((pass == -EAGAIN) || (dev->flags & DEV_FILTER_AFTER_SCAN)) {
|
||||
/* Shouldn't happen */
|
||||
@ -412,6 +415,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
|
||||
goto_out;
|
||||
}
|
||||
|
||||
dev->flags |= DEV_SCAN_FOUND_LABEL;
|
||||
*is_lvm_device = 1;
|
||||
|
||||
/*
|
||||
@ -827,6 +831,16 @@ static int _setup_bcache(int cache_blocks)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _free_hints(struct dm_list *hints)
|
||||
{
|
||||
struct hint *hint, *hint2;
|
||||
|
||||
dm_list_iterate_items_safe(hint, hint2, hints) {
|
||||
dm_list_del(&hint->list);
|
||||
free(hint);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan and cache lvm data from all devices on the system.
|
||||
* The cache should be empty/reset before calling this.
|
||||
@ -835,13 +849,18 @@ static int _setup_bcache(int cache_blocks)
|
||||
int label_scan(struct cmd_context *cmd)
|
||||
{
|
||||
struct dm_list all_devs;
|
||||
struct dm_list scan_devs;
|
||||
struct dm_list hints;
|
||||
struct dev_iter *iter;
|
||||
struct device_list *devl, *devl2;
|
||||
struct device *dev;
|
||||
int newhints = 0;
|
||||
|
||||
log_debug_devs("Finding devices to scan");
|
||||
|
||||
dm_list_init(&all_devs);
|
||||
dm_list_init(&scan_devs);
|
||||
dm_list_init(&hints);
|
||||
|
||||
/*
|
||||
* Iterate through all the devices in dev-cache (block devs that appear
|
||||
@ -889,20 +908,64 @@ 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) {
|
||||
if (!_setup_bcache(dm_list_size(&all_devs)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
_scan_list(cmd, cmd->filter, &all_devs, NULL);
|
||||
/*
|
||||
* In some common cases we can avoid scanning all devices.
|
||||
*
|
||||
* TODO: if the command is using hints and a single vgname
|
||||
* arg, we can also take the vg lock here, prior to scanning.
|
||||
* This means we would not need to rescan the PVs in the VG
|
||||
* in vg_read (skip lvmcache_label_rescan_vg) after the
|
||||
* vg lock is usually taken. (Some commands are already
|
||||
* able to avoid rescan in vg_read, but locking early would
|
||||
* apply to more cases.)
|
||||
*/
|
||||
if (!get_hints(cmd, &hints, &newhints, &all_devs, &scan_devs))
|
||||
dm_list_splice(&scan_devs, &all_devs);
|
||||
|
||||
log_debug("Will scan %d devices skip %d", dm_list_size(&scan_devs), dm_list_size(&all_devs));
|
||||
|
||||
/*
|
||||
* Do the main scan.
|
||||
*/
|
||||
_scan_list(cmd, cmd->filter, &scan_devs, NULL);
|
||||
|
||||
dm_list_init(&cmd->hints);
|
||||
|
||||
if (!dm_list_empty(&hints)) {
|
||||
if (!validate_hints(cmd, &hints)) {
|
||||
/*
|
||||
* We scanned a subset of all devices based on hints.
|
||||
* With the results from the scan we may decide that
|
||||
* the hints are not valid, so scan all others.
|
||||
*/
|
||||
log_debug("Will scan %d remaining devices", dm_list_size(&all_devs));
|
||||
_scan_list(cmd, cmd->filter, &all_devs, NULL);
|
||||
_free_hints(&hints);
|
||||
newhints = 0;
|
||||
} else {
|
||||
/* The hints may be used by another device iteration. */
|
||||
dm_list_splice(&cmd->hints, &hints);
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items_safe(devl, devl2, &all_devs) {
|
||||
dm_list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
|
||||
dm_list_iterate_items_safe(devl, devl2, &scan_devs) {
|
||||
dm_list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
|
||||
if (newhints)
|
||||
write_hint_file(cmd, newhints);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
377
test/shell/hints.sh
Normal file
377
test/shell/hints.sh
Normal file
@ -0,0 +1,377 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
/* hints are currently disabled with lvmlockd */
|
||||
SKIP_WITH_LVMLOCKD=1
|
||||
|
||||
RUNDIR="/run"
|
||||
test -d "$RUNDIR" || RUNDIR="/var/run"
|
||||
HINTS="$RUNDIR/lvm/hints"
|
||||
NOHINTS="$RUNDIR/lvm/nohints"
|
||||
NEWHINTS="$RUNDIR/lvm/newhints"
|
||||
PREV="$RUNDIR/lvm/prev-hints"
|
||||
|
||||
. lib/inittest
|
||||
|
||||
# TODO:
|
||||
# Test commands that ignore hints
|
||||
# Test flock
|
||||
|
||||
|
||||
aux lvmconf 'devices/scan_lvs = 0'
|
||||
|
||||
aux prepare_devs 6
|
||||
|
||||
# no PVs yet so hints should have no devs
|
||||
pvs
|
||||
not grep scan: $HINTS
|
||||
|
||||
#
|
||||
# vg1 uses dev1,dev2
|
||||
#
|
||||
# Test basics that PVs are in hints, not non-PV devs,
|
||||
# and that only PVs are scanned when using hints.
|
||||
#
|
||||
|
||||
vgcreate $vg1 "$dev1" "$dev2"
|
||||
lvcreate -n $lv1 -l 4 $vg1
|
||||
|
||||
# test that only the two PVs are in hints
|
||||
pvs
|
||||
grep -v -E "$dev1|$dev2" $HINTS > tmptest
|
||||
not grep scan: tmptest
|
||||
|
||||
# test that 'pvs' submits only two reads, one for each PV in hints
|
||||
strace -e io_submit pvs 2>&1|tee tmptest
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 2
|
||||
|
||||
# test that 'pvs -a' submits six reads, one for each device
|
||||
strace -e io_submit pvs -a 2>&1|tee tmptest
|
||||
test "$(grep io_submit tmptest | wc -l)" -eq 6
|
||||
|
||||
#
|
||||
# vg2 uses dev3,dev4
|
||||
#
|
||||
# Test common commands that cause hints to be refreshed:
|
||||
# pvcreate/vgcreate/vgextend/vgreduce/vgremove/pvremove
|
||||
#
|
||||
|
||||
not pvs "$dev3"
|
||||
not grep "$dev3" $HINTS
|
||||
cp $HINTS $PREV
|
||||
pvcreate "$dev3"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
pvs "$dev3"
|
||||
grep "$dev3" $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
not vgs $vg2
|
||||
cp $HINTS $PREV
|
||||
vgcreate $vg2 "$dev3"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
vgs $vg2
|
||||
grep $vg2 $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
cp $HINTS $PREV
|
||||
vgextend $vg2 "$dev4"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
vgs $vg2
|
||||
grep "$dev4" $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
cp $HINTS $PREV
|
||||
vgreduce $vg2 "$dev4"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
vgs $vg2
|
||||
grep "$dev4" $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
cp $HINTS $PREV
|
||||
vgremove $vg2
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
not vgs $vg2
|
||||
not grep $vg2 $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
cp $HINTS $PREV
|
||||
pvremove "$dev3" "$dev4"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# next cmd recreates hints
|
||||
not pvs "$dev3"
|
||||
not pvs "$dev4"
|
||||
not grep "$dev3" $HINTS
|
||||
not grep "$dev4" $HINTS
|
||||
not diff $HINTS $PREV
|
||||
not cat $NEWHINTS
|
||||
|
||||
#
|
||||
# Test that adding a new device and removing a device
|
||||
# causes hints to be recreated.
|
||||
#
|
||||
|
||||
not pvs "$dev5"
|
||||
|
||||
# create a new temp device that will cause hint hash to change
|
||||
DEVNAME=${PREFIX}pv99
|
||||
echo "0 `blockdev --getsize $dev5` linear $dev5 0" | dmsetup create $DEVNAME
|
||||
dmsetup status $DEVNAME
|
||||
|
||||
cp $HINTS $PREV
|
||||
# pvs ignores current hints because of different dev hash and refreshes new hints
|
||||
pvs
|
||||
# devs listed in hints before and after are the same
|
||||
grep scan: $PREV > scan1
|
||||
grep scan: $HINTS > scan2
|
||||
diff scan1 scan2
|
||||
# hash listed before and after are different
|
||||
cat $PREV
|
||||
cat $HINTS
|
||||
grep devs_hash $PREV > devs_hash1
|
||||
grep devs_hash $HINTS > devs_hash2
|
||||
not diff devs_hash1 devs_hash2
|
||||
|
||||
# hints are stable/unchanging
|
||||
cp $HINTS $PREV
|
||||
pvs
|
||||
diff $HINTS $PREV
|
||||
|
||||
# remove the temp device which will cause hint hash to change again
|
||||
dmsetup remove $DEVNAME
|
||||
|
||||
cp $HINTS $PREV
|
||||
# pvs ignores current hints because of different dev hash and refreshes new hints
|
||||
pvs
|
||||
# devs listed in hints before and after are the same
|
||||
grep scan: $PREV > scan1
|
||||
grep scan: $HINTS > scan2
|
||||
diff scan1 scan2
|
||||
# hash listed before and after are different
|
||||
grep devs_hash $PREV > devs_hash1
|
||||
grep devs_hash $HINTS > devs_hash2
|
||||
not diff devs_hash1 devs_hash2
|
||||
|
||||
#
|
||||
# Test that hints don't change from a bunch of commands
|
||||
# that use hints and shouldn't change it.
|
||||
#
|
||||
|
||||
# first create some more metadata using vg2
|
||||
pvcreate "$dev3" "$dev4"
|
||||
vgcreate $vg2 "$dev3"
|
||||
lvcreate -n $lv1 -l1 $vg2
|
||||
lvcreate -n $lv2 -l1 $vg2
|
||||
|
||||
cp $HINTS $PREV
|
||||
lvm fullreport
|
||||
lvchange -ay $vg1
|
||||
lvchange -an $vg1
|
||||
lvcreate -l1 -n $lv2 $vg1
|
||||
lvcreate -l1 -an -n $lv3 $vg1
|
||||
lvchange -an $vg1
|
||||
lvremove $vg1/$lv3
|
||||
lvresize -l+1 $vg1/$lv2
|
||||
lvresize -l-1 $vg1/$lv2
|
||||
lvdisplay
|
||||
pvdisplay
|
||||
vgdisplay
|
||||
lvs
|
||||
pvs
|
||||
vgs
|
||||
vgchange -ay $vg2
|
||||
vgchange -an $vg2
|
||||
vgck $vg2
|
||||
lvrename $vg1 $lv2 $lv3
|
||||
# no change in hints after all that
|
||||
diff $HINTS $PREV
|
||||
|
||||
#
|
||||
# Test that changing the filter will cause hint refresh
|
||||
#
|
||||
|
||||
rm $HINTS $PREV
|
||||
vgs
|
||||
cp $HINTS $PREV
|
||||
# this changes the filter to exclude dev5 which is not a PV
|
||||
aux hide_dev "$dev5"
|
||||
# next cmd sees different filter, ignores hints, creates new hints
|
||||
pvs
|
||||
not diff $HINTS $PREV
|
||||
# run cmds using new filter
|
||||
pvs
|
||||
cp $HINTS $PREV
|
||||
vgs
|
||||
# hints are stable once refreshed
|
||||
diff $HINTS $PREV
|
||||
# this changes the filter to include dev5
|
||||
aux unhide_dev "$dev5"
|
||||
# next cmd sees different filter, ignores hints, creates new hints
|
||||
pvs
|
||||
not diff $HINTS $PREV
|
||||
# hints are stable
|
||||
cp $HINTS $PREV
|
||||
vgs
|
||||
diff $HINTS $PREV
|
||||
|
||||
#
|
||||
# Test that changing scan_lvs will cause hint refresh
|
||||
#
|
||||
|
||||
rm $HINTS $PREV
|
||||
vgs
|
||||
cp $HINTS $PREV
|
||||
# change lvm.conf
|
||||
aux lvmconf 'devices/scan_lvs = 1'
|
||||
# next cmd sees new setting, ignores hints, creates new hints
|
||||
pvs
|
||||
not diff $HINTS $PREV
|
||||
# run cmds using new filter
|
||||
pvs
|
||||
cp $HINTS $PREV
|
||||
vgs
|
||||
# hints are stable once refreshed
|
||||
diff $HINTS $PREV
|
||||
# change lvm.conf back
|
||||
aux lvmconf 'devices/scan_lvs = 0'
|
||||
# next cmd sees different scan_lvs, ignores hints, creates new hints
|
||||
pvs
|
||||
not diff $HINTS $PREV
|
||||
# hints are stable once refreshed
|
||||
cp $HINTS $PREV
|
||||
pvs
|
||||
diff $HINTS $PREV
|
||||
|
||||
#
|
||||
# Test pvscan --cache to force hints refresh
|
||||
#
|
||||
|
||||
# pvs (no change), pvscan (hints are new), pvs (no change)
|
||||
pvs
|
||||
cp $HINTS $PREV
|
||||
diff $HINTS $PREV
|
||||
cp $HINTS $PREV
|
||||
pvscan --cache
|
||||
not diff $HINTS $PREV
|
||||
cp $HINTS $PREV
|
||||
pvs
|
||||
diff $HINTS $PREV
|
||||
grep 'Created by pvscan' $HINTS
|
||||
# dev4 is a PV not used by a VG, dev5 is not a PV
|
||||
# using dd to copy skirts hint tracking so dev5 won't be seen
|
||||
dd if="$dev4" of="$dev5" bs=1M
|
||||
# this pvs won't see dev5
|
||||
pvs > foo
|
||||
cat foo
|
||||
grep "$dev4" foo
|
||||
not grep "$dev5" foo
|
||||
# no hints have changed after dd and pvs since dd cannot be detected
|
||||
diff $HINTS $PREV
|
||||
# force hints refresh, will see duplicate now
|
||||
pvscan --cache
|
||||
not diff $HINTS $PREV
|
||||
cat $HINTS
|
||||
pvs -a > foo
|
||||
# after force refresh, both devs (dups) appear in output
|
||||
cat foo
|
||||
grep "$dev4" foo
|
||||
grep "$dev5" foo
|
||||
# clear PV from dev5
|
||||
dd if=/dev/zero of="$dev5" bs=1M count=1
|
||||
# this pvs won't use hints because of duplicate PVs,
|
||||
# and will create new hints
|
||||
cp $HINTS $PREV
|
||||
pvs > foo
|
||||
not diff $HINTS $PREV
|
||||
grep "$dev4" foo
|
||||
not grep "$dev5" foo
|
||||
grep "$dev4" $HINTS
|
||||
not grep "$dev5" $HINTS
|
||||
|
||||
|
||||
#
|
||||
# Test incorrect dev-to-pvid info in hints is detected
|
||||
# dev4 is a PV not in a VG
|
||||
#
|
||||
|
||||
pvs
|
||||
cp $HINTS tmp-old
|
||||
# this pvchange will invalidate current hints
|
||||
pvchange -u "$dev4"
|
||||
grep "# Created empty" $HINTS
|
||||
cat $NEWHINTS
|
||||
# this next pvs will create new hints with the new uuid
|
||||
pvs
|
||||
grep "$dev4" $HINTS > tmp-newuuid
|
||||
cp $HINTS tmp-new
|
||||
not diff tmp-old tmp-new
|
||||
# hints are stable
|
||||
pvs
|
||||
diff $HINTS tmp-new
|
||||
# replace the current hints with the old hints with the old uuid
|
||||
cp tmp-old $HINTS
|
||||
# this next pvs will see wrong dev-to-pvid mapping and invalidate hints
|
||||
pvs
|
||||
cat $HINTS
|
||||
cat $NEWHINTS
|
||||
# this next pvs will create new hints with the new uuid
|
||||
pvs
|
||||
cat $HINTS
|
||||
grep -f tmp-newuuid $HINTS
|
||||
rm tmp-old tmp-new tmp-newuuid
|
||||
|
||||
|
||||
#
|
||||
# Test incorrent pvid-to-vgname info in hints is detected
|
||||
#
|
||||
|
||||
# this vgcreate invalidates current hints
|
||||
vgcreate $vg3 $dev4
|
||||
# this pvs creates new hints
|
||||
pvs
|
||||
cp $HINTS tmp-old
|
||||
# this vgrename will invalidate current hints
|
||||
vgrename $vg3 $vg4
|
||||
# this pvs will create new hints with the new vg name
|
||||
pvs
|
||||
cp $HINTS tmp-new
|
||||
not diff tmp-old tmp-new
|
||||
# replace the current hints with the old hints with the old vg name
|
||||
cp tmp-old $HINTS
|
||||
# this pvs will see wrong pvid-to-vgname mapping and invalidate hints
|
||||
pvs
|
||||
cat $NEWHINTS
|
||||
# this pvs will create new hints with the new vg name
|
||||
pvs
|
||||
grep $vg4 $HINTS
|
||||
|
||||
vgremove -y $vg4
|
||||
vgremove -y $vg2
|
||||
vgremove -y $vg1
|
||||
|
@ -55,7 +55,7 @@ check pv_field "$dev2" dev_size "$SIZE2"
|
||||
|
||||
# Copy dev1 over dev2.
|
||||
dd if="$dev1" of="$dev2" bs=1M iflag=direct oflag=direct,sync
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
# The single preferred dev is shown from 'pvs'.
|
||||
pvs -o+uuid,duplicate 2>&1 | tee out
|
||||
@ -292,7 +292,7 @@ grep "$dev3" out
|
||||
grep "$dev4" out
|
||||
|
||||
dd if="$dev3" of="$dev4" bs=1M iflag=direct oflag=direct,sync
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
# One appears with 'pvs'
|
||||
|
||||
@ -375,7 +375,7 @@ check pv_field "$dev4" dev_size "$SIZE4"
|
||||
|
||||
dd if=/dev/zero of="$dev3" bs=1M oflag=direct,sync || true
|
||||
dd if=/dev/zero of="$dev4" bs=1M oflag=direct,sync || true
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
# The previous steps prevent us from nicely cleaning up
|
||||
# the vg lockspace in lvmlockd, so just restart it;
|
||||
@ -392,6 +392,9 @@ lvcreate -l1 -n $lv2 $vg2 "$dev4"
|
||||
|
||||
dd if="$dev3" of="$dev5" bs=1M iflag=direct oflag=direct,sync
|
||||
dd if="$dev4" of="$dev6" bs=1M iflag=direct oflag=direct,sync
|
||||
# dev5/dev6 not pvs so dd'ing pv onto them causes invalid hints
|
||||
# that won't be detected, so 5/6 won't be scanned unless we
|
||||
# force hint recreation
|
||||
pvscan --cache
|
||||
|
||||
pvs -o+uuid,duplicate 2>&1 | tee out
|
||||
@ -450,7 +453,7 @@ not grep "prefers device $dev6" warn
|
||||
|
||||
dd if=/dev/zero of="$dev5" bs=1M oflag=direct,sync || true
|
||||
dd if=/dev/zero of="$dev6" bs=1M oflag=direct,sync || true
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
lvremove -y $vg2/$lv1
|
||||
lvremove -y $vg2/$lv2
|
||||
@ -460,7 +463,7 @@ pvremove -ff -y "$dev4"
|
||||
|
||||
dd if=/dev/zero of="$dev3" bs=1M oflag=direct,sync || true
|
||||
dd if=/dev/zero of="$dev4" bs=1M oflag=direct,sync || true
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
# Reverse devs in the previous in case dev3/dev4 would be
|
||||
# preferred even without an active LV using them.
|
||||
@ -471,6 +474,9 @@ lvcreate -l1 -n $lv2 $vg2 "$dev6"
|
||||
|
||||
dd if="$dev5" of="$dev3" bs=1M iflag=direct oflag=direct,sync
|
||||
dd if="$dev6" of="$dev4" bs=1M iflag=direct oflag=direct,sync
|
||||
# dev3/dev4 are not pvs (zeroed above) so dd'ing pv onto them causes
|
||||
# invalid hints that won't be detected, so 3/4 won't be scanned
|
||||
# unless we force hint recreation
|
||||
pvscan --cache
|
||||
|
||||
pvs -o+uuid,duplicate 2>&1 | tee out
|
||||
@ -506,7 +512,7 @@ not grep "prefers device $dev4" warn
|
||||
|
||||
dd if=/dev/zero of="$dev3" bs=1M oflag=direct,sync || true
|
||||
dd if=/dev/zero of="$dev4" bs=1M oflag=direct,sync || true
|
||||
pvscan --cache
|
||||
#pvscan --cache
|
||||
|
||||
lvremove -y $vg2/$lv1
|
||||
lvremove -y $vg2/$lv2
|
||||
|
@ -136,6 +136,8 @@ static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused))
|
||||
#define DISALLOW_TAG_ARGS 0x00000800
|
||||
#define GET_VGNAME_FROM_OPTIONS 0x00001000
|
||||
#define CAN_USE_ONE_SCAN 0x00002000
|
||||
#define ALLOW_HINTS 0x00004000
|
||||
|
||||
|
||||
/* create foo_CMD enums for command def ID's in command-lines.in */
|
||||
|
||||
|
@ -35,7 +35,7 @@ xx(help,
|
||||
|
||||
xx(fullreport,
|
||||
"Display full report",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS)
|
||||
|
||||
xx(lastlog,
|
||||
"Display last command's log report",
|
||||
@ -43,7 +43,7 @@ xx(lastlog,
|
||||
|
||||
xx(lvchange,
|
||||
"Change the attributes of logical volume(s)",
|
||||
PERMITTED_READ_ONLY)
|
||||
PERMITTED_READ_ONLY | ALLOW_HINTS)
|
||||
|
||||
xx(lvconvert,
|
||||
"Change logical volume layout",
|
||||
@ -51,15 +51,15 @@ xx(lvconvert,
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(lvdisplay,
|
||||
"Display information about a logical volume",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
xx(lvextend,
|
||||
"Add space to a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(lvmchange,
|
||||
"With the device mapper, this is obsolete and does nothing.",
|
||||
@ -83,23 +83,23 @@ xx(lvmsar,
|
||||
|
||||
xx(lvreduce,
|
||||
"Reduce the size of a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(lvremove,
|
||||
"Remove logical volume(s) from the system",
|
||||
ALL_VGS_IS_DEFAULT) /* all VGs only with --select */
|
||||
ALL_VGS_IS_DEFAULT | ALLOW_HINTS) /* all VGs only with --select */
|
||||
|
||||
xx(lvrename,
|
||||
"Rename a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(lvresize,
|
||||
"Resize a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(lvs,
|
||||
"Display information about logical volumes",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
xx(lvscan,
|
||||
"List all logical volumes in all volume groups",
|
||||
@ -127,7 +127,7 @@ xx(pvdata,
|
||||
|
||||
xx(pvdisplay,
|
||||
"Display various attributes of physical volume(s)",
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
|
||||
|
||||
@ -137,7 +137,7 @@ xx(pvmove,
|
||||
|
||||
xx(lvpoll,
|
||||
"Continue already initiated poll operation on a logical volume",
|
||||
0)
|
||||
ALLOW_HINTS)
|
||||
|
||||
xx(pvremove,
|
||||
"Remove LVM label(s) from physical volume(s)",
|
||||
@ -145,7 +145,7 @@ xx(pvremove,
|
||||
|
||||
xx(pvs,
|
||||
"Display information about physical volumes",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ENABLE_ALL_DEVS | ENABLE_DUPLICATE_DEVS | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
xx(pvscan,
|
||||
"List all physical volumes",
|
||||
@ -173,11 +173,11 @@ xx(vgcfgrestore,
|
||||
|
||||
xx(vgchange,
|
||||
"Change volume group attributes",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | ALLOW_HINTS)
|
||||
|
||||
xx(vgck,
|
||||
"Check the consistency of volume group(s)",
|
||||
ALL_VGS_IS_DEFAULT | LOCKD_VG_SH)
|
||||
ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | ALLOW_HINTS)
|
||||
|
||||
xx(vgconvert,
|
||||
"Change volume group metadata format",
|
||||
@ -189,7 +189,7 @@ xx(vgcreate,
|
||||
|
||||
xx(vgdisplay,
|
||||
"Display volume group information",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
xx(vgexport,
|
||||
"Unregister volume group(s) from the system",
|
||||
@ -228,7 +228,7 @@ xx(vgrename,
|
||||
|
||||
xx(vgs,
|
||||
"Display information about volume groups",
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN)
|
||||
PERMITTED_READ_ONLY | ALL_VGS_IS_DEFAULT | LOCKD_VG_SH | CAN_USE_ONE_SCAN | ALLOW_HINTS)
|
||||
|
||||
xx(vgscan,
|
||||
"Search for all volume groups",
|
||||
|
@ -2286,6 +2286,7 @@ static void _apply_current_output_settings(struct cmd_context *cmd)
|
||||
static int _get_current_settings(struct cmd_context *cmd)
|
||||
{
|
||||
const char *activation_mode;
|
||||
const char *hint_mode;
|
||||
|
||||
_get_current_output_settings_from_args(cmd);
|
||||
|
||||
@ -2313,6 +2314,29 @@ static int _get_current_settings(struct cmd_context *cmd)
|
||||
if (cmd->cname->flags & CAN_USE_ONE_SCAN)
|
||||
cmd->can_use_one_scan = 1;
|
||||
|
||||
cmd->scan_lvs = find_config_tree_bool(cmd, devices_scan_lvs_CFG, NULL);
|
||||
|
||||
/*
|
||||
* enable_hints is set to 1 if any commands are using hints.
|
||||
* use_hints is set to 1 if this command doesn't use the hints.
|
||||
* enable_hints=1 and use_hints=0 means that this command won't
|
||||
* use the hints, but it may invalidate the hints that are used
|
||||
* by other commands.
|
||||
*
|
||||
* enable_hints=0 means no commands are using hints, so this
|
||||
* command would not need to invalidate hints for other cmds.
|
||||
*/
|
||||
cmd->enable_hints = 1;
|
||||
|
||||
/* Only certain commands need to be optimized by using hints. */
|
||||
if (cmd->cname->flags & ALLOW_HINTS)
|
||||
cmd->use_hints = 1;
|
||||
|
||||
if ((hint_mode = find_config_tree_str(cmd, devices_hints_CFG, NULL))) {
|
||||
if (!strcmp(hint_mode, "none"))
|
||||
cmd->enable_hints = 0;
|
||||
}
|
||||
|
||||
cmd->partial_activation = 0;
|
||||
cmd->degraded_activation = 0;
|
||||
activation_mode = find_config_tree_str(cmd, activation_mode_CFG, NULL);
|
||||
@ -2688,6 +2712,12 @@ static int _init_lvmlockd(struct cmd_context *cmd)
|
||||
const char *lvmlockd_socket;
|
||||
int use_lvmlockd = find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL);
|
||||
|
||||
/*
|
||||
* Think about when/how to enable hints with lvmlockd.
|
||||
*/
|
||||
if (use_lvmlockd)
|
||||
cmd->enable_hints = 0;
|
||||
|
||||
if (use_lvmlockd && arg_is_set(cmd, nolocking_ARG)) {
|
||||
/* --nolocking is only allowed with vgs/lvs/pvs commands */
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
@ -252,6 +252,8 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
set_pv_notify(cmd);
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
ret = process_each_pv(cmd, argc, argv, NULL, 0, READ_FOR_UPDATE | READ_ALLOW_EXPORTED, handle, _pvchange_single);
|
||||
|
||||
if (!argc)
|
||||
|
@ -148,6 +148,8 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
return_ECMD_FAILED;
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
if (!(handle = init_processing_handle(cmd, NULL))) {
|
||||
log_error("Failed to initialize processing handle.");
|
||||
return ECMD_FAILED;
|
||||
|
@ -93,6 +93,13 @@ int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Without -a, command only looks at PVs and can use hints,
|
||||
* with -a, the command looks at all (non-hinted) devices.
|
||||
*/
|
||||
if (arg_is_set(cmd, all_ARG))
|
||||
cmd->use_hints = 0;
|
||||
|
||||
ret = process_each_pv(cmd, argc, argv, NULL,
|
||||
arg_is_set(cmd, all_ARG), 0,
|
||||
NULL, _pvdisplay_single);
|
||||
|
@ -48,6 +48,8 @@ int pvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
/* When forcibly clearing a PV we don't care about a VG lock. */
|
||||
if (pp.force == DONT_PROMPT_OVERRIDE)
|
||||
cmd->lockd_vg_disable = 1;
|
||||
|
@ -656,6 +656,15 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
* Scan all devices when no args are given.
|
||||
*/
|
||||
if (!argc && !devno_args) {
|
||||
/*
|
||||
* pvscan --cache removes existing hints and recreates new ones.
|
||||
* We begin by clearing hints at the start of the command like
|
||||
* vgcreate would do. The pvscan_recreate_hints flag is used
|
||||
* to enable the special case hint recreation in label_scan.
|
||||
*/
|
||||
cmd->pvscan_recreate_hints = 1;
|
||||
clear_hint_file(cmd);
|
||||
|
||||
log_verbose("pvscan all devices.");
|
||||
_online_pvid_files_remove();
|
||||
_online_pvscan_all_devs(cmd, NULL, NULL);
|
||||
|
@ -1456,6 +1456,13 @@ int pvs(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
report_type_t type;
|
||||
|
||||
/*
|
||||
* Without -a, command only looks at PVs and can use hints,
|
||||
* with -a, the command looks at all (non-hinted) devices.
|
||||
*/
|
||||
if (arg_is_set(cmd, all_ARG))
|
||||
cmd->use_hints = 0;
|
||||
|
||||
if (arg_is_set(cmd, segments_ARG))
|
||||
type = PVSEGS;
|
||||
else
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "tools.h"
|
||||
#include "lib/format_text/format-text.h"
|
||||
#include "lib/label/hints.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
@ -3908,14 +3909,40 @@ static int _get_arg_devices(struct cmd_context *cmd,
|
||||
return ret_max;
|
||||
}
|
||||
|
||||
static int _get_all_devices(struct cmd_context *cmd, struct dm_list *all_devices)
|
||||
static int _get_all_devices(struct cmd_context *cmd,
|
||||
int process_all_devices,
|
||||
struct dm_list *all_devices)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct device_id_list *dil;
|
||||
struct hint *hint;
|
||||
int r = ECMD_FAILED;
|
||||
|
||||
log_debug("Getting list of all devices");
|
||||
/*
|
||||
* If command is using hints and is only looking for PVs
|
||||
* (not all devices), then we can use only devs from hints.
|
||||
*/
|
||||
if (!process_all_devices && !dm_list_empty(&cmd->hints)) {
|
||||
log_debug("Getting list of all devices from hints");
|
||||
|
||||
dm_list_iterate_items(hint, &cmd->hints) {
|
||||
if (!(dev = dev_cache_get(cmd, hint->name, NULL)))
|
||||
continue;
|
||||
|
||||
if (!(dil = dm_pool_alloc(cmd->mem, sizeof(*dil)))) {
|
||||
log_error("device_id_list alloc failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
strncpy(dil->pvid, hint->pvid, ID_LEN);
|
||||
dil->dev = dev;
|
||||
dm_list_add(all_devices, &dil->list);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_debug("Getting list of all devices from system");
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter, 1))) {
|
||||
log_error("dev_iter creation failed.");
|
||||
@ -4488,7 +4515,7 @@ int process_each_pv(struct cmd_context *cmd,
|
||||
* from all VGs are processed first, removing them from all_devices. Then
|
||||
* any devs remaining in all_devices are processed.
|
||||
*/
|
||||
if ((ret = _get_all_devices(cmd, &all_devices)) != ECMD_PROCESSED) {
|
||||
if ((ret = _get_all_devices(cmd, process_all_devices, &all_devices)) != ECMD_PROCESSED) {
|
||||
ret_max = ret;
|
||||
goto_out;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "toollib.h"
|
||||
#include "lib/notify/lvmnotify.h"
|
||||
#include "lib/label/hints.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
@ -133,6 +134,8 @@ struct arg_value_group_list {
|
||||
#define GET_VGNAME_FROM_OPTIONS 0x00001000
|
||||
/* The data read from disk by label scan can be used for vg_read. */
|
||||
#define CAN_USE_ONE_SCAN 0x00002000
|
||||
/* Command can use hints file */
|
||||
#define ALLOW_HINTS 0x00004000
|
||||
|
||||
|
||||
void usage(const char *name);
|
||||
|
@ -130,6 +130,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
lvmcache_label_scan(cmd);
|
||||
|
||||
cmd->handles_unknown_segments = 1;
|
||||
|
@ -64,6 +64,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
return_ECMD_FAILED;
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
/* Check for old md signatures at the end of devices. */
|
||||
cmd->use_full_md_check = 1;
|
||||
|
||||
|
@ -166,6 +166,8 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
return_ECMD_FAILED;
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
if (!(handle = init_processing_handle(cmd, NULL))) {
|
||||
log_error("Failed to initialize processing handle.");
|
||||
return ECMD_FAILED;
|
||||
|
@ -345,6 +345,8 @@ retry_name:
|
||||
*/
|
||||
cmd->lockd_vg_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
ret = process_each_vg(cmd, 0, NULL, vp.old_vgname, NULL, READ_FOR_UPDATE | READ_ALLOW_EXPORTED, 0, handle, _vgimportclone_vg_single);
|
||||
|
||||
unlock_vg(cmd, NULL, vp.new_vgname);
|
||||
|
@ -210,6 +210,8 @@ int vgmerge(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!lockd_gl(cmd, "ex", LDGL_UPDATE_NAMES))
|
||||
return ECMD_FAILED;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
|
||||
argc--;
|
||||
argv++;
|
||||
|
@ -224,6 +224,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
return_ECMD_FAILED;
|
||||
cmd->lockd_gl_disable = 1;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
if (!(handle = init_processing_handle(cmd, NULL))) {
|
||||
log_error("Failed to initialize processing handle.");
|
||||
return ECMD_FAILED;
|
||||
|
@ -101,6 +101,8 @@ int vgremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!lockd_gl(cmd, "ex", LDGL_UPDATE_NAMES))
|
||||
return ECMD_FAILED;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
/*
|
||||
* This is a special case: if vgremove is given a tag, it causes
|
||||
* process_each_vg to do lockd_gl(sh) when getting a list of all
|
||||
|
@ -195,6 +195,8 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!lockd_gl(cmd, "ex", LDGL_UPDATE_NAMES))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
/*
|
||||
* Special case where vg_name_old may be a UUID:
|
||||
* If vg_name_old is a UUID, then process_each may
|
||||
|
@ -569,6 +569,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!lockd_gl(cmd, "ex", LDGL_UPDATE_NAMES))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
clear_hint_file(cmd);
|
||||
|
||||
if (arg_is_set(cmd, name_ARG))
|
||||
lv_name = arg_value(cmd, name_ARG);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user