1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-12 07:33:16 +03:00

Compare commits

..

17 Commits

Author SHA1 Message Date
David Teigland
07338325e5 devices: fix name handling
- Fix cases where incorrect device paths were left
  on the dev->aliases list.  Leaving incorrect paths
  on dev->aliases could result in using the wrong device.

- Fix a widespread incorrect assumption that dev_name()
  always returns a valid path (or NULL).  dev_name()
  returns "[unknown]" when there are no paths to a
  device, and is mainly meant to be used in messages.

- Check for valid dev paths in cases that want to use
  the from dev_name() for things other than a message.
2022-02-24 15:37:53 -06:00
David Teigland
ac1f4bbbfd writecache: display block size from lvs
lvs was missing the ability to display writecache block size.
now possible with lvs -o writecache_block_size
2022-02-21 16:11:13 -06:00
David Teigland
6144dac897 man lvmcache: mention writecache memory usage 2022-02-21 11:35:58 -06:00
David Teigland
96c99d647e man: update cachesettings option description
to be more consistent with man page description
2022-02-16 15:37:54 -06:00
David Teigland
ec2119bedd man lvmcache: add more writecache cachesettings info 2022-02-16 15:21:09 -06:00
Zdenek Kabelac
d4a0816a58 dev_manager: use list info for preset devs
In some cases we can also use cached info obtained from DM_DEVICE_LIST
also to avoid extra ioctl check for present devices.
2022-02-16 01:00:36 +01:00
Zdenek Kabelac
fa7b67eeeb dev_manager: do not query for open_count
Oepn count is not used along this code path.
2022-02-16 01:00:36 +01:00
Zdenek Kabelac
4fd76de4b6 clang: possible better compilation with musl c
Try to help resolving reported compilation problem with
clang & musl C.
https://github.com/lvmteam/lvm2/issues/61
2022-02-16 01:00:36 +01:00
Zdenek Kabelac
d2e7a05573 clang: add extra check
Make clang happier.
2022-02-16 01:00:36 +01:00
Zdenek Kabelac
c2679f76e5 dev_manager: failing status is not internal error
Different target type for LV it's not an internal error.
i.e.  when target type is replaced with 'error' type - it should be
reported as regular warning and not cause interruption of command with
internall error.
2022-02-16 01:00:36 +01:00
Zdenek Kabelac
6ffb150f30 dev_manager: fix dm_task_get_device_list
With very old version of DM target driver we have to avoid
trying to use newuuid setting - otherwise we get error
during ioctl preparation phase.

Patch is fixing regression from commit:
988ea0e94c
2022-02-16 01:00:36 +01:00
David Teigland
6626adb467 tests: skip vgchange-pvs-online.sh on rhel5
the /dev/mapper/ paths to test devices don't seem to work there
2022-02-15 15:56:46 -06:00
David Teigland
d59382c772 devices file: do not clear PVID of unread devices
In a certain disconnected state, a block device is present on
the system, can be opened, reports a valid size, reports the
correct device id (wwid), and matches a devices file entry.
But, reading the device can still fail.  In this case,
device_ids_validate() was misinterpreting the read error as
the device having no data/label on it (and no PVID).
The validate function would then clear the PVID from the
devices file entry for the device, thinking that it was
fixing the devices file (making it consistent with the on disk
state.)  Fix this by not attempting to check and correct a
devices file entry that cannot be read.  Also make this case
explicit in the hints validation code (which was doing the
right thing but indirectly.)
2022-02-10 14:16:04 -06:00
David Teigland
61f23fe15e tests: udev-pvscan-vgchange fix service wait
As a result of removing -r from systemd-run in
commit fbd8b0cf43
this test needs to change how it handles the
transient services.
2022-02-07 16:44:57 -06:00
Zdenek Kabelac
13122bcc33 make: generate 2022-02-07 20:02:11 +01:00
Zdenek Kabelac
f83b3962c1 asan: fix some reports from libasan
When compiled and used with:

CFLAGS="-fsanitize=address -g -O0"
ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1

we have few reported issue - they where not normally spotted, since
we were still accessing our own memory - but ouf of buffer-range.

TODO: there is still something to enhance with handling of #orphan vgids
2022-02-07 20:02:11 +01:00
Marian Csontos
8dccc2314e post-release 2022-02-07 18:02:07 +01:00
43 changed files with 492 additions and 308 deletions

View File

@@ -1 +1 @@
2.03.15(2) (2022-02-07)
2.03.16(2)-git (2022-02-07)

View File

@@ -1 +1 @@
1.02.183 (2022-02-07)
1.02.185-git (2022-02-07)

View File

@@ -1,3 +1,6 @@
Version 2.03.16 -
====================================
Version 2.03.15 - 07th February 2022
====================================
Remove service based autoactivation. global/event_activation = 0 is NOOP.

View File

@@ -1,3 +1,6 @@
Version 1.02.185 -
=====================================
Version 1.02.183 - 07th February 2022
=====================================
Unmangle UUIDs for DM_DEVICE_LIST ioctl.

View File

