From 2a6981a6976368f633942a13cf007b141b2ece0a Mon Sep 17 00:00:00 2001 From: Zdenek Kabelac Date: Fri, 24 Nov 2017 13:55:42 +0100 Subject: [PATCH] activation: automaticaly discover pvmove holders When pvmove is finished and does 'suspend/resume' on PVMOVE LV, on resume path committed metadata are already showing 'standalone' pvmove LV prepared just for removal. However code should be able to 'resume' preloaded LV there were participating in pvmove operation. Previously this was all done in the 'tools' part of lvm2 code. So the lvconvert upon pvmove finish had to explicitely call 'resume' on every such LV. Now 'smarted' activation code is able to deduce and combine all information from the active dm table and committed metadata so single call resolves it all in one go. Internally holders are detected by reading sysfs directory to capture all needed UUID which are then looked in lvm2 metadata and all such LVs are automatically collected into dmtree. --- WHATS_NEW | 1 + lib/activate/dev_manager.c | 108 +++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/WHATS_NEW b/WHATS_NEW index f29a498d0..c27db7c82 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.177 - ==================================== + Activation code for pvmove automatically discovers holding LVs for resume. Make a pvmove LV locking holder. Do not change critical section counter on resume path without real resume. Enhance activation code to automatically suspend pvmove participants. diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 1ca3baa5b..76fc546da 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -26,6 +26,7 @@ #include "activate.h" #include "lvm-exec.h" #include "str_list.h" +#include "dm-ioctl.h" /* for DM_UUID_LEN */ #include #include @@ -1717,6 +1718,104 @@ static uint16_t _get_udev_flags(struct dev_manager *dm, const struct logical_vol return udev_flags; } +static int _add_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, + const struct logical_volume *lv, int origin_only); +/* + * Add exiting devices which holds given LV device open. + * This is used in case when metadata already do not contain information + * i.e. PVMOVE is being finished and final table is going to be resumed. + */ +static int _add_holders_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, + const struct logical_volume *lv, struct dm_info *info) +{ + const char *default_uuid_prefix = dm_uuid_prefix(); + const size_t default_uuid_prefix_len = strlen(default_uuid_prefix); + const char *sysfs_dir = dm_sysfs_dir(); + char sysfs_path[PATH_MAX]; + char uuid_path[PATH_MAX]; + char uuid_buf[DM_UUID_LEN + 1]; + char *uuid; + struct dirent *dirent; + DIR *d; + FILE *fp; + struct logical_volume *lv_det; + int r = 0; + + /* Sysfs path of holders */ + if (dm_snprintf(sysfs_path, sizeof(sysfs_path), "%sdev/block/" FMTu32 + ":" FMTu32 "/holders", sysfs_dir, info->major, info->minor) < 0) { + log_error("sysfs_path dm_snprintf failed."); + return 0; + } + + if (!(d = opendir(sysfs_path))) { + if (errno != ENOENT) + log_sys_error("opendir", sysfs_path); + return 0; + } + + while ((dirent = readdir(d))) { + if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..")) + continue; + + /* Determine path where sysfs holds UUID for holding dm device */ + if (dm_snprintf(uuid_path, sizeof(uuid_path), "%s/%s/dm/uuid", + sysfs_path, dirent->d_name) < 0) { + log_error("uuid_path dm_snprintf failed."); + goto out; + } + + if (!(fp = fopen(uuid_path, "r"))) { + log_sys_error("fopen", uuid_path); + goto out; + } + + if (!fgets(uuid_buf, sizeof(uuid_buf), fp)) { + log_sys_error("fgets", uuid_path); + fclose(fp); + goto out; + } + + if (fclose(fp)) + log_sys_debug("fclose", uuid_path); + + uuid = uuid_buf; + log_debug_activation("Checking holder of LV %s with uuid %s.", + display_lvname(lv), uuid); + + /* Skip common uuid LVM prefix */ + if (!strncmp(default_uuid_prefix, uuid, default_uuid_prefix_len)) + uuid += default_uuid_prefix_len; + + /* Check holder comes from processed VG and is not yet in dmtree */ + if (!strncmp(uuid, (char*)&lv->vg->id, sizeof(lv->vg->id)) && + !dm_tree_find_node_by_uuid(dtree, uuid)) { + uuid[2 * sizeof(struct id)] = 0; /* Cut any suffix */ + /* If UUID is not yet in dtree, look for matching LV */ + if (!(lv_det = find_lv_in_vg_by_lvid(lv->vg, (union lvid*)uuid))) { + log_error("Cannot find holding uuid %s in VG %s.", + uuid, lv->vg->name); + goto out; + } + + if (lv_is_cow(lv_det)) + lv_det = origin_from_cow(lv_det); + log_debug_activation("Found holder %s of %s.", + display_lvname(lv_det), + display_lvname(lv)); + if (!_add_lv_to_dtree(dm, dtree, lv_det, 0)) + goto_out; + } + } + + r = 1; +out: + if (closedir(d)) + log_sys_error("closedir", "holders"); + + return r; +} + static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, const struct logical_volume *lv, const char *layer) { @@ -1771,6 +1870,15 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree, return_0; } + /* + * Find holders of existing active LV where name starts with 'pvmove', + * but it's not anymore PVMOVE LV and also it's not PVMOVE _mimage + */ + if (info.exists && !lv_is_pvmove(lv) && + !strchr(lv->name, '_') && !strncmp(lv->name, "pvmove", 6)) + if (!_add_holders_to_dtree(dm, dtree, lv, &info)) + return_0; + return 1; }