mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-28 09:44:18 +03:00
Compare commits
24 Commits
dev-dct-pv
...
wip-2.03.1
Author | SHA1 | Date | |
---|---|---|---|
|
4b26fb3543 | ||
|
61833dd5b6 | ||
|
af4bfa1f1f | ||
|
7631c5b826 | ||
|
357a807e81 | ||
|
604fd528fb | ||
|
04770589b4 | ||
|
10a4478e9b | ||
|
c02a086fe7 | ||
|
25dbe3dd82 | ||
|
7ac0b3c119 | ||
|
594c1fec16 | ||
|
9c9bf13186 | ||
|
39adf3e513 | ||
|
5533cd7bf4 | ||
|
459d931a9b | ||
|
fad2b3dc8c | ||
|
f732f3d53f | ||
|
f73be4480a | ||
|
00ebabfe6e | ||
|
074fce5c73 | ||
|
a5a2d5fa1e | ||
|
2091305b79 | ||
|
63c4458aaf |
@@ -1143,19 +1143,6 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
* Update MAX_FILTERS definition above when adding new filters.
|
||||
*/
|
||||
|
||||
/*
|
||||
* sysfs filter. Only available on 2.6 kernels. Non-critical.
|
||||
* Listed first because it's very efficient at eliminating
|
||||
* unavailable devices.
|
||||
*
|
||||
* TODO: I suspect that using the lvm_type and device_id
|
||||
* filters before this one may be more efficient.
|
||||
*/
|
||||
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create()))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* internal filter used by command processing. */
|
||||
if (!(filters[nr_filt] = internal_filter_create())) {
|
||||
log_error("Failed to create internal device filter");
|
||||
@@ -1195,6 +1182,17 @@ static struct dev_filter *_init_filter_chain(struct cmd_context *cmd)
|
||||
}
|
||||
nr_filt++;
|
||||
|
||||
/*
|
||||
* sysfs filter. Only available on 2.6 kernels. Non-critical.
|
||||
* Eliminates unavailable devices.
|
||||
* TODO: this may be unnecessary now with device ids
|
||||
* (currently not used for devs match to device id using syfs)
|
||||
*/
|
||||
if (find_config_tree_bool(cmd, devices_sysfs_scan_CFG, NULL)) {
|
||||
if ((filters[nr_filt] = sysfs_filter_create()))
|
||||
nr_filt++;
|
||||
}
|
||||
|
||||
/* usable device filter. Required. */
|
||||
if (!(filters[nr_filt] = usable_filter_create(cmd, cmd->dev_types, FILTER_MODE_NO_LVMETAD))) {
|
||||
log_error("Failed to create usabled device filter");
|
||||
@@ -1605,7 +1603,6 @@ 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;
|
||||
@@ -1670,7 +1667,6 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
|
||||
dm_list_init(&cmd->formats);
|
||||
dm_list_init(&cmd->segtypes);
|
||||
dm_list_init(&cmd->tags);
|
||||
dm_list_init(&cmd->hints);
|
||||
dm_list_init(&cmd->config_files);
|
||||
label_init();
|
||||
|
||||
|
@@ -206,7 +206,6 @@ struct cmd_context {
|
||||
* Devices and filtering.
|
||||
*/
|
||||
struct dev_filter *filter;
|
||||
struct dm_list hints;
|
||||
struct dm_list use_devices; /* struct dev_use for each entry in devices file */
|
||||
const char *md_component_checks;
|
||||
const char *search_for_devnames; /* config file setting */
|
||||
|
@@ -1852,7 +1852,7 @@ int setup_devices_file(struct cmd_context *cmd)
|
||||
* Add all system devices to dev-cache, and attempt to
|
||||
* match all devices_file entries to dev-cache entries.
|
||||
*/
|
||||
int setup_devices(struct cmd_context *cmd)
|
||||
static int _setup_devices(struct cmd_context *cmd, int no_file_match)
|
||||
{
|
||||
int file_exists;
|
||||
int lock_mode = 0;
|
||||
@@ -1979,6 +1979,13 @@ int setup_devices(struct cmd_context *cmd)
|
||||
*/
|
||||
dev_cache_scan(cmd);
|
||||
|
||||
/*
|
||||
* The caller uses "no_file_match" if it wants to match specific devs
|
||||
* itself, instead of matching everything in device_ids_match.
|
||||
*/
|
||||
if (no_file_match && cmd->enable_devices_file)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Match entries from cmd->use_devices with device structs in dev-cache.
|
||||
*/
|
||||
@@ -1987,6 +1994,16 @@ int setup_devices(struct cmd_context *cmd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setup_devices(struct cmd_context *cmd)
|
||||
{
|
||||
return _setup_devices(cmd, 0);
|
||||
}
|
||||
|
||||
int setup_devices_no_file_match(struct cmd_context *cmd)
|
||||
{
|
||||
return _setup_devices(cmd, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The alternative to setup_devices() when the command is interested
|
||||
* in using only one PV.
|
||||
@@ -2055,188 +2072,3 @@ int setup_device(struct cmd_context *cmd, const char *devname)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pvscan --cache is specialized/optimized to look only at command args,
|
||||
* so this just sets up the devices file, then individual devices are
|
||||
* added to dev-cache and matched with device_ids later in pvscan.
|
||||
*/
|
||||
|
||||
int setup_devices_for_pvscan_cache(struct cmd_context *cmd)
|
||||
{
|
||||
if (cmd->enable_devices_list) {
|
||||
if (!_setup_devices_list(cmd))
|
||||
return_0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!setup_devices_file(cmd))
|
||||
return_0;
|
||||
|
||||
if (!cmd->enable_devices_file)
|
||||
return 1;
|
||||
|
||||
if (!devices_file_exists(cmd)) {
|
||||
log_debug("Devices file not found, ignoring.");
|
||||
cmd->enable_devices_file = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lock_devices_file(cmd, LOCK_SH)) {
|
||||
log_error("Failed to lock the devices file to read.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!device_ids_read(cmd)) {
|
||||
log_error("Failed to read the devices file.");
|
||||
unlock_devices_file(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlock_devices_file(cmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Get a device name from a devno. */
|
||||
|
||||
static char *_get_devname_from_devno(struct cmd_context *cmd, dev_t devno)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char devname[PATH_MAX];
|
||||
char namebuf[NAME_LEN];
|
||||
char line[1024];
|
||||
int major = MAJOR(devno);
|
||||
int minor = MINOR(devno);
|
||||
int line_major;
|
||||
int line_minor;
|
||||
uint64_t line_blocks;
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
FILE *fp;
|
||||
|
||||
/*
|
||||
* $ ls /sys/dev/block/8:0/device/block/
|
||||
* sda
|
||||
*/
|
||||
if (major_is_scsi_device(cmd->dev_types, major)) {
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/device/block",
|
||||
dm_sysfs_dir(), major, minor) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dir = opendir(path)))
|
||||
return NULL;
|
||||
|
||||
while ((dirent = readdir(dir))) {
|
||||
if (dirent->d_name[0] == '.')
|
||||
continue;
|
||||
if (dm_snprintf(devname, sizeof(devname), "/dev/%s", dirent->d_name) < 0) {
|
||||
devname[0] = '\0';
|
||||
stack;
|
||||
}
|
||||
break;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (devname[0]) {
|
||||
log_debug("Found %s for %d:%d from sys", devname, major, minor);
|
||||
return _strdup(devname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* $ cat /sys/dev/block/253:3/dm/name
|
||||
* mpatha
|
||||
*/
|
||||
if (major == cmd->dev_types->device_mapper_major) {
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d/dm/name",
|
||||
dm_sysfs_dir(), major, minor) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!get_sysfs_value(path, namebuf, sizeof(namebuf), 0))
|
||||
return NULL;
|
||||
|
||||
if (dm_snprintf(devname, sizeof(devname), "/dev/mapper/%s", namebuf) < 0) {
|
||||
devname[0] = '\0';
|
||||
stack;
|
||||
}
|
||||
|
||||
if (devname[0]) {
|
||||
log_debug("Found %s for %d:%d from sys", devname, major, minor);
|
||||
return _strdup(devname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* /proc/partitions lists
|
||||
* major minor #blocks name
|
||||
*/
|
||||
|
||||
if (!(fp = fopen("/proc/partitions", "r")))
|
||||
return NULL;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (sscanf(line, "%u %u %llu %s", &line_major, &line_minor, (unsigned long long *)&line_blocks, namebuf) != 4)
|
||||
continue;
|
||||
if (line_major != major)
|
||||
continue;
|
||||
if (line_minor != minor)
|
||||
continue;
|
||||
|
||||
if (dm_snprintf(devname, sizeof(devname), "/dev/%s", namebuf) < 0) {
|
||||
devname[0] = '\0';
|
||||
stack;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (devname[0]) {
|
||||
log_debug("Found %s for %d:%d from proc", devname, major, minor);
|
||||
return _strdup(devname);
|
||||
}
|
||||
|
||||
/*
|
||||
* If necessary, this could continue searching by stat'ing /dev entries.
|
||||
*/
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname)
|
||||
{
|
||||
struct stat buf;
|
||||
struct device *dev;
|
||||
|
||||
if (stat(devname, &buf) < 0) {
|
||||
log_error("Cannot access device %s.", devname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISBLK(buf.st_mode)) {
|
||||
log_error("Invaild device type %s.", devname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_insert_dev(devname, buf.st_rdev))
|
||||
return_0;
|
||||
|
||||
if (!(dev = (struct device *) dm_hash_lookup(_cache.names, devname)))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno)
|
||||
{
|
||||
const char *devname;
|
||||
|
||||
if (!(devname = _get_devname_from_devno(cmd, devno)))
|
||||
return_0;
|
||||
|
||||
return setup_devname_in_dev_cache(cmd, devname);
|
||||
}
|
||||
|
||||
|
@@ -77,11 +77,7 @@ int get_dm_uuid_from_sysfs(char *buf, size_t buf_size, int major, int minor);
|
||||
|
||||
int setup_devices_file(struct cmd_context *cmd);
|
||||
int setup_devices(struct cmd_context *cmd);
|
||||
int setup_devices_no_file_match(struct cmd_context *cmd);
|
||||
int setup_device(struct cmd_context *cmd, const char *devname);
|
||||
|
||||
/* Normal device setup functions are split up for pvscan optimization. */
|
||||
int setup_devices_for_pvscan_cache(struct cmd_context *cmd);
|
||||
int setup_devname_in_dev_cache(struct cmd_context *cmd, const char *devname);
|
||||
int setup_devno_in_dev_cache(struct cmd_context *cmd, dev_t devno);
|
||||
|
||||
#endif
|
||||
|
@@ -74,6 +74,8 @@ void unlink_searched_devnames(struct cmd_context *cmd)
|
||||
|
||||
if (unlink(_searched_file))
|
||||
log_debug("unlink %s errno %d", _searched_file, errno);
|
||||
else
|
||||
log_debug("unlink %s", _searched_file);
|
||||
}
|
||||
|
||||
static int _searched_devnames_exists(struct cmd_context *cmd)
|
||||
@@ -302,6 +304,7 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
|
||||
{
|
||||
char sysbuf[PATH_MAX] = { 0 };
|
||||
const char *idname = NULL;
|
||||
int i;
|
||||
|
||||
if (idtype == DEV_ID_TYPE_SYS_WWID) {
|
||||
read_sys_block(cmd, dev, "device/wwid", sysbuf, sizeof(sysbuf));
|
||||
@@ -309,10 +312,6 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
|
||||
if (!sysbuf[0])
|
||||
read_sys_block(cmd, dev, "wwid", sysbuf, sizeof(sysbuf));
|
||||
|
||||
/* scsi_debug wwid begins "t10.Linux scsi_debug ..." */
|
||||
if (strstr(sysbuf, "scsi_debug"))
|
||||
sysbuf[0] = '\0';
|
||||
|
||||
/* qemu wwid begins "t10.ATA QEMU HARDDISK ..." */
|
||||
if (strstr(sysbuf, "QEMU HARDDISK"))
|
||||
sysbuf[0] = '\0';
|
||||
@@ -353,6 +352,11 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u
|
||||
return idname;
|
||||
}
|
||||
|
||||
for (i = 0; i < strlen(sysbuf); i++) {
|
||||
if (isblank(sysbuf[i]) || isspace(sysbuf[i]) || iscntrl(sysbuf[i]))
|
||||
sysbuf[i] = '_';
|
||||
}
|
||||
|
||||
if (!sysbuf[0])
|
||||
goto_bad;
|
||||
|
||||
@@ -671,6 +675,9 @@ int device_ids_write(struct cmd_context *cmd)
|
||||
cmd->enable_devices_file = 1;
|
||||
}
|
||||
|
||||
if (test_mode())
|
||||
return 1;
|
||||
|
||||
if (_devices_file_version[0]) {
|
||||
if (sscanf(_devices_file_version, "%u.%u.%u", &df_major, &df_minor, &df_counter) != 3) {
|
||||
/* don't update a file we can't parse */
|
||||
@@ -780,7 +787,7 @@ static void _device_ids_update_try(struct cmd_context *cmd)
|
||||
|
||||
/* Defer updates to non-pvscan-cache commands. */
|
||||
if (cmd->pvscan_cache_single) {
|
||||
log_print("pvscan[%d] skip updating devices file.", getpid());
|
||||
log_print("Devices file update skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1360,6 +1367,10 @@ void device_id_update_vg_uuid(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
static int _idtype_compatible_with_major_number(struct cmd_context *cmd, int idtype, int major)
|
||||
{
|
||||
/* devname can be used with any kind of device */
|
||||
if (idtype == DEV_ID_TYPE_DEVNAME)
|
||||
return 1;
|
||||
|
||||
if (idtype == DEV_ID_TYPE_MPATH_UUID ||
|
||||
idtype == DEV_ID_TYPE_CRYPT_UUID ||
|
||||
idtype == DEV_ID_TYPE_LVMLV_UUID)
|
||||
@@ -1388,6 +1399,43 @@ static int _idtype_compatible_with_major_number(struct cmd_context *cmd, int idt
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _match_dm_devnames(struct cmd_context *cmd, struct device *dev,
|
||||
struct dev_id *id, struct dev_use *du)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (MAJOR(dev->dev) != cmd->dev_types->device_mapper_major)
|
||||
return 0;
|
||||
|
||||
if (id->idname && du->idname && !strcmp(id->idname, du->idname))
|
||||
return 1;
|
||||
|
||||
if (du->idname && !strcmp(du->idname, dev_name(dev))) {
|
||||
log_debug("Match device_id %s %s to %s: ignoring idname %s",
|
||||
idtype_to_str(du->idtype), du->idname, dev_name(dev), id->idname ?: ".");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!du->idname)
|
||||
return 0;
|
||||
|
||||
/* detect that a du entry is for a dm device */
|
||||
|
||||
if (!strncmp(du->idname, "/dev/dm-", 8) || !strncmp(du->idname, "/dev/mapper/", 12)) {
|
||||
if (stat(du->idname, &buf))
|
||||
return 0;
|
||||
|
||||
if ((MAJOR(buf.st_rdev) == cmd->dev_types->device_mapper_major) &&
|
||||
(MINOR(buf.st_rdev) == MINOR(dev->dev))) {
|
||||
log_debug("Match device_id %s %s to %s: using other dm name, ignoring %s",
|
||||
idtype_to_str(du->idtype), du->idname, dev_name(dev), id->idname ?: ".");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for dev->ids entry with du->idtype, if found compare it,
|
||||
* if not, system_read of this type and add entry to dev->ids, compare it.
|
||||
@@ -1400,43 +1448,74 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
|
||||
const char *idname;
|
||||
int part;
|
||||
|
||||
if (!du->idname || !du->idtype)
|
||||
/*
|
||||
* The idname will be removed from an entry with devname type when the
|
||||
* devname is read and found to hold a different PVID than the PVID in
|
||||
* the entry. At that point we only have the PVID and no known
|
||||
* location for it.
|
||||
*/
|
||||
if (!du->idname || !du->idtype) {
|
||||
/*
|
||||
log_debug("Mismatch device_id %s %s %s to %s",
|
||||
du->idtype ? idtype_to_str(du->idtype) : "idtype_missing",
|
||||
du->idname ? du->idname : "idname_missing",
|
||||
du->devname ? du->devname : "devname_missing",
|
||||
dev_name(dev));
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some idtypes can only match devices with a specific major number,
|
||||
* so we can skip trying to match certain du entries based simply on
|
||||
* the major number of dev.
|
||||
*/
|
||||
if (!_idtype_compatible_with_major_number(cmd, du->idtype, (int)MAJOR(dev->dev)))
|
||||
if (!_idtype_compatible_with_major_number(cmd, du->idtype, (int)MAJOR(dev->dev))) {
|
||||
/*
|
||||
log_debug("Mismatch device_id %s %s to %s: wrong major",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_get_partition_number(dev, &part)) {
|
||||
log_debug("compare %s failed to get dev partition", dev_name(dev));
|
||||
/*
|
||||
log_debug("Mismatch device_id %s %s to %s: no partition",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (part != du->part) {
|
||||
/*
|
||||
log_debug("compare mis %s %s part %d to %s part %d",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", du->part, dev_name(dev), part);
|
||||
log_debug("Mismatch device_id %s %s to %s: wrong partition %d vs %d",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), du->part, part);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(id, &dev->ids) {
|
||||
if (id->idtype == du->idtype) {
|
||||
if (id->idname && !strcmp(id->idname, du->idname)) {
|
||||
if ((id->idtype == DEV_ID_TYPE_DEVNAME) && _match_dm_devnames(cmd, dev, id, du)) {
|
||||
/* dm devs can have differing names that we know still match */
|
||||
du->dev = dev;
|
||||
dev->id = id;
|
||||
dev->flags |= DEV_MATCHED_USE_ID;
|
||||
log_debug("Match device_id %s %s to %s: dm names",
|
||||
idtype_to_str(du->idtype), du->idname, dev_name(dev));
|
||||
return 1;
|
||||
|
||||
} else if (id->idname && !strcmp(id->idname, du->idname)) {
|
||||
du->dev = dev;
|
||||
dev->id = id;
|
||||
dev->flags |= DEV_MATCHED_USE_ID;
|
||||
log_debug("Match device_id %s %s to %s",
|
||||
idtype_to_str(du->idtype), du->idname, dev_name(dev));
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
/*
|
||||
log_debug("compare mis %s %s to %s %s",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev),
|
||||
((id->idtype != DEV_ID_TYPE_DEVNAME) && id->idname) ? id->idname : "");
|
||||
log_debug("Mismatch device_id %s %s to %s: idname %s",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), id->idname ?: ":");
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
@@ -1456,7 +1535,7 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
|
||||
id->dev = dev;
|
||||
dm_list_add(&dev->ids, &id->list);
|
||||
/*
|
||||
log_debug("compare mis %s %s to %s no idtype",
|
||||
log_debug("Mismatch device_id %s %s to %s: no idtype",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev));
|
||||
*/
|
||||
return 0;
|
||||
@@ -1481,9 +1560,8 @@ static int _match_du_to_dev(struct cmd_context *cmd, struct dev_use *du, struct
|
||||
}
|
||||
|
||||
/*
|
||||
log_debug("compare mis %s %s to %s %s",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev),
|
||||
((id->idtype != DEV_ID_TYPE_DEVNAME) && id->idname) ? id->idname : "");
|
||||
log_debug("Mismatch device_id %s %s to %s: idname %s",
|
||||
idtype_to_str(du->idtype), du->idname ?: ".", dev_name(dev), idname);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
@@ -1534,22 +1612,6 @@ int device_ids_match_dev(struct cmd_context *cmd, struct device *dev)
|
||||
* passes the filter.
|
||||
*/
|
||||
|
||||
void device_ids_match_device_list(struct cmd_context *cmd)
|
||||
{
|
||||
struct dev_use *du;
|
||||
|
||||
dm_list_iterate_items(du, &cmd->use_devices) {
|
||||
if (du->dev)
|
||||
continue;
|
||||
if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) {
|
||||
log_warn("Device not found for %s.", du->devname);
|
||||
} else {
|
||||
/* Should we set dev->id? Which idtype? Use --deviceidtype? */
|
||||
du->dev->flags |= DEV_MATCHED_USE_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void device_ids_match(struct cmd_context *cmd)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
@@ -1557,7 +1619,16 @@ void device_ids_match(struct cmd_context *cmd)
|
||||
struct device *dev;
|
||||
|
||||
if (cmd->enable_devices_list) {
|
||||
device_ids_match_device_list(cmd);
|
||||
dm_list_iterate_items(du, &cmd->use_devices) {
|
||||
if (du->dev)
|
||||
continue;
|
||||
if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) {
|
||||
log_warn("Device not found for %s.", du->devname);
|
||||
} else {
|
||||
/* Should we set dev->id? Which idtype? Use --deviceidtype? */
|
||||
du->dev->flags |= DEV_MATCHED_USE_ID;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1907,6 +1978,14 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs,
|
||||
*device_ids_invalid = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When a new devname/pvid mismatch is discovered, a new search for the
|
||||
* pvid should be permitted (searched_devnames may exist to suppress
|
||||
* searching for other pvids.)
|
||||
*/
|
||||
if (update_file)
|
||||
unlink_searched_devnames(cmd);
|
||||
|
||||
/* FIXME: for wrong devname cases, wait to write new until device_ids_find_renamed_devs? */
|
||||
|
||||
/*
|
||||
@@ -1975,12 +2054,19 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
|
||||
search_auto = !strcmp(cmd->search_for_devnames, "auto");
|
||||
|
||||
dm_list_iterate_items(du, &cmd->use_devices) {
|
||||
if (du->dev)
|
||||
continue;
|
||||
if (!du->pvid)
|
||||
continue;
|
||||
if (du->idtype != DEV_ID_TYPE_DEVNAME)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* if the old incorrect devname is now a device that's
|
||||
* filtered and not scanned, e.g. an mpath component,
|
||||
* then we want to look for the pvid on a new device.
|
||||
*/
|
||||
if (du->dev && !du->dev->filtered_flags)
|
||||
continue;
|
||||
|
||||
if (!(dil = dm_pool_zalloc(cmd->mem, sizeof(*dil))))
|
||||
continue;
|
||||
|
||||
@@ -2005,6 +2091,11 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l
|
||||
* the searched file, so a subsequent lvm command will do the search
|
||||
* again. In future perhaps we could add a policy to automatically
|
||||
* remove a devices file entry that's not been found for some time.
|
||||
*
|
||||
* TODO: like the hint file, add a hash of all devnames to the searched
|
||||
* file so it can be ignored and removed if the devs/hash change.
|
||||
* If hints are enabled, the hints invalidation could also remove the
|
||||
* searched file.
|
||||
*/
|
||||
if (_searched_devnames_exists(cmd)) {
|
||||
log_debug("Search for PVIDs skipped for %s", _searched_file);
|
||||
|
@@ -32,7 +32,6 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid,
|
||||
void device_id_pvremove(struct cmd_context *cmd, struct device *dev);
|
||||
void device_ids_match(struct cmd_context *cmd);
|
||||
int device_ids_match_dev(struct cmd_context *cmd, struct device *dev);
|
||||
void device_ids_match_device_list(struct cmd_context *cmd);
|
||||
void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, int *device_ids_invalid, int noupdate);
|
||||
int device_ids_version_unchanged(struct cmd_context *cmd);
|
||||
void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_list, int *search_count, int noupdate);
|
||||
|
@@ -15,268 +15,41 @@
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/filters/filter.h"
|
||||
|
||||
static int _sys_dev_block_found;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <dirent.h>
|
||||
|
||||
static int _locate_sysfs_blocks(const char *sysfs_dir, char *path, size_t len,
|
||||
unsigned *sysfs_depth)
|
||||
{
|
||||
struct stat info;
|
||||
unsigned i;
|
||||
static const struct dir_class {
|
||||
const char path[32];
|
||||
int depth;
|
||||
} classes[] = {
|
||||
/*
|
||||
* unified classification directory for all kernel subsystems
|
||||
*
|
||||
* /sys/subsystem/block/devices
|
||||
* |-- sda -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
|
||||
* |-- sda1 -> ../../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
|
||||
* `-- sr0 -> ../../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
|
||||
*
|
||||
*/
|
||||
{ "subsystem/block/devices", 0 },
|
||||
|
||||
/*
|
||||
* block subsystem as a class
|
||||
*
|
||||
* /sys/class/block
|
||||
* |-- sda -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda
|
||||
* |-- sda1 -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1
|
||||
* `-- sr0 -> ../../devices/pci0000:00/0000:00:1f.2/host1/target1:0:0/1:0:0:0/block/sr0
|
||||
*
|
||||
*/
|
||||
{ "class/block", 0 },
|
||||
|
||||
/*
|
||||
* old block subsystem layout with nested directories
|
||||
*
|
||||
* /sys/block/
|
||||
* |-- sda
|
||||
* | |-- capability
|
||||
* | |-- dev
|
||||
* ...
|
||||
* | |-- sda1
|
||||
* | | |-- dev
|
||||
* ...
|
||||
* |
|
||||
* `-- sr0
|
||||
* |-- capability
|
||||
* |-- dev
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
|
||||
{ "block", 1 }
|
||||
};
|
||||
|
||||
for (i = 0; i < DM_ARRAY_SIZE(classes); ++i)
|
||||
if ((dm_snprintf(path, len, "%s%s", sysfs_dir, classes[i].path) >= 0) &&
|
||||
(stat(path, &info) == 0)) {
|
||||
*sysfs_depth = classes[i].depth;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* We need to store a set of dev_t.
|
||||
*--------------------------------------------------------------*/
|
||||
struct entry {
|
||||
struct entry *next;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
#define SET_BUCKETS 64
|
||||
struct dev_set {
|
||||
struct dm_pool *mem;
|
||||
const char *sys_block;
|
||||
unsigned sysfs_depth;
|
||||
int initialised;
|
||||
struct entry *slots[SET_BUCKETS];
|
||||
};
|
||||
|
||||
static struct dev_set *_dev_set_create(struct dm_pool *mem,
|
||||
const char *sys_block,
|
||||
unsigned sysfs_depth)
|
||||
{
|
||||
struct dev_set *ds;
|
||||
|
||||
if (!(ds = dm_pool_zalloc(mem, sizeof(*ds))))
|
||||
return NULL;
|
||||
|
||||
ds->mem = mem;
|
||||
if (!(ds->sys_block = dm_pool_strdup(mem, sys_block)))
|
||||
return NULL;
|
||||
|
||||
ds->sysfs_depth = sysfs_depth;
|
||||
ds->initialised = 0;
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
static unsigned _hash_dev(dev_t dev)
|
||||
{
|
||||
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Doesn't check that the set already contains dev.
|
||||
*/
|
||||
static int _set_insert(struct dev_set *ds, dev_t dev)
|
||||
{
|
||||
struct entry *e;
|
||||
unsigned h = _hash_dev(dev);
|
||||
|
||||
if (!(e = dm_pool_alloc(ds->mem, sizeof(*e))))
|
||||
return 0;
|
||||
|
||||
e->next = ds->slots[h];
|
||||
e->dev = dev;
|
||||
ds->slots[h] = e;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _set_lookup(struct dev_set *ds, dev_t dev)
|
||||
{
|
||||
unsigned h = _hash_dev(dev);
|
||||
struct entry *e;
|
||||
|
||||
for (e = ds->slots[h]; e; e = e->next)
|
||||
if (e->dev == dev)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------
|
||||
* filter methods
|
||||
*--------------------------------------------------------------*/
|
||||
static int _parse_dev(const char *file, FILE *fp, dev_t *result)
|
||||
{
|
||||
unsigned major, minor;
|
||||
char buffer[64];
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||
log_error("Empty sysfs device file: %s", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
|
||||
log_error("Incorrect format for sysfs device file: %s.", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*result = makedev(major, minor);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_dev(const char *file, dev_t *result)
|
||||
{
|
||||
int r;
|
||||
FILE *fp;
|
||||
|
||||
if (!(fp = fopen(file, "r"))) {
|
||||
log_sys_error("fopen", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _parse_dev(file, fp, result);
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", file);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recurse through sysfs directories, inserting any devs found.
|
||||
*/
|
||||
static int _read_devs(struct dev_set *ds, const char *dir, unsigned sysfs_depth)
|
||||
{
|
||||
struct dirent *d;
|
||||
DIR *dr;
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
char file[PATH_MAX];
|
||||
dev_t dev = { 0 };
|
||||
int r = 1;
|
||||
|
||||
if (!(dr = opendir(dir))) {
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((d = readdir(dr))) {
|
||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||
continue;
|
||||
|
||||
if (dm_snprintf(path, sizeof(path), "%s/%s", dir,
|
||||
d->d_name) < 0) {
|
||||
log_warn("WARNING: sysfs path name too long: %s in %s.",
|
||||
d->d_name, dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* devices have a "dev" file */
|
||||
if (dm_snprintf(file, sizeof(file), "%s/dev", path) < 0) {
|
||||
log_warn("WARNING: sysfs path name too long: %s in %s.",
|
||||
d->d_name, dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!stat(file, &info)) {
|
||||
/* recurse if we found a device and expect subdirs */
|
||||
if (sysfs_depth)
|
||||
_read_devs(ds, path, sysfs_depth - 1);
|
||||
|
||||
/* add the device we have found */
|
||||
if (_read_dev(file, &dev))
|
||||
_set_insert(ds, dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (closedir(dr))
|
||||
log_sys_debug("closedir", dir);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _init_devs(struct dev_set *ds)
|
||||
{
|
||||
if (!_read_devs(ds, ds->sys_block, ds->sysfs_depth)) {
|
||||
ds->initialised = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ds->initialised = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
char path[PATH_MAX];
|
||||
const char *sysfs_dir;
|
||||
struct stat info;
|
||||
|
||||
if (!_sys_dev_block_found)
|
||||
return 1;
|
||||
|
||||
dev->filtered_flags &= ~DEV_FILTERED_SYSFS;
|
||||
|
||||
if (!ds->initialised)
|
||||
_init_devs(ds);
|
||||
|
||||
/* Pass through if initialisation failed */
|
||||
if (ds->initialised != 1)
|
||||
/*
|
||||
* Any kind of device id other than devname has been set
|
||||
* using sysfs so we know that sysfs info exists for dev.
|
||||
*/
|
||||
if (dev->id && dev->id->idtype && (dev->id->idtype != DEV_ID_TYPE_DEVNAME))
|
||||
return 1;
|
||||
|
||||
if (!_set_lookup(ds, dev->dev)) {
|
||||
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_SYSFS;
|
||||
return 0;
|
||||
sysfs_dir = dm_sysfs_dir();
|
||||
if (sysfs_dir && *sysfs_dir) {
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d",
|
||||
sysfs_dir, (int)MAJOR(dev->dev), (int)MINOR(dev->dev)) < 0) {
|
||||
log_debug("failed to create sysfs path");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lstat(path, &info)) {
|
||||
log_debug_devs("%s: Skipping (sysfs)", dev_name(dev));
|
||||
dev->filtered_flags |= DEV_FILTERED_SYSFS;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -284,21 +57,34 @@ static int _accept_p(struct cmd_context *cmd, struct dev_filter *f, struct devic
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
struct dev_set *ds = (struct dev_set *) f->private;
|
||||
|
||||
if (f->use_count)
|
||||
log_error(INTERNAL_ERROR "Destroying sysfs filter while in use %u times.", f->use_count);
|
||||
free(f);
|
||||
}
|
||||
|
||||
dm_pool_destroy(ds->mem);
|
||||
static void _check_sys_dev_block(void)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
const char *sysfs_dir;
|
||||
struct stat info;
|
||||
|
||||
sysfs_dir = dm_sysfs_dir();
|
||||
if (sysfs_dir && *sysfs_dir) {
|
||||
if (dm_snprintf(path, sizeof(path), "%sdev/block", sysfs_dir) < 0)
|
||||
return;
|
||||
|
||||
if (lstat(path, &info)) {
|
||||
log_debug("filter-sysfs disabled: /sys/dev/block not found");
|
||||
_sys_dev_block_found = 0;
|
||||
} else {
|
||||
_sys_dev_block_found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dev_filter *sysfs_filter_create(void)
|
||||
{
|
||||
const char *sysfs_dir = dm_sysfs_dir();
|
||||
char sys_block[PATH_MAX];
|
||||
unsigned sysfs_depth;
|
||||
struct dm_pool *mem;
|
||||
struct dev_set *ds;
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!*sysfs_dir) {
|
||||
@@ -306,26 +92,15 @@ struct dev_filter *sysfs_filter_create(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_locate_sysfs_blocks(sysfs_dir, sys_block, sizeof(sys_block), &sysfs_depth))
|
||||
return NULL;
|
||||
/* support old kernels that don't have this */
|
||||
_check_sys_dev_block();
|
||||
|
||||
if (!(mem = dm_pool_create("sysfs", 256))) {
|
||||
log_error("sysfs pool creation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ds = _dev_set_create(mem, sys_block, sysfs_depth))) {
|
||||
log_error("sysfs dev_set creation failed");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
if (!(f = zalloc(sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
f->use_count = 0;
|
||||
f->private = ds;
|
||||
f->name = "sysfs";
|
||||
|
||||
log_debug_devs("Sysfs filter initialised.");
|
||||
@@ -333,7 +108,6 @@ struct dev_filter *sysfs_filter_create(void)
|
||||
return f;
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -219,7 +219,7 @@ static void _remove_expired(const char *dir, const char *vgname,
|
||||
|
||||
sum /= 1024 * 1024;
|
||||
if (sum > 128 || archives_size > 8192)
|
||||
log_print_unless_silent("Consider prunning %s VG archive with more then %u MiB in %u files (check archiving is needed in lvm.conf).",
|
||||
log_print_unless_silent("Consider pruning %s VG archive with more then %u MiB in %u files (check archiving is needed in lvm.conf).",
|
||||
vgname, (unsigned)sum, archives_size);
|
||||
}
|
||||
|
||||
|
@@ -365,7 +365,6 @@ static void _unlock_hints(struct cmd_context *cmd)
|
||||
|
||||
void hints_exit(struct cmd_context *cmd)
|
||||
{
|
||||
free_hints(&cmd->hints);
|
||||
if (_hints_fd == -1)
|
||||
return;
|
||||
_unlock_hints(cmd);
|
||||
@@ -1391,6 +1390,16 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints,
|
||||
log_debug("get_hints: needs refresh");
|
||||
free_hints(&hints_list);
|
||||
|
||||
/*
|
||||
* This is not related to hints, and is probably unnecessary,
|
||||
* but it could possibly help. When hints become invalid it's
|
||||
* usually becaues devs on the system have changed, and that
|
||||
* also means that a missing devices file entry might be found
|
||||
* by searching devices again. (the searched_devnames
|
||||
* mechanism should eventually be replaced)
|
||||
*/
|
||||
unlink_searched_devnames(cmd);
|
||||
|
||||
if (!_lock_hints(cmd, LOCK_EX, NONBLOCK))
|
||||
return 0;
|
||||
|
||||
|
@@ -891,7 +891,7 @@ static int _setup_bcache(void)
|
||||
|
||||
#define BASE_FD_COUNT 32 /* Number of open files we want apart from devs */
|
||||
|
||||
static void _prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
|
||||
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs)
|
||||
{
|
||||
#ifdef HAVE_PRLIMIT
|
||||
struct rlimit old = { 0 }, new;
|
||||
@@ -1165,7 +1165,7 @@ int label_scan(struct cmd_context *cmd)
|
||||
* which we want to keep open) is higher than the current
|
||||
* soft limit.
|
||||
*/
|
||||
_prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
|
||||
prepare_open_file_limit(cmd, dm_list_size(&scan_devs));
|
||||
|
||||
/*
|
||||
* Do the main scan.
|
||||
@@ -1207,8 +1207,6 @@ int label_scan(struct cmd_context *cmd)
|
||||
(unsigned long long)want_size_kb);
|
||||
}
|
||||
|
||||
dm_list_init(&cmd->hints);
|
||||
|
||||
/*
|
||||
* If we're using hints to limit which devs we scanned, verify
|
||||
* that those hints were valid, and if not we need to scan the
|
||||
@@ -1220,18 +1218,16 @@ int label_scan(struct cmd_context *cmd)
|
||||
_scan_list(cmd, cmd->filter, &all_devs, 0, NULL);
|
||||
/* scan_devs are the devs that have been scanned */
|
||||
dm_list_splice(&scan_devs, &all_devs);
|
||||
free_hints(&hints_list);
|
||||
using_hints = 0;
|
||||
create_hints = 0;
|
||||
/* invalid hints means a new dev probably appeared and
|
||||
we should search for any missing pvids again. */
|
||||
unlink_searched_devnames(cmd);
|
||||
} else {
|
||||
/* The hints may be used by another device iteration. */
|
||||
dm_list_splice(&cmd->hints, &hints_list);
|
||||
}
|
||||
}
|
||||
|
||||
free_hints(&hints_list);
|
||||
|
||||
/*
|
||||
* Check if the devices_file content is up to date and
|
||||
* if not update it.
|
||||
|
@@ -134,4 +134,6 @@ void dev_invalidate(struct device *dev);
|
||||
void dev_set_last_byte(struct device *dev, uint64_t offset);
|
||||
void dev_unset_last_byte(struct device *dev);
|
||||
|
||||
void prepare_open_file_limit(struct cmd_context *cmd, unsigned int num_devs);
|
||||
|
||||
#endif
|
||||
|
@@ -892,6 +892,7 @@ uint32_t log_journal_str_to_val(const char *str)
|
||||
return LOG_JOURNAL_OUTPUT;
|
||||
if (!strcasecmp(str, "debug"))
|
||||
return LOG_JOURNAL_DEBUG;
|
||||
log_warn("Ignoring unrecognized journal value.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@ CMIRRORDMAN = cmirrord.8
|
||||
LVMDBUSDMAN = lvmdbusd.8
|
||||
|
||||
MAN5=lvm.conf.5
|
||||
MAN7=lvmsystemid.7 lvmreport.7 lvmraid.7
|
||||
MAN7=lvmsystemid.7 lvmreport.7 lvmraid.7 lvmautoactivation.7
|
||||
|
||||
MAN8=lvm.8 lvmdump.8 lvm-fullreport.8 lvm-lvpoll.8 \
|
||||
lvcreate.8 lvchange.8 lvmconfig.8 lvconvert.8 lvdisplay.8 \
|
||||
|
@@ -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
|
||||
.
|
||||
|
@@ -579,6 +579,7 @@ Prepends source file name and code line number with libdm debugging.
|
||||
.BR lvmraid (7),
|
||||
.BR lvmthin (7),
|
||||
.BR lvmcache (7),
|
||||
.BR lvmautoactivation (7),
|
||||
.P
|
||||
.BR dmsetup (8),
|
||||
.BR dmstats (8),
|
||||
|
314
man/lvmautoactivation.7_main
Normal file
314
man/lvmautoactivation.7_main
Normal file
@@ -0,0 +1,314 @@
|
||||
.TH "LVMAUTOACTIVATION" "7" "LVM TOOLS #VERSION#" "Red Hat, Inc" "\""
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
lvmautoactivation \(em LVM autoactivation
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
.
|
||||
Autoactivation is the activation of LVs performed automatically by the
|
||||
system in response to LVM devices being attached to the machine. When all
|
||||
PVs in a VG have been attached, the VG is complete, and LVs in the VG are
|
||||
activated.
|
||||
.P
|
||||
Autoactivation of VGs, or specific LVs, can be prevented using vgchange or
|
||||
lvchange --setautoactivation n. The lvm.conf auto_activation_volume_list
|
||||
is another way to limit autoactivation.
|
||||
.
|
||||
.SS event autoactivation
|
||||
.P
|
||||
The most common form of autoactivation is "event based", in which complete
|
||||
VGs are activated in response to uevents which occur during system startup
|
||||
or at any time after the system has started. Another form of
|
||||
autoactivation is "static" in which complete VGs are activated at a fixed
|
||||
point during system startup by a systemd service, and not in response to
|
||||
events. This can be controlled with the lvm.conf setting
|
||||
event_activation.
|
||||
.P
|
||||
Event based autoactivation is driven by udev, udev rules, and systemd.
|
||||
When a device is attached to a machine, a uevent is generated by the
|
||||
kernel to notify userspace of the new device. systemd-udev runs udev
|
||||
rules to process the new device. Udev rules use blkid to identify the
|
||||
device as an LVM PV and then execute the lvm-specific udev rule for the
|
||||
device, which triggers autoactivation.
|
||||
.P
|
||||
There are two variations of event baed autoactivation that may be used on
|
||||
a system, depending on the LVM udev rule that is installed (found in
|
||||
/lib/udev/rules.d/.) The following summarizes the steps in each rule
|
||||
which lead to autoactivation:
|
||||
.P
|
||||
.B 69-dm-lvm-metad.rules
|
||||
.
|
||||
.IP \[bu] 2
|
||||
device /dev/name with major:minor X:Y is attached to the machine
|
||||
.
|
||||
.IP \[bu] 2
|
||||
systemd/udev runs blkid to identify /dev/name as an LVM PV
|
||||
.
|
||||
.IP \[bu] 2
|
||||
udev rule 69-dm-lvm-metad.rules is run for /dev/name
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the lvm udev rule runs the systemd service lvm2-pvscan@X:Yservice
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the lvm2-pvscan service runs:
|
||||
.br
|
||||
pvscan --cache -aay --major X --minor Y
|
||||
.
|
||||
.IP \[bu] 2
|
||||
pvscan reads the device, records that the PV is online
|
||||
(see pvs_online), and checks if the VG is complete.
|
||||
.
|
||||
.IP \[bu] 2
|
||||
if the VG is complete, pvscan creates the vgs_online temp file,
|
||||
and activates the VG.
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the activation command output can be seen from
|
||||
systemctl status lvm2-pvscan*
|
||||
.P
|
||||
.B 69-dm-lvm.rules
|
||||
.
|
||||
.IP \[bu] 2
|
||||
device /dev/name with major:minor X:Y is attached to the machine
|
||||
.
|
||||
.IP \[bu] 2
|
||||
systemd/udev runs blkid to identify /dev/name as an LVM PV
|
||||
.
|
||||
.IP \[bu] 2
|
||||
udev rule 69-dm-lvm.rules is run for /dev/name
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the lvm udev rule runs:
|
||||
.br
|
||||
pvscan --cache --listvg --checkcomplete --vgonline
|
||||
.br
|
||||
--autoactivation event --udevoutput --journal=output /dev/name
|
||||
.
|
||||
.IP \[bu] 2
|
||||
pvscan reads the device, records that the PV is online
|
||||
(see pvs_online), and checks if the VG is complete.
|
||||
.
|
||||
.IP \[bu] 2
|
||||
if the VG is complete, pvscan creates the vgs_online temp file,
|
||||
and prints the name of the VG for the udev rule to import:
|
||||
LVM_VG_NAME_COMPLETE='vgname'
|
||||
.
|
||||
.IP \[bu] 2
|
||||
if the lvm udev rule sees LVM_VG_NAME_COMPLETE from pvscan,
|
||||
it activates the VG using a transient systemd service named
|
||||
lvm-activate-<vgname>.
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the lvm-activate-<vgname> service runs
|
||||
.br
|
||||
vgchange -aay --autoactivation event <vgname>
|
||||
.
|
||||
.IP \[bu] 2
|
||||
the activation command output can be seen from
|
||||
journalctl -u lvm-activate-<vgname>
|
||||
.P
|
||||
.
|
||||
.SS pvscan options
|
||||
.P
|
||||
.B --cache
|
||||
.br
|
||||
Read the <device> arg (and only that device), and record that
|
||||
the PV is online by creating the /run/lvm/pvs_online/<pvid>
|
||||
file containing the name of the VG and the device for the PV.
|
||||
.P
|
||||
.B -aay
|
||||
.br
|
||||
Activate the VG from the pvscan command
|
||||
(includes implicit --checkcomplete and --vgonline.)
|
||||
.P
|
||||
.B --checkcomplete
|
||||
.br
|
||||
Check if the VG is complete, i.e. all PVs are present on
|
||||
the system, by checking /run/lvm/pvs_online/<pvid> files.
|
||||
.P
|
||||
.B --vgonline
|
||||
.br
|
||||
Create /run/lvm/vgs_online/<vgname> if the VG is complete
|
||||
(used to ensure only one command performs activation.)
|
||||
.P
|
||||
.B --autoactivation event
|
||||
.br
|
||||
Inform the command it is used for event based autoactivation.
|
||||
.P
|
||||
.B --listvg
|
||||
.br
|
||||
Print the name of the VG using the device.
|
||||
.P
|
||||
.B --udevoutput
|
||||
.br
|
||||
Only print output that can be imported to the udev rule,
|
||||
using the udev environment key format, i.e. NAME='value'.
|
||||
.P
|
||||
.B --journal=output
|
||||
.br
|
||||
Send standard command output to the journal (when stdout
|
||||
is reserved for udev output.)
|
||||
.P
|
||||
.SS run files
|
||||
.P
|
||||
Autoactivation commands use a number of temp files in /run/lvm (with the
|
||||
expectation that /run is cleared between boots.)
|
||||
.P
|
||||
.B pvs_online
|
||||
.br
|
||||
pvscan --cache creates a file here for each PV that is attached. The file
|
||||
is named with the PVID and contains the VG name and device information.
|
||||
The existence of the file is used to determine when all PVs for a given VG
|
||||
are present. The device information in these files is also used to
|
||||
optimize locating devices for a VG when the VG is activated.
|
||||
.P
|
||||
.B pvs_lookup
|
||||
.br
|
||||
pvscan --cache creates a file here named for a VG (if one doesn't already
|
||||
exist.) The file contains a list of PVIDs in the VG. This is needed when
|
||||
a PV is processed which has no VG metadata, in which case the list of
|
||||
PVIDs from the lookup file is used to check if the VG is complete.
|
||||
.P
|
||||
.B vgs_online
|
||||
.br
|
||||
The first activation command (pvscan or vgchange) to create a file here,
|
||||
named for the VG, will activate the VG. This resolves a race when
|
||||
concurrent commands attempt to activate a VG at once.
|
||||
.
|
||||
.SS static autoactivation
|
||||
.P
|
||||
When event autoactivation is disabled by setting lvm.conf
|
||||
event_activation=0, autoactivation is performed at one or more static
|
||||
points during system startup. At these points, a vgchange -aay command is
|
||||
run to activate complete VGs from devices that are present on the system
|
||||
at that time. pvscan commands (and lvm2-pvscan services) do not perform
|
||||
autoactivation in this mode. pvscan commands may still be run from
|
||||
uevents but will do nothing when they read the event_activation=0 setting.
|
||||
.P
|
||||
The static vgchange -aay commands are run by three systemd services at
|
||||
three points during startup: lvm2-activation-early, lvm2-activation, and
|
||||
lvm2-activation-net. These static activation services are "generated
|
||||
services", so the service files are created at run time by the
|
||||
lvm2-activation-generator command (run by systemd).
|
||||
lvm2-activation-generator creates the services if lvm.conf
|
||||
event_activation=0.
|
||||
.P
|
||||
The limitation of this method is that devices may not be attached to the
|
||||
system (or set up) at a reliable point in time during startup, and they
|
||||
may not be present when the services run vgchange. In this case, the VGs
|
||||
will not be autoactivated. So, the timing of device attachment/setup
|
||||
determines whether static autoactivation will produce the same results as
|
||||
event autoactivation. For this reason, static autoactivation is not
|
||||
recommended.
|
||||
.P
|
||||
Sometimes, static autoactivation is mistakenly expected to disable all
|
||||
autoactivation of particular VGs. This may appear to be effective if those
|
||||
VGs are slow to be attached or set up. But, the only correct and reliable
|
||||
way to disable autoactivation is using vgchange/lvchange
|
||||
--setautoactivation n, or lvm.conf auto_activation_volume_list.
|
||||
.
|
||||
.SH EXAMPLES
|
||||
.P
|
||||
VG "vg" contains two PVs:
|
||||
.nf
|
||||
$ pvs -o name,vgname,uuid /dev/sdb /dev/sdc
|
||||
PV VG PV UUID
|
||||
/dev/sdb vg 1uKpaT-lFOZ-NLHX-j4jI-OBi1-QpdE-HZ5hZY
|
||||
/dev/sdc vg 5J3tM8-aIPe-2vbd-DBe7-bvRq-TGj0-DaKV2G
|
||||
.fi
|
||||
.P
|
||||
use of --cache:
|
||||
.nf
|
||||
$ pvscan --cache /dev/sdb
|
||||
pvscan[12922] PV /dev/sdb online.
|
||||
$ pvscan --cache /dev/sdc
|
||||
pvscan[12923] PV /dev/sdc online.
|
||||
|
||||
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
|
||||
8:16
|
||||
vg:vg
|
||||
dev:/dev/sdb
|
||||
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
|
||||
8:32
|
||||
vg:vg
|
||||
dev:/dev/sdc
|
||||
.fi
|
||||
.P
|
||||
use of -aay:
|
||||
.nf
|
||||
$ pvscan --cache -aay /dev/sdb
|
||||
pvscan[12935] PV /dev/sdb online, VG vg incomplete (need 1).
|
||||
$ pvscan --cache -aay /dev/sdc
|
||||
pvscan[12936] PV /dev/sdc online, VG vg is complete.
|
||||
pvscan[12936] VG vg run autoactivation.
|
||||
1 logical volume(s) in volume group "vg" now active
|
||||
|
||||
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
|
||||
8:16
|
||||
vg:vg
|
||||
dev:/dev/sdb
|
||||
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
|
||||
8:32
|
||||
vg:vg
|
||||
dev:/dev/sdc
|
||||
$ ls /run/lvm/vgs_online/vg
|
||||
/run/lvm/vgs_online/vg
|
||||
.fi
|
||||
.P
|
||||
use of --listvg:
|
||||
.nf
|
||||
$ pvscan --cache --listvg /dev/sdb
|
||||
VG vg
|
||||
$ pvscan --cache --listvg /dev/sdc
|
||||
VG vg
|
||||
|
||||
$ cat /run/lvm/pvs_online/1uKpaTlFOZNLHXj4jIOBi1QpdEHZ5hZY
|
||||
8:16
|
||||
vg:vg
|
||||
dev:/dev/sdb
|
||||
$ cat /run/lvm/pvs_online/5J3tM8aIPe2vbdDBe7bvRqTGj0DaKV2G
|
||||
8:32
|
||||
vg:vg
|
||||
dev:/dev/sdc
|
||||
.fi
|
||||
.P
|
||||
use of --checkcomplete:
|
||||
.nf
|
||||
$ pvscan --cache --listvg --checkcomplete --vgonline /dev/sdb
|
||||
pvscan[12996] PV /dev/sdb online, VG vg incomplete (need 1).
|
||||
VG vg incomplete
|
||||
$ pvscan --cache --listvg --checkcomplete --vgonline /dev/sdc
|
||||
pvscan[12997] PV /dev/sdc online, VG vg is complete.
|
||||
VG vg complete
|
||||
.fi
|
||||
.P
|
||||
use of --udevoutput:
|
||||
.nf
|
||||
$ pvscan --cache --listvg --checkcomplete --vgonline --udevoutput /dev/sdb
|
||||
LVM_VG_NAME_INCOMPLETE='vg'
|
||||
$ pvscan --cache --listvg --checkcomplete --vgonline --udevoutput /dev/sdc
|
||||
LVM_VG_NAME_COMPLETE='vg'
|
||||
.fi
|
||||
.P
|
||||
use of --listlvs:
|
||||
.nf
|
||||
$ lvs -o name,devices vg
|
||||
LV Devices
|
||||
lvol0 /dev/sdb(0)
|
||||
lvol1 /dev/sdc(0)
|
||||
lvol2 /dev/sdb(1),/dev/sdc(1)
|
||||
|
||||
$ pvscan --cache --listlvs --checkcomplete /dev/sdb
|
||||
pvscan[13288] PV /dev/sdb online, VG vg incomplete (need 1).
|
||||
VG vg incomplete
|
||||
LV vg/lvol0 complete
|
||||
LV vg/lvol2 incomplete
|
||||
$ pvscan --cache --listlvs --checkcomplete /dev/sdc
|
||||
pvscan[13289] PV /dev/sdc online, VG vg is complete.
|
||||
VG vg complete
|
||||
LV vg/lvol1 complete
|
||||
LV vg/lvol2 complete
|
||||
.fi
|
||||
|
@@ -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.
|
||||
|
@@ -4,56 +4,47 @@ 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.
|
||||
|
@@ -91,59 +91,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
|
||||
.
|
||||
|
@@ -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.
|
||||
|
@@ -92,6 +92,7 @@ install_systemd_generators:
|
||||
install_systemd_units: install_dbus_service
|
||||
@echo " [INSTALL] systemd_units"
|
||||
$(Q) $(INSTALL_DIR) $(systemd_unit_dir)
|
||||
$(Q) $(INSTALL_DATA) lvm2-pvscan.service $(systemd_unit_dir)/lvm2-pvscan@.service
|
||||
ifeq ("@BUILD_DMEVENTD@", "yes")
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket
|
||||
$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service
|
||||
|
@@ -88,6 +88,7 @@ fi
|
||||
%{_sbindir}/lvmpolld
|
||||
%endif
|
||||
%{_mandir}/man5/lvm.conf.5.gz
|
||||
%{_mandir}/man7/lvmautoactivation.7.gz
|
||||
%{_mandir}/man7/lvmsystemid.7.gz
|
||||
%{_mandir}/man7/lvmreport.7.gz
|
||||
%{_mandir}/man7/lvmraid.7.gz
|
||||
@@ -163,7 +164,7 @@ fi
|
||||
%endif
|
||||
%if %{enable_udev}
|
||||
%{_udevdir}/11-dm-lvm.rules
|
||||
%{_udevdir}/69-dm-lvm.rules
|
||||
%{_udevdir}/69-dm-lvm-metad.rules
|
||||
%endif
|
||||
%dir %{_sysconfdir}/lvm
|
||||
%ghost %{_sysconfdir}/lvm/cache/.cache
|
||||
@@ -189,6 +190,7 @@ fi
|
||||
%{_tmpfilesdir}/%{name}.conf
|
||||
%{_unitdir}/blk-availability.service
|
||||
%{_unitdir}/lvm2-monitor.service
|
||||
%{_unitdir}/lvm2-pvscan@.service
|
||||
%attr(555, -, -) %{_prefix}/lib/systemd/system-generators/lvm2-activation-generator
|
||||
%if %{have_service lvmpolld}
|
||||
%{_unitdir}/lvm2-lvmpolld.service
|
||||
|
@@ -283,7 +283,7 @@ not ls "$RUNDIR/lvm/pvs_online/$PVID3"
|
||||
# arg in devices list
|
||||
_clear_online_files
|
||||
pvscan --devices "$dev3" --cache -aay "$dev3"
|
||||
pvscan --devices "$dev4","$dev3" --cache -aay "$dev4"
|
||||
pvscan --devices "$dev4" --cache -aay "$dev4"
|
||||
check lv_field $vg2/$lv2 lv_active "active"
|
||||
vgchange -an $vg2
|
||||
|
||||
|
@@ -545,4 +545,73 @@ grep "$PVID2" "$DF" |tee out
|
||||
grep "$dev2" out
|
||||
not grep "$dev1" out
|
||||
|
||||
vgchange -an $vg1
|
||||
vgchange -an $vg2
|
||||
vgremove -ff $vg1
|
||||
vgremove -ff $vg2
|
||||
|
||||
# devnames change so the new devname now refers to a filtered device,
|
||||
# e.g. an mpath or md component, which is not scanned
|
||||
|
||||
wait_md_create() {
|
||||
local md=$1
|
||||
|
||||
while :; do
|
||||
if ! grep "$(basename $md)" /proc/mdstat; then
|
||||
echo "$md not ready"
|
||||
cat /proc/mdstat
|
||||
sleep 2
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
echo "$md" > WAIT_MD_DEV
|
||||
}
|
||||
|
||||
aux wipefs_a "$dev1"
|
||||
aux wipefs_a "$dev2"
|
||||
aux wipefs_a "$dev3"
|
||||
aux wipefs_a "$dev4"
|
||||
|
||||
mddev="/dev/md33"
|
||||
not grep $mddev /proc/mdstat || skip
|
||||
|
||||
rm "$DF"
|
||||
touch "$DF"
|
||||
vgcreate $vg1 "$dev1" "$dev2"
|
||||
cat "$DF"
|
||||
cp "$DF" "$ORIG"
|
||||
|
||||
# PVID with dashes for matching pvs -o+uuid output
|
||||
OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
|
||||
OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
|
||||
|
||||
# PVID without dashes for matching devices file fields
|
||||
PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
|
||||
PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
|
||||
|
||||
mdadm --create --metadata=1.0 "$mddev" --level 1 --raid-devices=2 "$dev3" "$dev4"
|
||||
wait_md_create "$mddev"
|
||||
|
||||
sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
|
||||
sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
|
||||
cat "$DF"
|
||||
pvs -o+uuid |tee out
|
||||
grep "$dev1" out
|
||||
grep "$dev2" out
|
||||
grep "$OPVID1" out
|
||||
grep "$OPVID2" out
|
||||
not grep "$dev3" out
|
||||
not grep "$dev4" out
|
||||
|
||||
grep "$dev1" "$DF"
|
||||
grep "$dev2" "$DF"
|
||||
grep "$PVID1" "$DF"
|
||||
grep "$PVID2" "$DF"
|
||||
not grep "$dev3" "$DF"
|
||||
not grep "$dev4" "$DF"
|
||||
|
||||
mdadm --stop "$mddev"
|
||||
aux udev_wait
|
||||
|
||||
vgremove -ff $vg1
|
||||
|
@@ -57,9 +57,11 @@ dd if="$dev1" of=dev1_backup bs=1M
|
||||
|
||||
# pvcreate and pvremove can be forced even if the PV is marked as used
|
||||
pvremove -ff -y "$dev1"
|
||||
lvmdevices --deldev "$dev1" || true
|
||||
dd if=dev1_backup of="$dev1" bs=1M
|
||||
pvcreate -ff -y "$dev1"
|
||||
dd if=dev1_backup of="$dev1" bs=1M
|
||||
lvmdevices --adddev "$dev1" || true
|
||||
|
||||
# prepare a VG with $dev1 and $dev both having 1 MDA
|
||||
aux enable_dev "$dev2"
|
||||
@@ -116,9 +118,11 @@ dd if="$dev1" of=dev1_backup bs=1M
|
||||
|
||||
# pvcreate and pvremove can be forced even if the PV is marked as used
|
||||
pvremove -ff -y "$dev1"
|
||||
lvmdevices --deldev "$dev1" || true
|
||||
dd if=dev1_backup of="$dev1" bs=1M
|
||||
pvcreate -ff -y "$dev1"
|
||||
dd if=dev1_backup of="$dev1" bs=1M
|
||||
lvmdevices --adddev "$dev1" || true
|
||||
|
||||
# prepare a VG with $dev1 and $dev both having 1 MDA
|
||||
aux enable_dev "$dev2"
|
||||
|
@@ -1,403 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (C) 2021 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
|
||||
|
||||
test_description='udev rule and systemd unit run vgchange'
|
||||
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
SKIP_WITH_LVMLOCKD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
#
|
||||
# $ cat /tmp/devs
|
||||
# /dev/sdb
|
||||
# /dev/sdc
|
||||
# /dev/sdd
|
||||
#
|
||||
# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
|
||||
# when running the test.
|
||||
#
|
||||
# This test will wipe these devices.
|
||||
#
|
||||
|
||||
if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi
|
||||
|
||||
test -e "$LVM_TEST_DEVICE_LIST" || skip
|
||||
|
||||
num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l)
|
||||
|
||||
RUNDIR="/run"
|
||||
test -d "$RUNDIR" || RUNDIR="/var/run"
|
||||
PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
|
||||
VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
|
||||
PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
|
||||
|
||||
_clear_online_files() {
|
||||
# wait till udev is finished
|
||||
aux udev_wait
|
||||
rm -f "$PVS_ONLINE_DIR"/*
|
||||
rm -f "$VGS_ONLINE_DIR"/*
|
||||
rm -f "$PVS_LOOKUP_DIR"/*
|
||||
}
|
||||
|
||||
test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
|
||||
test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
|
||||
test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
|
||||
_clear_online_files
|
||||
|
||||
aux prepare_real_devs
|
||||
|
||||
aux lvmconf 'devices/dir = "/dev"'
|
||||
aux lvmconf 'devices/use_devicesfile = 1'
|
||||
DFDIR="$LVM_SYSTEM_DIR/devices"
|
||||
DF="$DFDIR/system.devices"
|
||||
mkdir $DFDIR || true
|
||||
not ls $DF
|
||||
|
||||
get_real_devs
|
||||
|
||||
wipe_all() {
|
||||
for dev in "${REAL_DEVICES[@]}"; do
|
||||
wipefs -a $dev
|
||||
done
|
||||
}
|
||||
|
||||
# udevadm trigger runs udev rule which runs systemd-run --no-wait vgchange -aay
|
||||
# Because of --no-wait, we need to wait for the transient systemd
|
||||
# service to be gone before checking the effects of the vgchange.
|
||||
|
||||
wait_lvm_activate() {
|
||||
local vgw=$1
|
||||
local wait=0
|
||||
|
||||
while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
|
||||
sleep .2
|
||||
wait=$(( wait + 1 ))
|
||||
done
|
||||
}
|
||||
|
||||
# Test requires 3 devs
|
||||
test $num_devs -gt 2 || skip
|
||||
BDEV1=$(basename "$dev1")
|
||||
BDEV2=$(basename "$dev2")
|
||||
BDEV3=$(basename "$dev3")
|
||||
|
||||
wipe_all
|
||||
touch $DF
|
||||
for dev in "${REAL_DEVICES[@]}"; do
|
||||
pvcreate $dev
|
||||
done
|
||||
|
||||
# 1 dev, 1 vg, 1 lv
|
||||
|
||||
vgcreate $vg1 "$dev1"
|
||||
lvcreate -l1 -an -n $lv1 $vg1 "$dev1"
|
||||
|
||||
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
|
||||
_clear_online_files
|
||||
udevadm trigger --settle -c add /sys/block/$BDEV1
|
||||
|
||||
wait_lvm_activate $vg1
|
||||
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID1"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg1"
|
||||
journalctl -u lvm-activate-$vg1 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg1/$lv1 lv_active "active"
|
||||
|
||||
vgchange -an $vg1
|
||||
vgremove -y $vg1
|
||||
|
||||
|
||||
# 2 devs, 1 vg, 2 lvs
|
||||
|
||||
vgcreate $vg2 "$dev1" "$dev2"
|
||||
lvcreate -l1 -an -n $lv1 $vg2 "$dev1"
|
||||
lvcreate -l1 -an -n $lv2 $vg2 "$dev2"
|
||||
|
||||
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger --settle -c add /sys/block/$BDEV1
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID1"
|
||||
not ls "$RUNDIR/lvm/vgs_online/$vg2"
|
||||
journalctl -u lvm-activate-$vg2 | tee out || true
|
||||
not grep "now active" out
|
||||
check lv_field $vg2/$lv1 lv_active ""
|
||||
check lv_field $vg2/$lv2 lv_active ""
|
||||
|
||||
udevadm trigger --settle -c add /sys/block/$BDEV2
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID2"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg2"
|
||||
|
||||
wait_lvm_activate $vg2
|
||||
|
||||
journalctl -u lvm-activate-$vg2 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg2/$lv1 lv_active "active"
|
||||
check lv_field $vg2/$lv2 lv_active "active"
|
||||
|
||||
vgchange -an $vg2
|
||||
vgremove -y $vg2
|
||||
|
||||
|
||||
# 3 devs, 1 vg, 4 lvs, concurrent pvscans
|
||||
# (attempting to have the pvscans run concurrently and race
|
||||
# to activate the VG)
|
||||
|
||||
vgcreate $vg3 "$dev1" "$dev2" "$dev3"
|
||||
lvcreate -l1 -an -n $lv1 $vg3 "$dev1"
|
||||
lvcreate -l1 -an -n $lv2 $vg3 "$dev2"
|
||||
lvcreate -l1 -an -n $lv3 $vg3 "$dev3"
|
||||
lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2"
|
||||
|
||||
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger -c add /sys/block/$BDEV1 &
|
||||
udevadm trigger -c add /sys/block/$BDEV2 &
|
||||
udevadm trigger -c add /sys/block/$BDEV3
|
||||
|
||||
aux udev_wait
|
||||
wait_lvm_activate $vg3
|
||||
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID1"
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID2"
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID3"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg3"
|
||||
journalctl -u lvm-activate-$vg3 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg3/$lv1 lv_active "active"
|
||||
check lv_field $vg3/$lv2 lv_active "active"
|
||||
check lv_field $vg3/$lv3 lv_active "active"
|
||||
check lv_field $vg3/$lv4 lv_active "active"
|
||||
|
||||
vgchange -an $vg3
|
||||
vgremove -y $vg3
|
||||
|
||||
|
||||
# 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV
|
||||
|
||||
wipe_all
|
||||
rm $DF
|
||||
touch $DF
|
||||
pvcreate --metadatacopies 0 "$dev1"
|
||||
pvcreate --metadatacopies 0 "$dev2"
|
||||
pvcreate "$dev3"
|
||||
|
||||
vgcreate $vg4 "$dev1" "$dev2" "$dev3"
|
||||
lvcreate -l1 -an -n $lv1 $vg4 "$dev1"
|
||||
lvcreate -l1 -an -n $lv2 $vg4 "$dev2"
|
||||
lvcreate -l1 -an -n $lv3 $vg4 "$dev3"
|
||||
lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2"
|
||||
|
||||
PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger -c add /sys/block/$BDEV1 &
|
||||
udevadm trigger -c add /sys/block/$BDEV2 &
|
||||
udevadm trigger -c add /sys/block/$BDEV3
|
||||
|
||||
aux udev_wait
|
||||
wait_lvm_activate $vg4
|
||||
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID1"
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID2"
|
||||
ls "$RUNDIR/lvm/pvs_online/$PVID3"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg4"
|
||||
journalctl -u lvm-activate-$vg4 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg4/$lv1 lv_active "active"
|
||||
check lv_field $vg4/$lv2 lv_active "active"
|
||||
check lv_field $vg4/$lv3 lv_active "active"
|
||||
check lv_field $vg4/$lv4 lv_active "active"
|
||||
|
||||
vgchange -an $vg4
|
||||
vgremove -y $vg4
|
||||
|
||||
|
||||
# 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans
|
||||
|
||||
wipe_all
|
||||
rm $DF
|
||||
touch $DF
|
||||
|
||||
vgcreate $vg5 "$dev1"
|
||||
vgcreate $vg6 "$dev2"
|
||||
vgcreate $vg7 "$dev3"
|
||||
lvcreate -l1 -an -n $lv1 $vg5
|
||||
lvcreate -l1 -an -n $lv2 $vg5
|
||||
lvcreate -l1 -an -n $lv1 $vg6
|
||||
lvcreate -l1 -an -n $lv2 $vg6
|
||||
lvcreate -l1 -an -n $lv1 $vg7
|
||||
lvcreate -l1 -an -n $lv2 $vg7
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger -c add /sys/block/$BDEV1 &
|
||||
udevadm trigger -c add /sys/block/$BDEV2 &
|
||||
udevadm trigger -c add /sys/block/$BDEV3
|
||||
|
||||
aux udev_wait
|
||||
wait_lvm_activate $vg5
|
||||
wait_lvm_activate $vg6
|
||||
wait_lvm_activate $vg7
|
||||
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg5"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg6"
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg7"
|
||||
journalctl -u lvm-activate-$vg5 | tee out || true
|
||||
grep "now active" out
|
||||
journalctl -u lvm-activate-$vg6 | tee out || true
|
||||
grep "now active" out
|
||||
journalctl -u lvm-activate-$vg7 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg5/$lv1 lv_active "active"
|
||||
check lv_field $vg5/$lv2 lv_active "active"
|
||||
check lv_field $vg6/$lv1 lv_active "active"
|
||||
check lv_field $vg6/$lv2 lv_active "active"
|
||||
check lv_field $vg7/$lv1 lv_active "active"
|
||||
check lv_field $vg7/$lv2 lv_active "active"
|
||||
|
||||
vgchange -an $vg5
|
||||
vgremove -y $vg5
|
||||
vgchange -an $vg6
|
||||
vgremove -y $vg6
|
||||
vgchange -an $vg7
|
||||
vgremove -y $vg7
|
||||
|
||||
# 3 devs, 1 vg, 1000 LVs
|
||||
|
||||
wipe_all
|
||||
rm $DF
|
||||
touch $DF
|
||||
pvcreate --metadatacopies 0 "$dev1"
|
||||
pvcreate "$dev2"
|
||||
pvcreate "$dev3"
|
||||
vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3"
|
||||
|
||||
# Number of LVs to create
|
||||
TEST_DEVS=1000
|
||||
# On low-memory boxes let's not stress too much
|
||||
test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
|
||||
|
||||
vgcfgbackup -f data $vg8
|
||||
|
||||
# Generate a lot of devices (size of 1 extent)
|
||||
awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
|
||||
printf("\t}\n\tlogical_volumes {\n");
|
||||
cnt=0;
|
||||
for (i = 0; i < TEST_DEVS; i++) {
|
||||
printf("\t\tlvol%06d {\n", i);
|
||||
printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
|
||||
print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
|
||||
print "\t\t\tsegment_count = 1";
|
||||
print "\t\t\tsegment1 {";
|
||||
print "\t\t\t\tstart_extent = 0";
|
||||
print "\t\t\t\textent_count = 1";
|
||||
print "\t\t\t\ttype = \"striped\"";
|
||||
print "\t\t\t\tstripe_count = 1";
|
||||
print "\t\t\t\tstripes = [";
|
||||
print "\t\t\t\t\t\"pv0\", " cnt++;
|
||||
printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
|
||||
}
|
||||
}
|
||||
{print}
|
||||
' data >data_new
|
||||
|
||||
vgcfgrestore -f data_new $vg8
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger -c add /sys/block/$BDEV1 &
|
||||
udevadm trigger -c add /sys/block/$BDEV2 &
|
||||
udevadm trigger -c add /sys/block/$BDEV3
|
||||
|
||||
aux udev_wait
|
||||
wait_lvm_activate $vg8
|
||||
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg8"
|
||||
journalctl -u lvm-activate-$vg8 | tee out || true
|
||||
grep "now active" out
|
||||
|
||||
num_active=$(lvs $vg8 --noheading -o active | grep active | wc -l)
|
||||
|
||||
test $num_active -eq $TEST_DEVS
|
||||
|
||||
vgchange -an $vg8
|
||||
vgremove -y $vg8
|
||||
|
||||
# 1 pv on an md dev, 1 vg
|
||||
|
||||
wait_md_create() {
|
||||
local md=$1
|
||||
|
||||
while :; do
|
||||
if ! grep "$(basename $md)" /proc/mdstat; then
|
||||
echo "$md not ready"
|
||||
cat /proc/mdstat
|
||||
sleep 2
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
echo "$md" > WAIT_MD_DEV
|
||||
}
|
||||
|
||||
test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
|
||||
modprobe raid1 || skip
|
||||
|
||||
mddev="/dev/md33"
|
||||
not grep $mddev /proc/mdstat || skip
|
||||
|
||||
wipe_all
|
||||
rm $DF
|
||||
touch $DF
|
||||
|
||||
mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
|
||||
wait_md_create "$mddev"
|
||||
vgcreate $vg9 "$mddev"
|
||||
|
||||
PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'`
|
||||
BDEVMD=$(basename "$mddev")
|
||||
|
||||
lvcreate -l1 -an -n $lv1 $vg9
|
||||
lvcreate -l1 -an -n $lv2 $vg9
|
||||
|
||||
_clear_online_files
|
||||
|
||||
udevadm trigger --settle -c add /sys/block/$BDEVMD
|
||||
|
||||
wait_lvm_activate $vg9
|
||||
|
||||
ls "$RUNDIR/lvm/vgs_online/$vg9"
|
||||
journalctl -u lvm-activate-$vg9 | tee out || true
|
||||
grep "now active" out
|
||||
check lv_field $vg9/$lv1 lv_active "active"
|
||||
check lv_field $vg9/$lv2 lv_active "active"
|
||||
|
||||
vgchange -an $vg9
|
||||
vgremove -y $vg9
|
||||
|
||||
mdadm --stop "$mddev"
|
||||
aux udev_wait
|
||||
wipe_all
|
||||
|
@@ -1359,10 +1359,10 @@ OO: --aligned, --all, --binary, --colon, --columns,
|
||||
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
|
||||
--logonly, --maps, --noheadings,
|
||||
--nosuffix, --options String, --sort String, --readonly,
|
||||
--reportformat ReportFmt, --segments, --select String, --separator String,
|
||||
--segments, --select String, --separator String,
|
||||
--shared, --unbuffered, --units Units
|
||||
OP: VG|LV|Tag ...
|
||||
IO: --partial, --ignoreskippedcluster
|
||||
IO: --partial, --ignoreskippedcluster, --reportformat ReportFmt
|
||||
ID: lvdisplay_general
|
||||
|
||||
---
|
||||
@@ -1590,10 +1590,10 @@ pvdisplay
|
||||
OO: --aligned, --all, --binary, --colon, --columns, --configreport ConfigReport,
|
||||
--foreign, --ignorelockingfailure,
|
||||
--logonly, --maps, --noheadings, --nosuffix, --options String,
|
||||
--readonly, --reportformat ReportFmt, --select String, --separator String, --shared,
|
||||
--readonly, --select String, --separator String, --shared,
|
||||
--short, --sort String, --unbuffered, --units Units
|
||||
OP: PV|Tag ...
|
||||
IO: --ignoreskippedcluster
|
||||
IO: --ignoreskippedcluster, --reportformat ReportFmt
|
||||
ID: pvdisplay_general
|
||||
|
||||
---
|
||||
@@ -1809,10 +1809,10 @@ vgdisplay
|
||||
OO: --activevolumegroups, --aligned, --binary, --colon, --columns,
|
||||
--configreport ConfigReport, --foreign, --ignorelockingfailure,
|
||||
--logonly, --noheadings, --nosuffix,
|
||||
--options String, --readonly, --reportformat ReportFmt, --select String,
|
||||
--options String, --readonly, --select String,
|
||||
--shared, --short, --separator String, --sort String, --unbuffered, --units Units
|
||||
OP: VG|Tag ...
|
||||
IO: --partial, --ignoreskippedcluster
|
||||
IO: --partial, --ignoreskippedcluster, --reportformat ReportFmt
|
||||
ID: vgdisplay_general
|
||||
|
||||
---
|
||||
|
@@ -824,12 +824,16 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
autobackup_ARG,\
|
||||
available_ARG,\
|
||||
contiguous_ARG,\
|
||||
devices_ARG,\
|
||||
devicesfile_ARG,\
|
||||
ignoreactivationskip_ARG,\
|
||||
ignoremonitoring_ARG,\
|
||||
journal_ARG,\
|
||||
metadataprofile_ARG,\
|
||||
monitor_ARG,\
|
||||
mirrors_ARG,\
|
||||
name_ARG,\
|
||||
nohints_ARG,\
|
||||
noudevsync_ARG,\
|
||||
permission_ARG,\
|
||||
persistent_ARG,\
|
||||
|
@@ -3058,6 +3058,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
int i;
|
||||
int skip_hyphens;
|
||||
int refresh_done = 0;
|
||||
int io;
|
||||
|
||||
/* Avoid excessive access to /etc/localtime and set TZ variable for glibc
|
||||
* so it does not need to check /etc/localtime everytime that needs that info */
|
||||
@@ -3140,6 +3141,20 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
|
||||
return EINVALID_CMD_LINE;
|
||||
|
||||
/*
|
||||
* If option --foo is set which is listed in IO (ignore option) in
|
||||
* command-lines.in, then unset foo. Commands won't usually use an
|
||||
* ignored option, but there can be shared code that checks for --foo,
|
||||
* and should not find it to be set.
|
||||
*/
|
||||
for (io = 0; io < cmd->command->io_count; io++) {
|
||||
int opt = cmd->command->ignore_opt_args[io].opt;
|
||||
if (arg_is_set(cmd, opt)) {
|
||||
log_debug("Ignore opt %d", opt);
|
||||
cmd->opt_arg_values[opt].count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remaining position args after command name and --options are removed.
|
||||
*/
|
||||
|
@@ -176,6 +176,9 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
log_error("Failed to read the devices file.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
prepare_open_file_limit(cmd, dm_list_size(&cmd->use_devices));
|
||||
|
||||
dev_cache_scan(cmd);
|
||||
device_ids_match(cmd);
|
||||
|
||||
|
@@ -857,21 +857,11 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname,
|
||||
|
||||
devno = MKDEV(file_major, file_minor);
|
||||
|
||||
if (!setup_devno_in_dev_cache(cmd, devno)) {
|
||||
log_error_pvscan(cmd, "No device set up for %d:%d PVID %s", file_major, file_minor, pvid);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) {
|
||||
log_error_pvscan(cmd, "No device found for %d:%d PVID %s", file_major, file_minor, pvid);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not need to match device_id here, see comment after
|
||||
* get_devs_from_saved_vg about relying on pvid online file.
|
||||
*/
|
||||
|
||||
name1 = dev_name(dev);
|
||||
name2 = pvl->pv->device_hint;
|
||||
|
||||
@@ -1109,11 +1099,17 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp,
|
||||
* PROCESS_SKIP_SCAN: we have already done lvmcache_label_scan
|
||||
* so tell process_each to skip it.
|
||||
*/
|
||||
if (do_all)
|
||||
read_flags |= PROCESS_SKIP_SCAN;
|
||||
|
||||
/*
|
||||
* When the command is processing specific devs (not all), it
|
||||
* has done setup_devices_no_file_match() to avoid matching ids
|
||||
* fo all devs unnecessarily, but now that we're falling back
|
||||
* to process_each_vg() we need to complete the id matching.
|
||||
*/
|
||||
if (!do_all)
|
||||
lvmcache_label_scan(cmd);
|
||||
|
||||
read_flags |= PROCESS_SKIP_SCAN;
|
||||
device_ids_match(cmd);
|
||||
|
||||
ret = process_each_vg(cmd, 0, NULL, NULL, vgnames, read_flags, 0, handle, _pvscan_aa_single);
|
||||
}
|
||||
@@ -1196,15 +1192,11 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args,
|
||||
/* in common usage, no dev will be found for a devno */
|
||||
|
||||
dm_list_iterate_items(arg, pvscan_args) {
|
||||
if (arg->devname) {
|
||||
if (!setup_devname_in_dev_cache(cmd, arg->devname))
|
||||
log_error_pvscan(cmd, "No device set up for name arg %s", arg->devname);
|
||||
if (arg->devname)
|
||||
arg->dev = dev_cache_get(cmd, arg->devname, NULL);
|
||||
} else if (arg->devno) {
|
||||
if (!setup_devno_in_dev_cache(cmd, arg->devno))
|
||||
log_error_pvscan(cmd, "No device set up for devno arg %d", (int)arg->devno);
|
||||
else if (arg->devno)
|
||||
arg->dev = dev_cache_get_by_devt(cmd, arg->devno, NULL, NULL);
|
||||
} else
|
||||
else
|
||||
return_0;
|
||||
}
|
||||
|
||||
@@ -1362,7 +1354,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs
|
||||
devsize = dev->size;
|
||||
if (!devsize &&
|
||||
!dev_get_size(dev, &devsize)) {
|
||||
log_print("pvscan[%d] PV %s can get device size.", getpid(), dev_name(dev));
|
||||
log_print_pvscan(cmd, "PV %s missing device size.", dev_name(dev));
|
||||
release_vg(vg);
|
||||
continue;
|
||||
}
|
||||
@@ -1680,13 +1672,11 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
cmd->pvscan_cache_single = 1;
|
||||
|
||||
/*
|
||||
* Special pvscan-specific setup steps to avoid looking
|
||||
* at any devices except for device args.
|
||||
* Read devices file and determine if devices file will be used.
|
||||
* Does not do dev_cache_scan (adds nothing to dev-cache), and
|
||||
* does not do any device id matching.
|
||||
* "no_file_match" means that when the devices file is used,
|
||||
* setup_devices will skip matching devs to devices file entries.
|
||||
* Specific devs must be matched later with device_ids_match_dev().
|
||||
*/
|
||||
if (!setup_devices_for_pvscan_cache(cmd)) {
|
||||
if (!setup_devices_no_file_match(cmd)) {
|
||||
log_error_pvscan(cmd, "Failed to set up devices.");
|
||||
return 0;
|
||||
}
|
||||
@@ -1745,21 +1735,17 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
log_debug("pvscan_cache_args: filter devs nodata");
|
||||
|
||||
/*
|
||||
* Match dev args with the devices file because special/optimized
|
||||
* device setup was used above which does not check the devices file.
|
||||
* If a match fails here do not exclude it, that will be done below by
|
||||
* passes_filter() which runs filter-deviceid. The
|
||||
* relax_deviceid_filter case needs to be able to work around
|
||||
* Match dev args with the devices file because
|
||||
* setup_devices_no_file_match() was used above which skipped checking
|
||||
* the devices file. If a match fails here do not exclude it, that
|
||||
* will be done below by passes_filter() which runs filter-deviceid.
|
||||
* The relax_deviceid_filter case needs to be able to work around
|
||||
* unmatching devs.
|
||||
*/
|
||||
|
||||
if (cmd->enable_devices_file) {
|
||||
dm_list_iterate_items(devl, &pvscan_devs)
|
||||
dm_list_iterate_items_safe(devl, devl2, &pvscan_devs)
|
||||
device_ids_match_dev(cmd, devl->dev);
|
||||
|
||||
}
|
||||
if (cmd->enable_devices_list)
|
||||
device_ids_match_device_list(cmd);
|
||||
|
||||
if (cmd->enable_devices_file && device_ids_use_devname(cmd)) {
|
||||
relax_deviceid_filter = 1;
|
||||
@@ -1800,7 +1786,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv,
|
||||
int has_pvid;
|
||||
|
||||
if (!label_read_pvid(devl->dev, &has_pvid)) {
|
||||
log_print("pvscan[%d] %s cannot read.", getpid(), dev_name(devl->dev));
|
||||
log_print_pvscan(cmd, "%s cannot read label.", dev_name(devl->dev));
|
||||
dm_list_del(&devl->list);
|
||||
continue;
|
||||
}
|
||||
|
@@ -172,6 +172,17 @@ int vgimportdevices(struct cmd_context *cmd, int argc, char **argv)
|
||||
cmd->filter_regex_with_devices_file = 1;
|
||||
cmd->create_edit_devices_file = 1;
|
||||
|
||||
/*
|
||||
* This helps a user bootstrap existing shared VGs into the devices
|
||||
* file. Reading the vg to import devices requires locking, but
|
||||
* lockstart won't find the vg before it's in the devices file.
|
||||
* So, allow importing devices without an lvmlockd lock (in a
|
||||
* a shared vg the vg metadata won't be updated with device ids,
|
||||
* so the lvmlockd lock isn't protecting vg modification.)
|
||||
*/
|
||||
cmd->lockd_gl_disable = 1;
|
||||
cmd->lockd_vg_disable = 1;
|
||||
|
||||
/*
|
||||
* For each VG:
|
||||
* device_id_add() each PV in the VG
|
||||
|
@@ -1,87 +0,0 @@
|
||||
# Copyright (C) 2012,2021 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of LVM.
|
||||
#
|
||||
# This rule requires blkid to be called on block devices before so only devices
|
||||
# used as LVM PVs are processed (ID_FS_TYPE="LVM2_member").
|
||||
|
||||
SUBSYSTEM!="block", GOTO="lvm_end"
|
||||
(LVM_EXEC_RULE)
|
||||
|
||||
ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="lvm_end"
|
||||
|
||||
# Only process devices already marked as a PV - this requires blkid to be called before.
|
||||
ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
|
||||
ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
|
||||
ACTION=="remove", GOTO="lvm_end"
|
||||
|
||||
# Create /dev/disk/by-id/lvm-pv-uuid-<PV_UUID> symlink for each PV
|
||||
ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}"
|
||||
|
||||
# If the PV is a special device listed below, scan only if the device is
|
||||
# properly activated. These devices are not usable after an ADD event,
|
||||
# but they require an extra setup and they are ready after a CHANGE event.
|
||||
# Also support coldplugging with ADD event but only if the device is already
|
||||
# properly activated.
|
||||
# This logic should be eventually moved to rules where those particular
|
||||
# devices are processed primarily (MD and loop).
|
||||
|
||||
# DM device:
|
||||
KERNEL!="dm-[0-9]*", GOTO="next"
|
||||
ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}=="1", GOTO="lvm_scan"
|
||||
GOTO="lvm_end"
|
||||
|
||||
# MD device:
|
||||
LABEL="next"
|
||||
KERNEL!="md[0-9]*", GOTO="next"
|
||||
IMPORT{db}="LVM_MD_PV_ACTIVATED"
|
||||
ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan"
|
||||
ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan"
|
||||
ACTION=="add", KERNEL=="md[0-9]*p[0-9]*", GOTO="lvm_scan"
|
||||
ENV{LVM_MD_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
|
||||
GOTO="lvm_end"
|
||||
|
||||
# Loop device:
|
||||
LABEL="next"
|
||||
KERNEL!="loop[0-9]*", GOTO="next"
|
||||
ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan"
|
||||
ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan"
|
||||
ENV{LVM_LOOP_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0"
|
||||
GOTO="lvm_end"
|
||||
|
||||
LABEL="next"
|
||||
ACTION!="add", GOTO="lvm_end"
|
||||
|
||||
LABEL="lvm_scan"
|
||||
|
||||
ENV{SYSTEMD_READY}="1"
|
||||
|
||||
# pvscan will check if this device completes a VG,
|
||||
# i.e. all PVs in the VG are now present with the
|
||||
# arrival of this PV. If so, it prints to stdout:
|
||||
# LVM_VG_NAME_COMPLETE='foo'
|
||||
#
|
||||
# When the VG is complete it can be activated, so
|
||||
# vgchange -aay <vgname> is run. It is run via
|
||||
# systemd since it can take longer to run than
|
||||
# udev wants to block when processing rules.
|
||||
# (if there are hundreds of LVs to activate,
|
||||
# the vgchange can take many seconds.)
|
||||
#
|
||||
# pvscan only reads the single device specified,
|
||||
# and uses temp files under /run/lvm to check if
|
||||
# other PVs in the VG are present.
|
||||
#
|
||||
# If event_activation=0 in lvm.conf, this pvscan
|
||||
# (using checkcomplete) will do nothing, so that
|
||||
# no event-based autoactivation will be happen.
|
||||
#
|
||||
# TODO: adjust the output of vgchange -aay so that
|
||||
# it's better suited to appearing in the journal.
|
||||
|
||||
IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}"
|
||||
ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run -r --no-block --property DefaultDependencies=no --unit lvm-activate-$env{LVM_VG_NAME_COMPLETE} lvm vgchange -aay --nohints $env{LVM_VG_NAME_COMPLETE}"
|
||||
GOTO="lvm_end"
|
||||
|
||||
LABEL="lvm_end"
|
||||
|
@@ -18,7 +18,7 @@ top_builddir = @top_builddir@
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
|
||||
LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules
|
||||
LVM_RULES=11-dm-lvm.rules 69-dm-lvm-metad.rules
|
||||
|
||||
DM_DIR=$(shell $(GREP) "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | $(AWK) '{print $$3}')
|
||||
|
||||
|
Reference in New Issue
Block a user