@@ -1151,16 +1151,11 @@ global {
# lvdisplay_shows_full_device_path = 0
# Configuration option global/event_activation.
# Activate LVs based on system-generated device events.
# When a PV appears on the system, a system-generated uevent triggers
# the lvm2-pvscan service which runs the pvscan --cache -aay command.
# If the new PV completes a VG, pvscan autoactivates LVs in the VG.
# When event_activation is disabled, the lvm2-activation services are
# generated and run at fixed points during system startup. These
# services run vgchange -aay to autoactivate LVs in VGs that happen
# to be present at that point in time.
# See the --setautoactivation option or the auto_activation_volume_list
# setting to configure autoactivation for specific VGs or LVs.
# Disable event based autoactivation commands.
# WARNING: setting this to zero may cause machine startup to fail.
# Previously, setting this to zero would enable static autoactivation
# services (via the lvm2-activation-generator), but the autoactivation
# services and generator have been removed.
# This configuration option has an automatic default value.
# event_activation = 1

View File

@@ -107,6 +107,8 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
int with_flush,
int query_inactive)
{
char vsn[80];
unsigned maj, min;
struct dm_task *dmt;
if (!(dmt = dm_task_create(task)))
@@ -142,7 +144,11 @@ static struct dm_task *_setup_task_run(int task, struct dm_info *info,
case DM_DEVICE_TARGET_MSG:
return dmt; /* TARGET_MSG needs more local tweaking before task_run() */
case DM_DEVICE_LIST:
if (!dm_task_set_newuuid(dmt, " ")) // new uuid has no meaning here
/* Use 'newuuid' only with DM version that supports it */
if (driver_version(vsn, sizeof(vsn)) &&
(sscanf(vsn, "%u.%u", &maj, &min) == 2) &&
(maj == 4 ? min >= 19 : maj > 4) &&
!dm_task_set_newuuid(dmt, " ")) // new uuid has no meaning here
log_warn("WARNING: Failed to query uuid with LIST.");
break;
default:
@@ -198,7 +204,7 @@ static int _get_segment_status_from_target_params(const char *target_name,
/* If kernel's type isn't an exact match is it compatible? */
(!segtype->ops->target_status_compatible ||
!segtype->ops->target_status_compatible(target_name))) {
log_warn(INTERNAL_ERROR "WARNING: Segment type %s found does not match expected type %s for %s.",
log_warn("WARNING: Detected %s segment type does not match expected type %s for %s.",
target_name, segtype->name, display_lvname(seg_status->seg->lv));
return 0;
}
@@ -2248,6 +2254,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
{
char *dlid, *name;
struct dm_info info, info2;
const struct dm_active_device *dev;
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, lv->name, layer)))
return_0;
@@ -2256,15 +2263,20 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
if (!dm->cmd->disable_dm_devs &&
dm->cmd->cache_dm_devs &&
!dm_device_list_find_by_uuid(dm->cmd->cache_dm_devs, dlid, NULL)) {
log_debug("Cached as not present %s.", name);
return 1;
}
if (!_info(dm->cmd, name, dlid, 1, 0, 0, &info, NULL, NULL))
dm->cmd->cache_dm_devs) {
if (!dm_device_list_find_by_uuid(dm->cmd->cache_dm_devs, dlid, &dev)) {
log_debug("Cached as not present %s.", name);
return 1;
}
info = (struct dm_info) {
.exists = 1,
.major = dev->major,
.minor = dev->minor,
};
log_debug("Cached as present %s %s (%d:%d).",
name, dlid, info.major, info.minor);
} else if (!_info(dm->cmd, name, dlid, 0, 0, 0, &info, NULL, NULL))
return_0;
/*
* For top level volumes verify that existing device match
* requested major/minor and that major/minor pair is available for use
@@ -2935,6 +2947,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
/* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
for (s = start_area; s < areas; s++) {
/* FIXME: dev_name() does not return NULL! It needs to check if dm_list_empty(&dev->aliases)
but this knot of logic is too complex to pull apart without careful deconstruction. */
if ((seg_type(seg, s) == AREA_PV &&
(!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) ||
!(name = dev_name(seg_dev(seg, s))) || !*name ||
@@ -2953,7 +2969,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg,
return_0;
num_error_areas++;
} else if (seg_type(seg, s) == AREA_PV) {
if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL,
struct device *dev = seg_dev(seg, s);
name = dm_list_empty(&dev->aliases) ? NULL : dev_name(dev);
if (!dm_tree_node_add_target_area(node, name, NULL,
(seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s)))))
return_0;
num_existing_areas++;

View File

@@ -522,7 +522,9 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (!(dev->flags & DEV_REGULAR) || size2)
use_plain_read = 0;
if (!(buf = zalloc(size + size2))) {
/* Ensure there is extra '\0' after end of buffer since we pass
* buffer to funtions like strtoll() */
if (!(buf = zalloc(size + size2 + 1))) {
log_error("Failed to allocate circular buffer.");
return 0;
}

View File

@@ -351,7 +351,7 @@ static int _add_alias(struct device *dev, const char *path, enum add_hash hash)
goto out;
}
if (!(path = dm_pool_strdup(_cache.mem, path)) ||
if (!(path = _strdup(path)) ||
!(sl = _zalloc(sizeof(*sl)))) {
log_error("Failed to add allias to dev cache.");
return 0;
@@ -1162,6 +1162,17 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
static void _drop_all_aliases(struct device *dev)
{
struct dm_str_list *strl, *strl2;
dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
log_debug("Drop alias for %d:%d %s.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str);
dm_hash_remove(_cache.names, strl->str);
dm_list_del(&strl->list);
}
}
void dev_cache_scan(struct cmd_context *cmd)
{
log_debug_devs("Creating list of system devices.");
@@ -1371,59 +1382,6 @@ int dev_cache_add_dir(const char *path)
return 1;
}
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
const char *dev_name_confirmed(struct device *dev, int quiet)
{
struct stat buf;
const char *name;
int r;
if ((dev->flags & DEV_REGULAR))
return dev_name(dev);
while ((r = stat(name = dm_list_item(dev->aliases.n,
struct dm_str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
if (r < 0) {
if (quiet)
log_sys_debug("stat", name);
else
log_sys_error("stat", name);
}
if (quiet)
log_debug_devs("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
else
log_warn("Path %s no longer valid for device(%d,%d)",
name, (int) MAJOR(dev->dev),
(int) MINOR(dev->dev));
/* Remove the incorrect hash entry */
dm_hash_remove(_cache.names, name);
/* Leave list alone if there isn't an alternative name */
/* so dev_name will always find something to return. */
/* Otherwise add the name to the correct device. */
if (dm_list_size(&dev->aliases) > 1) {
dm_list_del(dev->aliases.n);
if (!r)
_insert(name, &buf, 0, obtain_device_list_from_udev());
continue;
}
/* Scanning issues this inappropriately sometimes. */
log_debug_devs("Aborting - please provide new pathname for what "
"used to be %s", name);
return NULL;
}
return dev_name(dev);
}
struct device *dev_hash_get(const char *name)
{
return (struct device *) dm_hash_lookup(_cache.names, name);
@@ -1452,26 +1410,23 @@ static void _remove_alias(struct device *dev, const char *name)
* deactivated LV. Those old paths are all invalid and are dropped here.
*/
static void _verify_aliases(struct device *dev, const char *newname)
static void _verify_aliases(struct device *dev)
{
struct dm_str_list *strl, *strl2;
struct stat st;
dm_list_iterate_items_safe(strl, strl2, &dev->aliases) {
/* newname was just stat'd and added by caller */
if (newname && !strcmp(strl->str, newname))
continue;
if (stat(strl->str, &st) || (st.st_rdev != dev->dev)) {
log_debug("Drop invalid path %s for %d:%d (new path %s).",
strl->str, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), newname ?: "");
log_debug("Drop alias for %d:%d invalid path %s %d:%d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str,
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev));
dm_hash_remove(_cache.names, strl->str);
dm_list_del(&strl->list);
}
}
}
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f, int existing)
{
struct device *dev = (struct device *) dm_hash_lookup(_cache.names, name);
struct stat st;
@@ -1485,13 +1440,18 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
if (dev && (dev->flags & DEV_REGULAR))
return dev;
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
/*
* The requested path is invalid, remove any dev-cache
* info for it.
* The requested path is invalid, remove any dev-cache info for it.
*/
if (stat(name, &st)) {
if (dev) {
log_print("Device path %s is invalid for %d:%d %s.",
log_debug("Device path %s is invalid for %d:%d %s.",
name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
dm_hash_remove(_cache.names, name);
@@ -1499,11 +1459,17 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
_remove_alias(dev, name);
/* Remove any other names in dev->aliases that are incorrect. */
_verify_aliases(dev, NULL);
_verify_aliases(dev);
}
return NULL;
}
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
if (!S_ISBLK(st.st_mode)) {
log_debug("Not a block device %s.", name);
return NULL;
@@ -1514,26 +1480,41 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
* Remove incorrect info and then add new dev-cache entry.
*/
if (dev && (st.st_rdev != dev->dev)) {
log_debug("Device path %s does not match %d:%d %s.",
name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev));
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev);
dm_hash_remove(_cache.names, name);
/*
* lvm commands create this condition when they
* activate/deactivate LVs combined with creating new LVs.
* The command does not purge dev structs when deactivating
* an LV (which it probably should do), but the better
* approach would be not using dev-cache at all for LVs.
*/
_remove_alias(dev, name);
log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev),
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name);
/* Remove any other names in dev->aliases that are incorrect. */
_verify_aliases(dev, NULL);
_drop_all_aliases(dev);
/* Add new dev-cache entry next. */
dev = NULL;
}
if (dev_by_devt) {
log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.",
(int)MAJOR(dev_by_devt->dev), (int)MINOR(dev_by_devt->dev), dev_name(dev_by_devt),
(int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name);
_drop_all_aliases(dev_by_devt);
}
#if 0
/*
* I think only lvm's own dm devs should be added here, so use
* a warning to look for any other unknown cases.
*/
if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) {
log_warn("WARNING: new device appeared %d:%d %s",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
}
#endif
/*
* Either add a new struct dev for st_rdev and name,
* or add name as a new alias for an existing struct dev
* for st_rdev.
*/
if (!dev) {
if (!_insert_dev(name, st.st_rdev))
return_NULL;
@@ -1545,9 +1526,77 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
return NULL;
}
_verify_aliases(dev, name);
goto out;
}
if (dev && dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_warn("Ignoring dev with no valid paths for %s.", name);
return NULL;
}
if (!dev && existing)
return_NULL;
/*
* This case should never be hit for a PV. It should only
* happen when the command is opening a new LV it has created.
* Add an arg to all callers indicating when the arg should be
* new (for an LV) and not existing.
* FIXME: fix this further by not using dev-cache struct devs
* at all for new dm devs (LVs) that lvm uses. Make the
* dev-cache contain only devs for PVs.
* Places to fix that use a dev for LVs include:
* . lv_resize opening lv to discard
* . wipe_lv opening lv to zero it
* . _extend_sanlock_lv opening lv to extend it
* . _write_log_header opening lv to write header
* Also, io to LVs should not go through bcache.
* bcache should contain only labels and metadata
* scanned from PVs.
*/
if (!dev) {
/*
* This case should only be used for new devices created by this
* command (opening LVs it's created), so if a dev exists for the
* dev_t referenced by the name, then drop all aliases for before
* _insert_dev adds the new name. lvm commands actually hit this
* fairly often when it uses some LV, deactivates the LV, then
* creates some new LV which ends up with the same major:minor.
* Without dropping the aliases, it's plausible that lvm commands
* could end up using the wrong dm device.
*/
struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev);
if (dev_by_devt) {
log_debug("Dropping aliases for %d:%d before adding new path %s.",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
_drop_all_aliases(dev_by_devt);
}
#if 0
/*
* I think only lvm's own dm devs should be added here, so use
* a warning to look for any other unknown cases.
*/
if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) {
log_warn("WARNING: new device appeared %d:%d %s",
(int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name);
}
#endif
if (!_insert_dev(name, st.st_rdev))
return_NULL;
/* Get the struct dev that was just added. */
dev = (struct device *) dm_hash_lookup(_cache.names, name);
if (!dev) {
log_error("Failed to get device %s", name);
return NULL;
}
}
out:
/*
* The caller passed a filter if they only want the dev if it
* passes filters.
@@ -1577,63 +1626,23 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d
return dev;
}
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct dev_filter *f, int *filtered)
struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f)
{
char path[PATH_MAX];
const char *sysfs_dir;
struct stat info;
struct device *d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
int ret;
return _dev_cache_get(cmd, name, f, 1);
}
if (filtered)
*filtered = 0;
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f)
{
return _dev_cache_get(cmd, name, f, 0);
}
if (!d) {
sysfs_dir = dm_sysfs_dir();
if (sysfs_dir && *sysfs_dir) {
/* First check if dev is sysfs to avoid useless scan */
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) {
log_error("dm_snprintf partition failed.");
return NULL;
}
if (lstat(path, &info)) {
log_debug("No sysfs entry for %d:%d errno %d at %s.",
(int)MAJOR(dev), (int)MINOR(dev), errno, path);
return NULL;
}
}
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
(int)MAJOR(dev), (int)MINOR(dev));
dev_cache_scan(cmd);
d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
if (!d)
return NULL;
}
if (d->flags & DEV_REGULAR)
return d;
if (!f)
return 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));
d->flags |= DEV_FILTER_AFTER_SCAN;
ret = 1;
}
if (ret)
return d;
if (filtered)
*filtered = 1;
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt)
{
struct device *dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devt);
if (dev)
return dev;
log_debug_devs("No devno %d:%d in dev cache.", (int)MAJOR(devt), (int)MINOR(devt));
return NULL;
}
@@ -1703,8 +1712,10 @@ int dev_fd(struct device *dev)
const char *dev_name(const struct device *dev)
{
return (dev && dev->aliases.n) ? dm_list_item(dev->aliases.n, struct dm_str_list)->str :
unknown_device_name();
if (dev && dev->aliases.n && !dm_list_empty(&dev->aliases))
return dm_list_item(dev->aliases.n, struct dm_str_list)->str;
else
return unknown_device_name();
}
bool dev_cache_has_md_with_end_superblock(struct dev_types *dt)

View File

@@ -53,8 +53,8 @@ int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t device, struct dev_filter *f, int *filtered);
struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f);
struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt);
struct device *dev_hash_get(const char *name);

View File

@@ -58,6 +58,9 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size)
const char *name = dev_name(dev);
struct stat info;
if (dm_list_empty(&dev->aliases))
return_0;
if (dev->size_seqno == _dev_size_seqno) {
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
name, dev->size);
@@ -87,7 +90,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size)
int do_close = 0;
if (dm_list_empty(&dev->aliases))
return 0;
return_0;
if (dev->size_seqno == _dev_size_seqno) {
log_very_verbose("%s: using cached size %" PRIu64 " sectors",
@@ -305,6 +308,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if ((flags & O_EXCL))
need_excl = 1;
if (dm_list_empty(&dev->aliases)) {
/* shouldn't happen */
log_print("Cannot open device %d:%d with no valid paths.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev));
return 0;
}
name = dev_name(dev);
if (dev->fd >= 0) {
if (((dev->flags & DEV_OPENED_RW) || !need_rw) &&
((dev->flags & DEV_OPENED_EXCL) || !need_excl)) {
@@ -314,7 +324,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if (dev->open_count && !need_excl)
log_debug_devs("%s: Already opened read-only. Upgrading "
"to read-write.", dev_name(dev));
"to read-write.", name);
/* dev_close_immediate will decrement this */
dev->open_count++;
@@ -327,11 +337,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if (critical_section())
/* FIXME Make this log_error */
log_verbose("dev_open(%s) called while suspended",
dev_name(dev));
if (!(name = dev_name_confirmed(dev, quiet)))
return_0;
log_verbose("dev_open(%s) called while suspended", name);
#ifdef O_DIRECT_SUPPORT
if (direct) {
@@ -372,9 +378,9 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
}
#endif
if (quiet)
log_sys_debug("open", name);
log_debug("Failed to open device path %s (%d).", name, errno);
else
log_sys_error("open", name);
log_error("Failed to open device path %s (%d).", name, errno);
dev->flags |= DEV_OPEN_FAILURE;
return 0;
@@ -415,10 +421,12 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
if ((flags & O_CREAT) && !(flags & O_TRUNC))
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
log_debug_devs("Opened %s %s%s%s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
if (!quiet) {
log_debug_devs("Opened %s %s%s%s", name,
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
}
dev->flags &= ~DEV_OPEN_FAILURE;
return 1;

View File

@@ -966,6 +966,9 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam
/* TODO: Should we check for valid dev - _dev_is_valid(dev)? */
if (dm_list_empty(&dev->aliases))
goto_out;
if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) {
log_error("Failed to create a new blkid probe for device %s.", dev_name(dev));
goto out;

View File

@@ -40,6 +40,7 @@
#define DEV_IS_NVME 0x00040000 /* set if dev is nvme */
#define DEV_MATCHED_USE_ID 0x00080000 /* matched an entry from cmd->use_devices */
#define DEV_SCAN_FOUND_NOLABEL 0x00100000 /* label_scan read, passed filters, but no lvm label */
#define DEV_SCAN_NOT_READ 0x00200000 /* label_scan not able to read dev */
/*
* Support for external device info.
@@ -203,9 +204,6 @@ struct device *dev_create_file(const char *filename, struct device *dev,
struct dm_str_list *alias, int use_malloc);
void dev_destroy_file(struct device *dev);
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
int dev_mpath_init(const char *config_wwids_file);
void dev_mpath_exit(void);

View File

@@ -347,6 +347,8 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
}
else if (idtype == DEV_ID_TYPE_DEVNAME) {
if (dm_list_empty(&dev->aliases))
goto_bad;
if (!(idname = strdup(dev_name(dev))))
goto_bad;
return idname;
@@ -955,6 +957,10 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_
if (!dev_get_partition_number(dev, &part))
return_0;
/* Ensure valid dev_name(dev) below. */
if (dm_list_empty(&dev->aliases))
return_0;
/*
* When enable_devices_file=0 and pending_devices_file=1 we let
* pvcreate/vgcreate add new du's to cmd->use_devices. These du's may
@@ -1577,7 +1583,7 @@ void device_ids_match_device_list(struct cmd_context *cmd)
dm_list_iterate_items(du, &cmd->use_devices) {
if (du->dev)
continue;
if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) {
if (!(du->dev = dev_cache_get_existing(cmd, du->devname, NULL))) {
log_warn("Device not found for %s.", du->devname);
} else {
/* Should we set dev->id? Which idtype? Use --deviceidtype? */
@@ -1625,7 +1631,7 @@ void device_ids_match(struct cmd_context *cmd)
* the du/dev pairs in preparation for using the filters.
*/
if (du->devname &&
(dev = dev_cache_get(cmd, du->devname, NULL))) {
(dev = dev_cache_get_existing(cmd, du->devname, NULL))) {
/* On successful match, du, dev, and id are linked. */
if (_match_du_to_dev(cmd, du, dev))
continue;
@@ -1746,6 +1752,13 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
if (scanned_devs && !dev_in_device_list(dev, scanned_devs))
continue;
/*
* The matched device could not be read so we do not have
* the PVID from disk and cannot verify the devices file entry.
*/
if (dev->flags & DEV_SCAN_NOT_READ)
continue;
/*
* du and dev may have been matched, but the dev could still
* have been excluded by other filters during label scan.
@@ -1828,6 +1841,16 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
if (scanned_devs && !dev_in_device_list(dev, scanned_devs))
continue;
/*
* The matched device could not be read so we do not have
* the PVID from disk and cannot verify the devices file entry.
*/
if (dev->flags & DEV_SCAN_NOT_READ)
continue;
if (dm_list_empty(&dev->aliases))
continue;
if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "persistent")) {
log_warn("Devices file %s is excluded by filter: %s.",
dev_name(dev), dev_filtered_reason(dev));
@@ -2211,14 +2234,14 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
dm_list_iterate_items(dil, &search_pvids) {
char *dup_devname1, *dup_devname2, *dup_devname3;
if (!dil->dev) {
if (!dil->dev || dm_list_empty(&dil->dev->aliases)) {
not_found++;
continue;
}
found++;
dev = dil->dev;
devname = dev_name(dev);
found++;
if (!(du = get_du_for_pvid(cmd, dil->pvid))) {
/* shouldn't happen */

View File

@@ -2601,7 +2601,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->alias = FMT_TEXT_ALIAS;
fmt->orphan_vg_name = ORPHAN_VG_NAME(FMT_TEXT_NAME);
strncpy(fmt->orphan_vg_name, ORPHAN_VG_NAME(FMT_TEXT_NAME), sizeof(fmt->orphan_vg_name));
fmt->features = FMT_SEGMENTS | FMT_TAGS | FMT_PRECOMMIT |
FMT_UNLIMITED_VOLS | FMT_RESIZE_PV |
FMT_UNLIMITED_STRIPESIZE | FMT_CONFIG_PROFILE |

View File

@@ -410,6 +410,7 @@ static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct
{
struct lvmcache_vgsummary vgsummary;
char pvid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
char vgid[ID_LEN + 1] __attribute__((aligned(8))) = { 0 };
struct lvmcache_info *info;
const struct format_type *fmt = labeller->fmt;
struct label_header *lh = (struct label_header *) label_buf;
@@ -433,6 +434,7 @@ static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct
pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
memcpy(pvid, &pvhdr->pv_uuid, ID_LEN);
strncpy(vgid, FMT_TEXT_ORPHAN_VG_NAME, ID_LEN);
/*
* FIXME: stop adding the device to lvmcache initially as an orphan
@@ -449,8 +451,8 @@ static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct
* Other reasons for lvmcache_add to return NULL are internal errors.
*/
if (!(info = lvmcache_add(cmd, labeller, pvid, dev, label_sector,
FMT_TEXT_ORPHAN_VG_NAME,
FMT_TEXT_ORPHAN_VG_NAME, 0, is_duplicate)))
vgid,
vgid, 0, is_duplicate)))
return_0;
lvmcache_set_device_size(info, xlate64(pvhdr->device_size_xl));

View File

@@ -236,6 +236,7 @@ static int _touch_newhints(void)
return_0;
if (fclose(fp))
stack;
log_debug("newhints created");
return 1;
}
@@ -499,6 +500,8 @@ int validate_hints(struct cmd_context *cmd, struct dm_list *hints)
if (!(iter = dev_iter_create(NULL, 0)))
return 0;
while ((dev = dev_iter_get(cmd, iter))) {
if (dm_list_empty(&dev->aliases))
continue;
if (!(hint = _find_hint_name(hints, dev_name(dev))))
continue;
@@ -506,6 +509,19 @@ int validate_hints(struct cmd_context *cmd, struct dm_list *hints)
if (!hint->chosen)
continue;
/*
* label_scan was unable to read the dev so we don't know its pvid.
* Since we are unable to verify the hint is correct, it's possible
* that the PVID is actually found on a different device, so don't
* depend on hints. (This would also fail the following pvid check.)
*/
if (dev->flags & DEV_SCAN_NOT_READ) {
log_debug("Uncertain hint for unread device %d:%d %s",
major(hint->devt), minor(hint->devt), dev_name(dev));
ret = 0;
continue;
}
if (strcmp(dev->pvid, hint->pvid)) {
log_debug("Invalid hint device %d:%d %s pvid %s had hint pvid %s",
major(hint->devt), minor(hint->devt), dev_name(dev),

View File

@@ -687,6 +687,8 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
dm_list_iterate_items_safe(devl, devl2, devs) {
devl->dev->flags &= ~DEV_SCAN_NOT_READ;
/*
* If we prefetch more devs than blocks in the cache, then the
* cache will wait for earlier reads to complete, toss the
@@ -702,6 +704,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
log_debug_devs("Scan failed to open %s.", dev_name(devl->dev));
dm_list_del(&devl->list);
dm_list_add(&reopen_devs, &devl->list);
devl->dev->flags |= DEV_SCAN_NOT_READ;
continue;
}
}
@@ -725,6 +728,7 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
log_debug_devs("Scan failed to read %s.", dev_name(devl->dev));
scan_read_errors++;
scan_failed_count++;
devl->dev->flags |= DEV_SCAN_NOT_READ;
lvmcache_del_dev(devl->dev);
if (bb)
bcache_put(bb);
@@ -1126,11 +1130,12 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname,
* sure to find the device.
*/
if (try_dev_scan) {
log_debug("Repeat dev cache scan to translate devnos.");
dev_cache_scan(cmd);
dm_list_iterate_items(po, &pvs_online) {
if (po->dev)
continue;
if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) {
if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno))) {
log_error("No device found for %d:%d PVID %s",
(int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid);
goto bad;
@@ -1389,6 +1394,10 @@ int label_scan(struct cmd_context *cmd)
* filter", and this result needs to be cleared (wiped) so that the
* complete set of filters (including those that require data) can be
* checked in _process_block, where headers have been read.
*
* FIXME: devs that are filtered with data in _process_block
* are not moved to the filtered_devs list like devs filtered
* here without data. Does that have any effect?
*/
log_debug_devs("Filtering devices to scan (nodata)");
@@ -1714,7 +1723,7 @@ void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv
if (lv_info(cmd, lv, 0, &lvinfo, 0, 0) && lvinfo.exists) {
/* FIXME: Still unclear what is it supposed to find */
devt = MKDEV(lvinfo.major, lvinfo.minor);
if ((dev = dev_cache_get_by_devt(cmd, devt, NULL, NULL)))
if ((dev = dev_cache_get_by_devt(cmd, devt)))
label_scan_invalidate(dev);
}
}
@@ -1728,13 +1737,19 @@ void label_scan_invalidate_lvs(struct cmd_context *cmd, struct dm_list *lvs)
struct lv_list *lvl;
dev_t devt;
/*
* FIXME: this is all unnecessary unless there are PVs stacked on LVs,
* so we can skip all of this if scan_lvs=0.
*/
log_debug("invalidating devs for any pvs on lvs");
if (get_device_list(NULL, &devs, &devs_features)) {
if (devs_features & DM_DEVICE_LIST_HAS_UUID) {
dm_list_iterate_items(dm_dev, devs)
if (dm_dev->uuid &&
strncmp(dm_dev->uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) == 0) {
devt = MKDEV(dm_dev->major, dm_dev->minor);
if ((dev = dev_cache_get_by_devt(cmd, devt, NULL, NULL)))
if ((dev = dev_cache_get_by_devt(cmd, devt)))
label_scan_invalidate(dev);
}
/* ATM no further caching for any lvconvert command
@@ -1871,10 +1886,24 @@ int label_scan_open_rw(struct device *dev)
int label_scan_reopen_rw(struct device *dev)
{
const char *name;
int flags = 0;
int prev_fd = dev->bcache_fd;
int fd;
if (dm_list_empty(&dev->aliases)) {
log_error("Cannot reopen rw device %d:%d with no valid paths di %d fd %d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev->bcache_di, dev->bcache_fd);
return 0;
}
name = dev_name(dev);
if (!name || name[0] != '/') {
log_error("Cannot reopen rw device %d:%d with no valid name di %d fd %d.",
(int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev->bcache_di, dev->bcache_fd);
return 0;
}
if (!(dev->flags & DEV_IN_BCACHE)) {
if ((dev->bcache_fd != -1) || (dev->bcache_di != -1)) {
/* shouldn't happen */
@@ -1904,7 +1933,7 @@ int label_scan_reopen_rw(struct device *dev)
flags |= O_NOATIME;
flags |= O_RDWR;
fd = open(dev_name(dev), flags, 0777);
fd = open(name, flags, 0777);
if (fd < 0) {
log_error("Failed to open rw %s errno %d di %d fd %d.",
dev_name(dev), errno, dev->bcache_di, dev->bcache_fd);

View File

@@ -272,6 +272,8 @@ static void _lockd_retrive_vg_pv_list(struct volume_group *vg,
i = 0;
dm_list_iterate_items(pvl, &vg->pvs) {
if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases))
continue;
lock_pvs->path[i] = strdup(pv_dev_name(pvl->pv));
if (!lock_pvs->path[i]) {
log_error("Fail to allocate PV path for VG %s", vg->name);
@@ -341,6 +343,8 @@ static void _lockd_retrive_lv_pv_list(struct volume_group *vg,
dm_list_iterate_items(pvl, &vg->pvs) {
if (lv_is_on_pv(lv, pvl->pv)) {
if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases))
continue;
lock_pvs->path[i] = strdup(pv_dev_name(pvl->pv));
if (!lock_pvs->path[i]) {
log_error("Fail to allocate PV path for LV %s/%s",

View File

@@ -371,7 +371,7 @@ struct format_type {
struct labeller *labeller;
const char *name;
const char *alias;
const char *orphan_vg_name;
char orphan_vg_name[ID_LEN];
struct volume_group *orphan_vg; /* Only one ever exists. */
uint32_t features;
void *library;

View File

@@ -2197,7 +2197,7 @@ static int _validate_lock_args_chars(const char *lock_args)
static int _validate_vg_lock_args(struct volume_group *vg)
{
if (!_validate_lock_args_chars(vg->lock_args)) {
if (!vg->lock_args || !_validate_lock_args_chars(vg->lock_args)) {
log_error(INTERNAL_ERROR "VG %s has invalid lock_args chars", vg->name);
return 0;
}

View File

@@ -1231,14 +1231,23 @@ int remove_mirrors_from_segments(struct logical_volume *lv,
const char *get_pvmove_pvname_from_lv_mirr(const struct logical_volume *lv_mirr)
{
struct lv_segment *seg;
struct device *dev;
dm_list_iterate_items(seg, &lv_mirr->segments) {
if (!seg_is_mirrored(seg))
continue;
if (seg_type(seg, 0) == AREA_PV)
return dev_name(seg_dev(seg, 0));
if (seg_type(seg, 0) == AREA_LV)
return dev_name(seg_dev(first_seg(seg_lv(seg, 0)), 0));
if (seg_type(seg, 0) == AREA_PV) {
dev = seg_dev(seg, 0);
if (!dev || dm_list_empty(&dev->aliases))
return NULL;
return dev_name(dev);
}
if (seg_type(seg, 0) == AREA_LV) {
dev = seg_dev(first_seg(seg_lv(seg, 0)), 0);
if (!dev || dm_list_empty(&dev->aliases))
return NULL;
return dev_name(dev);
}
}
return NULL;

View File

@@ -152,6 +152,11 @@ static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
struct pv_list *new_pvl = NULL, *pvl2;
struct dm_list *pe_ranges;
if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases)) {
log_error("Failed to create PV entry for missing device.");
return 0;
}
pvname = pv_dev_name(pvl->pv);
if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
log_warn("WARNING: Physical volume %s not allocatable.", pvname);

View File

@@ -679,6 +679,11 @@ int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
return r;
}
if (!pv->dev || dm_list_empty(&pv->dev->aliases)) {
log_error("No device found for PV.");
return r;
}
log_debug("vgreduce_single VG %s PV %s", vg->name, pv_dev_name(pv));
if (pv_pe_alloc_count(pv)) {

View File

@@ -108,6 +108,7 @@ FIELD(LVS, lv, TIM, "RTime", lvid, 26, lvtimeremoved, lv_time_removed, "Removal
FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0)
FIELD(LVS, lv, STR_LIST, "Modules", lvid, 0, modules, lv_modules, "Kernel device-mapper modules required for this LV.", 0)
FIELD(LVS, lv, BIN, "Historical", lvid, 0, lvhistorical, lv_historical, "Set if the LV is historical.", 0)
FIELD(LVS, lv, NUM, "WCacheBlkSize", lvid, 0, writecache_block_size, writecache_block_size, "The writecache block size", 0)
/*
* End of LVS type fields
*/

View File

@@ -353,6 +353,8 @@ GET_PV_STR_PROPERTY_FN(pv_device_id_type, pv->device_id_type)
#define _writecache_writeback_blocks_get prop_not_implemented_get
#define _writecache_error_set prop_not_implemented_set
#define _writecache_error_get prop_not_implemented_get
#define _writecache_block_size_set prop_not_implemented_set
#define _writecache_block_size_get prop_not_implemented_get
#define _vdo_operating_mode_set prop_not_implemented_set
#define _vdo_operating_mode_get prop_not_implemented_get

View File

@@ -3346,6 +3346,26 @@ static int _integritymismatches_disp(struct dm_report *rh __attribute__((unused)
return _field_set_value(field, "", &GET_TYPE_RESERVED_VALUE(num_undef_64));
}
static int _writecache_block_size_disp(struct dm_report *rh __attribute__((unused)),
struct dm_pool *mem,
struct dm_report_field *field,
const void *data,
void *private __attribute__((unused)))
{
struct logical_volume *lv = (struct logical_volume *) data;
uint32_t bs = 0;
if (lv_is_writecache(lv)) {
struct lv_segment *seg = first_seg(lv);
bs = seg->writecache_block_size;
}
if (!bs)
return dm_report_field_int32(rh, field, &GET_TYPE_RESERVED_VALUE(num_undef_32));
return dm_report_field_uint32(rh, field, &bs);
}
static int _datapercent_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field,
const void *data, void *private)

View File

@@ -168,6 +168,11 @@ int id_write_format(const struct id *id, char *buffer, size_t size)
assert(ID_LEN == 32);
if (id->uuid[0] == '#') {
(void) dm_strncpy(buffer, (char*)id->uuid, size);
return 1;
}
/* split into groups separated by dashes */
if (size < (32 + 6 + 1)) {
if (size > 0)

View File

@@ -18,6 +18,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h> /* help musl C */
#include <pthread.h>
#include <sys/file.h>
#include <sys/stat.h>

View File

@@ -61,8 +61,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--segments\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
@@ -332,16 +330,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB--segments\fP
.br
.

View File

@@ -240,18 +240,59 @@ The writecache block size should be chosen to match the xfs sectsz value.
It is also possible to specify a sector size of 4096 to mkfs.xfs when
creating the file system. In this case the writecache block size of 4096
can be used.
.P
The writecache block size is displayed by the command:
.br
lvs -o writecacheblocksize VG/LV
.P
.SS dm-writecache memory usage
.P
The amount of main system memory used by dm-writecache can be a factor
when selecting the writecache cachevol size and the writecache block size.
.P
.IP \[bu] 2
writecache block size 4096: each 100 GiB of writecache cachevol uses
slighly over 2 GiB of system memory.
.IP \[bu] 2
writecache block size 512: each 100 GiB of writecache cachevol uses
a little over 16 GiB of system memory.
.
.SS dm-writecache settings
.
Tunable parameters can be passed to the dm-writecache kernel module using
the --cachesettings option when caching is started, e.g.
To specify dm-writecache tunable settings on the command line, use:
.br
--cachesettings 'option=N' or
.br
--cachesettings 'option1=N option2=N ...'
.P
For example, --cachesettings 'high_watermark=90 writeback_jobs=4'.
.P
To include settings when caching is started, run:
.P
.nf
# lvconvert --type writecache --cachevol fast \\
--cachesettings 'high_watermark=N writeback_jobs=N' vg/main
--cachesettings 'option=N' vg/main
.fi
.P
Tunable options are:
To change settings for an existing writecache, run:
.P
.nf
# lvchange --cachesettings 'option=N' vg/main
.fi
.P
To clear all settings that have been applied, run:
.P
.nf
# lvchange --cachesettings '' vg/main
.fi
.P
To view the settings that are applied to a writecache LV, run:
.P
.nf
# lvs -o cachesettings vg/main
.fi
.P
Tunable settings are:
.
.TP
high_watermark = <percent>
@@ -301,11 +342,14 @@ writecache. Adding cleaner=0 to the splitcache command will skip the
cleaner mode, and any required flushing is performed in device suspend.
.SS dm-writecache using metadata profiles
Writecache allows to set a variety of options. Lots of these settings
can be specified in lvm.conf or profile settings. You can prepare
a number of different profiles in the \fI#DEFAULT_SYS_DIR#/profile\fP directory
and just specify the metadata profile file name when writecaching LV.
.
In addition to specifying writecache settings on the command line, they
can also be set in lvm.conf, or in a profile file, using the
allocation/cache_settings/writecache config structure shown below.
.P
It's possible to prepare a number of different profile files in the
\fI#DEFAULT_SYS_DIR#/profile\fP directory and specify the file name
of the profile when starting writecache.
.P
.I Example
.nf
@@ -327,11 +371,10 @@ writeback_jobs=1024
EOF
.P
# lvcreate -an -L10G --name wcache vg /dev/fast_ssd
# lvcreate --type writecache -L10G --name main --cachevol wcache \\
# lvcreate -an -L10G --name fast vg /dev/fast_ssd
# lvcreate --type writecache -L10G --name main --cachevol fast \\
--metadataprofile cache_writecache vg /dev/slow_hdd
.fi
.
.SS dm-cache with separate data and metadata LVs
.

View File

@@ -322,7 +322,8 @@ Find a device with the PVID and add the device to the devices file.
.HP
\fB--check\fP
.br
Check the content of the devices file.
Checks the content of the devices file.
Reports incorrect device names or PVIDs for entries.
.
.HP
\fB--commandprofile\fP \fIString\fP

View File

@@ -61,8 +61,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
.br
[ \fB--shared\fP ]
@@ -320,16 +318,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB-S\fP|\fB--select\fP \fIString\fP
.br
Select objects for processing and reporting based on specified criteria.

View File

@@ -15,6 +15,8 @@ pvscan \(em List all physical volumes
.P
.ad l
\fB-a\fP|\fB--activate\fP \fBy\fP|\fBn\fP|\fBay\fP
.br
\fB--autoactivation\fP \fIString\fP
.br
\fB--cache\fP
.br
@@ -91,59 +93,50 @@ like
or
.BR pvdisplay (8).
.P
When the --cache and -aay options are used, pvscan records which PVs are
available on the system, and activates LVs in completed VGs. A VG is
complete when pvscan sees that the final PV in the VG has appeared. This
is used by event-based system startup (systemd, udev) to activate LVs.
.P
The four main variations of this are:
When --cache is used, pvscan updates runtime lvm state on the system, or
with -aay performs autoactivation.
.P
.B pvscan --cache
.I device
.P
If device is present, lvm adds a record that the PV on device is online.
If device is present, lvm records that the PV on device is online.
If device is not present, lvm removes the online record for the PV.
In most cases, the pvscan will only read the named devices.
.P
.B pvscan --cache -aay
.IR device ...
.P
This begins by performing the same steps as above. Afterward, if the VG
for the specified PV is complete, then pvscan will activate LVs in the VG
(the same as vgchange -aay vgname would do.)
pvscan only reads the named device.
.P
.B pvscan --cache
.P
This first clears all existing PV online records, then scans all devices
on the system, adding PV online records for any PVs that are found.
Updates the runtime state for all lvm devices.
.P
.B pvscan --cache -aay
.I device
.P
Performs the --cache steps for the device, then checks if the VG using the
device is complete. If so, LVs in the VG are autoactivated, the same as
vgchange -aay vgname would do. (A device name may be replaced with major
and minor numbers.)
.P
.B pvscan --cache -aay
.P
This begins by performing the same steps as pvscan --cache. Afterward, it
activates LVs in any complete VGs.
Performs the --cache steps for all devices, then autoactivates any complete VGs.
.P
To prevent devices from being scanned by pvscan --cache, add them
to
.BR lvm.conf (5)
.B devices/global_filter.
For more information, see:
.br
.B lvmconfig --withcomments devices/global_filter
.B pvscan --cache --listvg|--listlvs
.I device
.P
Auto-activation of VGs or LVs can be enabled/disabled using:
.br
Performs the --cache steps for the device, then prints the name of the VG
using the device, or the names of LVs using the device. --checkcomplete
is usually included to check if all PVs for the VG or LVs are online.
When this command is called by a udev rule, the output must conform to
udev rule specifications (see --udevoutput.) The udev rule will use the
results to perform autoactivation.
.P
Autoactivation of VGs or LVs can be enabled/disabled using vgchange or
lvchange with --setautoactivation y|n, or by adding names to
.BR lvm.conf (5)
.B activation/auto_activation_volume_list
.P
For more information, see:
.br
.B lvmconfig --withcomments activation/auto_activation_volume_list
.P
To disable auto-activation, explicitly set this list to an empty list,
i.e. auto_activation_volume_list = [ ].
.P
When this setting is undefined (e.g. commented), then all LVs are
auto-activated.
See
.BR lvmautoactivation (7)
for more information about how pvscan is used for autoactivation.
.
.SH USAGE
.
@@ -215,6 +208,8 @@ Record that a PV is online and autoactivate the VG if complete.
.br
[ \fB--noudevsync\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ COMMON_OPTIONS ]
.ad b
.RE
@@ -239,6 +234,8 @@ Record that a PV is online and list the VG using the PV.
.br
[ \fB--udevoutput\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ COMMON_OPTIONS ]
.ad b
.RE
@@ -342,6 +339,14 @@ Auto-activate LVs in a VG when the PVs scanned have completed the VG.
(Only \fBay\fP is applicable.)
.
.HP
\fB--autoactivation\fP \fIString\fP
.br
Specify if autoactivation is being used from an event.
This allows the command to apply settings that are specific
to event activation, such as device scanning optimizations
using pvs_online files created by event-based pvscans.
.
.HP
\fB--cache\fP
.br
Scan one or more devices and record that they are online.

View File

@@ -24,6 +24,8 @@ vgchange \(em Change volume group attributes
.nh
\%\fBcontiguous\fP|\:\fBcling\fP|\:\fBcling_by_tags\fP|\:\fBnormal\fP|\:\fBanywhere\fP|\:\fBinherit\fP
.hy
.br
\fB--autoactivation\fP \fIString\fP
.br
\fB-A\fP|\fB--autobackup\fP \fBy\fP|\fBn\fP
.br
@@ -286,6 +288,8 @@ Activate or deactivate LVs.
.br
[ \fB--poll\fP \fBy\fP|\fBn\fP ]
.br
[ \fB--autoactivation\fP \fIString\fP ]
.br
[ \fB--ignoremonitoring\fP ]
.br
[ \fB--noudevsync\fP ]
@@ -516,6 +520,14 @@ which PVs the command will use for allocation.
See \fBlvm\fP(8) for more information about allocation.
.
.HP
\fB--autoactivation\fP \fIString\fP
.br
Specify if autoactivation is being used from an event.
This allows the command to apply settings that are specific
to event activation, such as device scanning optimizations
using pvs_online files created by event-based pvscans.
.
.HP
\fB-A\fP|\fB--autobackup\fP \fBy\fP|\fBn\fP
.br
Specifies if metadata should be backed up automatically after a change.

View File

@@ -58,8 +58,6 @@ and more, using a more compact and configurable output format.
.br
[ \fB--readonly\fP ]
.br
[ \fB--reportformat\fP \fBbasic\fP|\fBjson\fP ]
.br
[ \fB--shared\fP ]
.br
[ \fB--separator\fP \fIString\fP ]
@@ -312,16 +310,6 @@ device-mapper kernel driver, so this option is unable to report whether
or not LVs are actually in use.
.
.HP
\fB--reportformat\fP \fBbasic\fP|\fBjson\fP
.br
Overrides current output format for reports which is defined globally by
the report/output_format setting in \fBlvm.conf\fP(5).
\fBbasic\fP is the original format with columns and rows.
If there is more than one report per command, each report is prefixed
with the report name for identification. \fBjson\fP produces report
output in JSON format. See \fBlvmreport\fP(7) for more information.
.
.HP
\fB-S\fP|\fB--select\fP \fIString\fP
.br
Select objects for processing and reporting based on specified criteria.

View File

@@ -33,6 +33,8 @@ aux udev_wait
ls -la "${LOOP}"*
test -e "${LOOP}p1"
aux lvmconf 'devices/scan = "/dev"'
aux extend_filter "a|$LOOP|"
aux extend_devices "$LOOP"

View File

@@ -75,7 +75,7 @@ wait_lvm_activate() {
local vgw=$1
local wait=0
while systemctl status lvm-activate-$vgw | grep "active (running)" && test "$wait" -le 30; do
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
sleep .2
wait=$(( wait + 1 ))
done
@@ -382,7 +382,6 @@ lvcreate -l1 -an -n $lv1 $vg9
lvcreate -l1 -an -n $lv2 $vg9
mdadm --stop "$mddev"
systemctl stop lvm-activate-$vg9 || true
_clear_online_files
mdadm --assemble "$mddev" "$dev1" "$dev2"
@@ -405,17 +404,6 @@ mdadm --stop "$mddev"
aux udev_wait
wipe_all
systemctl stop lvm-activate-$vg1
systemctl stop lvm-activate-$vg2
systemctl stop lvm-activate-$vg3
systemctl stop lvm-activate-$vg4
systemctl stop lvm-activate-$vg5
systemctl stop lvm-activate-$vg6
systemctl stop lvm-activate-$vg7
systemctl stop lvm-activate-$vg8
systemctl stop lvm-activate-$vg9
# no devices file, filter with symlink of PV
# the pvscan needs to look at all dev names to
# match the symlink in the filter with the
@@ -439,7 +427,6 @@ udevadm trigger --settle -c add /sys/block/$BDEV1
ls /dev/disk/by-id/lvm-pv-uuid-$OPVID1
vgchange -an $vg10
systemctl stop lvm-activate-$vg10
_clear_online_files
aux lvmconf "devices/filter = [ \"a|/dev/disk/by-id/lvm-pv-uuid-$OPVID1|\", \"r|.*|\" ]"

View File

@@ -19,6 +19,9 @@ _clear_online_files() {
aux prepare_devs 4
# skip rhel5 which doesn't seem to have /dev/mapper/LVMTESTpv1
aux driver_at_least 4 15 || skip
DFDIR="$LVM_SYSTEM_DIR/devices"
mkdir -p "$DFDIR" || true
DF="$DFDIR/system.devices"

View File

@@ -222,6 +222,8 @@ vgextend $vg "$dev2"
lvcreate -n $lv1 -l 8 -an $vg "$dev1"
lvcreate -n $lv2 -l 4 -an $vg "$dev2"
lvconvert --yes --type writecache --cachevol $lv2 --cachesettings "block_size=4096" $vg/$lv1
lvs -o writecacheblocksize $vg/$lv1 |tee out
grep 4096 out
lvchange -ay $vg/$lv1
mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
grep "sectsz=4096" out

View File

@@ -190,9 +190,9 @@ command-lines-input.h: $(srcdir)/command-lines.in Makefile
$(Q) set -o pipefail && \
( cat $(srcdir)/license.inc && \
echo "/* Do not edit. This file is generated by the Makefile. */" && \
echo -en "const char _command_input[] =\n\n\"" && \
echo -en "static const char _command_input[] =\n\n\"" && \
$(EGREP) -v '^#|\-\-\-|^$$' $(srcdir)/command-lines.in | $(AWK) 'BEGIN {ORS = "\\n\"\n\""} //' && \
echo "\\n\";" \
echo "\\n\\n\";" \
) > $@
$(SOURCES:%.c=%.d) $(SOURCES2:%.c=%.d): command-lines-input.h command-count.h cmds.h

View File

@@ -862,12 +862,13 @@ arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0,
"See \\fBlvmcache\\fP(7) for more information.\n")
arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0,
"Specifies tunable values for a cache LV in \"Key = Value\" form.\n"
"Repeat this option to specify multiple values.\n"
"(The default values should usually be adequate.)\n"
"The special string value \\fBdefault\\fP switches\n"
"settings back to their default kernel values and removes\n"
"them from the list of settings stored in LVM metadata.\n"
"Specifies tunable kernel options for dm-cache or dm-writecache LVs.\n"
"Use the form 'option=value' or 'option1=value option2=value', or\n"
"repeat --cachesettings for each option being set.\n"
"These settings override the default kernel behaviors which are\n"
"usually adequate. To remove cachesettings and revert to the default\n"
"kernel behaviors, use --cachesettings 'default' for dm-cache or\n"
"an empty string --cachesettings '' for dm-writecache.\n"
"See \\fBlvmcache\\fP(7) for more information.\n")
arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0,

View File

@@ -2549,7 +2549,7 @@ static const char *_man_long_opt_name(const char *cmdname, int opt_enum)
}
if (strchr(long_opt, '[')) {
for (i = 0; i < sizeof(long_opt_name) - 1; ++long_opt, ++i) {
for (i = 0; *long_opt && i < sizeof(long_opt_name) - 1; ++long_opt, ++i) {
if (i < (sizeof(long_opt_name) - 8))
switch(*long_opt) {
case '[':

View File

@@ -1488,7 +1488,7 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv,
goto out;
}
if (!(dev = dev_cache_get(cmd, argv[opt], cmd->filter))) {
if (!(dev = dev_cache_get_existing(cmd, argv[opt], cmd->filter))) {
log_error("Failed to find device "
"\"%s\".", argv[opt]);
ret_max = ECMD_FAILED;
@@ -3925,7 +3925,7 @@ static int _get_arg_devices(struct cmd_context *cmd,
return ECMD_FAILED;
}
if (!(dil->dev = dev_cache_get(cmd, sl->str, cmd->filter))) {
if (!(dil->dev = dev_cache_get_existing(cmd, sl->str, cmd->filter))) {
log_error("Cannot use %s: %s", sl->str, devname_error_reason(sl->str));
ret_max = EINIT_FAILED;
} else {
@@ -5261,7 +5261,7 @@ int pvcreate_each_device(struct cmd_context *cmd,
struct device *dev;
/* No filter used here */
if (!(dev = dev_cache_get(cmd, pd->name, NULL))) {
if (!(dev = dev_cache_get_existing(cmd, pd->name, NULL))) {
log_error("No device found for %s.", pd->name);
dm_list_del(&pd->list);
dm_list_add(&pp->arg_fail, &pd->list);