base/data-struct/list.h | 4 +- daemons/lvmlockd/lvmlockd-client.h | 1 + daemons/lvmlockd/lvmlockd-core.c | 370 +++++++-------- daemons/lvmlockd/lvmlockd-dlm.c | 8 +- daemons/lvmlockd/lvmlockd-internal.h | 7 +- lib/cache/lvmcache.c | 551 ++++++++++------------ lib/cache/lvmcache.h | 12 +- lib/commands/toolcontext.c | 3 +- lib/device/dev-io.c | 3 + lib/format_text/archiver.c | 2 +- lib/format_text/format-text.c | 28 +- lib/format_text/text_label.c | 8 +- lib/label/hints.c | 6 + lib/label/label.c | 2 +- lib/label/label.h | 2 +- lib/locking/lvmlockd.c | 14 +- lib/metadata/metadata-exported.h | 3 - lib/metadata/metadata.c | 68 +-- lib/metadata/metadata.h | 8 +- man/lvmlockd.8_main | 14 +- test/shell/duplicate-vgnames.sh | 660 +++++++++++++++++++++++++++ test/shell/duplicate-vgrename.sh | 319 +++++++++++++ test/shell/integrity-dmeventd.sh | 6 +- test/shell/integrity-large.sh | 6 +- test/shell/integrity-misc.sh | 6 +- test/shell/integrity.sh | 6 +- test/shell/process-each-duplicate-vgnames.sh | 55 --- test/shell/thin-foreign-repair.sh | 4 +- tools/command.c | 12 +- tools/lvconvert.c | 3 +- tools/pvck.c | 8 +- tools/pvscan.c | 2 +- tools/toollib.c | 2 - tools/vgchange.c | 9 +- tools/vgimportclone.c | 4 +- tools/vgmerge.c | 4 +- tools/vgrename.c | 2 +- tools/vgsplit.c | 2 +- 39 files changed, 1571 insertions(+), 654 deletions(-) create mode 100644 test/shell/duplicate-vgnames.sh create mode 100644 test/shell/duplicate-vgrename.sh delete mode 100644 test/shell/process-each-duplicate-vgnames.sh diff --git a/base/data-struct/list.h b/base/data-struct/list.h index 54cb1c1..e0a6256 100644 --- a/base/data-struct/list.h +++ b/base/data-struct/list.h @@ -1,7 +1,7 @@ #ifndef BASE_DATA_STRUCT_LIST_H #define BASE_DATA_STRUCT_LIST_H -#include /* offsetof */ +#include "base/memory/container_of.h" //---------------------------------------------------------------- @@ -100,7 +100,7 @@ struct dm_list *dm_list_next(const struct dm_list *head, const struct dm_list *e * contained in a structure of type t, return the containing structure. */ #define dm_list_struct_base(v, t, head) \ - ((t *)((const char *)(v) - offsetof(t, head))) + container_of(v, t, head) /* * Given the address v of an instance of 'struct dm_list list' contained in diff --git a/daemons/lvmlockd/lvmlockd-client.h b/daemons/lvmlockd/lvmlockd-client.h index 16d1613..62ffb73 100644 --- a/daemons/lvmlockd/lvmlockd-client.h +++ b/daemons/lvmlockd/lvmlockd-client.h @@ -14,6 +14,7 @@ #include "libdaemon/client/daemon-client.h" #define LVMLOCKD_SOCKET DEFAULT_RUN_DIR "/lvmlockd.socket" +#define LVMLOCKD_ADOPT_FILE DEFAULT_RUN_DIR "/lvmlockd.adopt" /* Wrappers to open/close connection */ diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c index 39275fb..84272c4 100644 --- a/daemons/lvmlockd/lvmlockd-core.c +++ b/daemons/lvmlockd/lvmlockd-core.c @@ -38,6 +38,8 @@ #define EXTERN #include "lvmlockd-internal.h" +static int str_to_mode(const char *str); + /* * Basic operation of lvmlockd * @@ -142,6 +144,8 @@ static const char *lvmlockd_protocol = "lvmlockd"; static const int lvmlockd_protocol_version = 1; static int daemon_quit; static int adopt_opt; +static uint32_t adopt_update_count; +static const char *adopt_file; /* * We use a separate socket for dumping daemon info. @@ -812,6 +816,144 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi } /* + * Write new info when a command exits if that command has acquired a new LV + * lock. If the command has released an LV lock we don't bother updating the + * info. When adopting, we eliminate any LV lock adoptions if there is no dm + * device for that LV. If lvmlockd is terminated after acquiring but before + * writing this file, those LV locks would not be adopted on restart. + */ + +#define ADOPT_VERSION_MAJOR 1 +#define ADOPT_VERSION_MINOR 0 + +static void write_adopt_file(void) +{ + struct lockspace *ls; + struct resource *r; + struct lock *lk; + time_t t; + FILE *fp; + + if (!(fp = fopen(adopt_file, "w"))) + return; + + adopt_update_count++; + + t = time(NULL); + fprintf(fp, "lvmlockd adopt_version %u.%u pid %d updates %u %s", + ADOPT_VERSION_MAJOR, ADOPT_VERSION_MINOR, getpid(), adopt_update_count, ctime(&t)); + + pthread_mutex_lock(&lockspaces_mutex); + list_for_each_entry(ls, &lockspaces, list) { + if (ls->lm_type == LD_LM_DLM && !strcmp(ls->name, gl_lsname_dlm)) + continue; + fprintf(fp, "VG: %38s %s %s %s\n", + ls->vg_uuid, ls->vg_name, lm_str(ls->lm_type), ls->vg_args); + list_for_each_entry(r, &ls->resources, list) { + if (r->type != LD_RT_LV) + continue; + if ((r->mode != LD_LK_EX) && (r->mode != LD_LK_SH)) + continue; + list_for_each_entry(lk, &r->locks, list) { + fprintf(fp, "LV: %38s %s %s %s %u\n", + ls->vg_uuid, r->name, r->lv_args, mode_str(r->mode), r->version); + } + } + } + pthread_mutex_unlock(&lockspaces_mutex); + + fflush(fp); + fclose(fp); +} + +static int read_adopt_file(struct list_head *vg_lockd) +{ + char adopt_line[512]; + char vg_uuid[72]; + char lm_type_str[16]; + char mode[8]; + struct lockspace *ls, *ls2; + struct resource *r; + FILE *fp; + + if (MAX_ARGS != 64 || MAX_NAME != 64) + return -1; + + if (!(fp = fopen(adopt_file, "r"))) + return 0; + + while (fgets(adopt_line, sizeof(adopt_line), fp)) { + if (adopt_line[0] == '#') + continue; + else if (!strncmp(adopt_line, "lvmlockd", 8)) { + unsigned int v_major = 0, v_minor = 0; + sscanf(adopt_line, "lvmlockd adopt_version %u.%u", &v_major, &v_minor); + if (v_major != ADOPT_VERSION_MAJOR) + goto fail; + + } else if (!strncmp(adopt_line, "VG:", 3)) { + if (!(ls = alloc_lockspace())) + goto fail; + + memset(vg_uuid, 0, sizeof(vg_uuid)); + + if (sscanf(adopt_line, "VG: %63s %64s %16s %64s", + vg_uuid, ls->vg_name, lm_type_str, ls->vg_args) != 4) { + goto fail; + } + + memcpy(ls->vg_uuid, vg_uuid, 64); + + if ((ls->lm_type = str_to_lm(lm_type_str)) < 0) + goto fail; + + list_add(&ls->list, vg_lockd); + + } else if (!strncmp(adopt_line, "LV:", 3)) { + if (!(r = alloc_resource())) + goto fail; + + r->type = LD_RT_LV; + + memset(vg_uuid, 0, sizeof(vg_uuid)); + + if (sscanf(adopt_line, "LV: %64s %64s %s %8s %u", + vg_uuid, r->name, r->lv_args, mode, &r->version) != 5) { + goto fail; + } + + if ((r->adopt_mode = str_to_mode(mode)) == LD_LK_IV) + goto fail; + + if (ls && !memcmp(ls->vg_uuid, vg_uuid, 64)) { + list_add(&r->list, &ls->resources); + r = NULL; + } else { + list_for_each_entry(ls2, vg_lockd, list) { + if (memcmp(ls2->vg_uuid, vg_uuid, 64)) + continue; + list_add(&r->list, &ls2->resources); + r = NULL; + break; + } + } + + if (r) { + log_error("No lockspace found for resource %s vg_uuid %s", r->name, vg_uuid); + goto fail; + } + } + } + + fclose(fp); + return 0; + +fail: + fclose(fp); + return -1; +} + +/* * These are few enough that arrays of function pointers can * be avoided. */ @@ -4689,6 +4831,7 @@ static void *client_thread_main(void *arg_in) struct client *cl; struct action *act; struct action *act_un; + uint32_t lock_acquire_count = 0, lock_acquire_written = 0; int rv; while (1) { @@ -4720,6 +4863,9 @@ static void *client_thread_main(void *arg_in) rv = -1; } + if (act->flags & LD_AF_LV_LOCK) + lock_acquire_count++; + /* * The client failed after we acquired an LV lock for * it, but before getting this reply saying it's done. @@ -4741,6 +4887,11 @@ static void *client_thread_main(void *arg_in) continue; } + if (adopt_opt && (lock_acquire_count > lock_acquire_written)) { + lock_acquire_written = lock_acquire_count; + write_adopt_file(); + } + /* * Queue incoming actions for lockspace threads */ @@ -4814,6 +4965,8 @@ static void *client_thread_main(void *arg_in) pthread_mutex_unlock(&client_mutex); } out: + if (adopt_opt && lock_acquire_written) + unlink(adopt_file); return NULL; } @@ -4846,180 +4999,6 @@ static void close_client_thread(void) log_error("pthread_join client_thread error %d", perrno); } -/* - * Get a list of all VGs with a lockd type (sanlock|dlm). - * We'll match this list against a list of existing lockspaces that are - * found in the lock manager. - * - * For each of these VGs, also create a struct resource on ls->resources to - * represent each LV in the VG that uses a lock. For each of these LVs - * that are active, we'll attempt to adopt a lock. - */ - -static int get_lockd_vgs(struct list_head *vg_lockd) -{ - /* FIXME: get VGs some other way */ - return -1; -#if 0 - struct list_head update_vgs; - daemon_reply reply; - struct dm_config_node *cn; - struct dm_config_node *metadata; - struct dm_config_node *md_cn; - struct dm_config_node *lv_cn; - struct lockspace *ls, *safe; - struct resource *r; - const char *vg_name; - const char *vg_uuid; - const char *lv_uuid; - const char *lock_type; - const char *lock_args; - char find_str_path[PATH_MAX]; - int rv = 0; - - INIT_LIST_HEAD(&update_vgs); - - reply = send_lvmetad("vg_list", "token = %s", "skip", NULL); - - if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) { - log_error("vg_list from lvmetad failed %d", reply.error); - rv = -EINVAL; - goto destroy; - } - - if (!(cn = dm_config_find_node(reply.cft->root, "volume_groups"))) { - log_error("get_lockd_vgs no vgs"); - rv = -EINVAL; - goto destroy; - } - - /* create an update_vgs list of all vg uuids */ - - for (cn = cn->child; cn; cn = cn->sib) { - vg_uuid = cn->key; - - if (!(ls = alloc_lockspace())) { - rv = -ENOMEM; - break; - } - - strncpy(ls->vg_uuid, vg_uuid, 64); - list_add_tail(&ls->list, &update_vgs); - log_debug("get_lockd_vgs %s", vg_uuid); - } - destroy: - daemon_reply_destroy(reply); - - if (rv < 0) - goto out; - - /* get vg_name and lock_type for each vg uuid entry in update_vgs */ - - list_for_each_entry(ls, &update_vgs, list) { - reply = send_lvmetad("vg_lookup", - "token = %s", "skip", - "uuid = %s", ls->vg_uuid, - NULL); - - if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) { - log_error("vg_lookup from lvmetad failed %d", reply.error); - rv = -EINVAL; - goto next; - } - - vg_name = daemon_reply_str(reply, "name", NULL); - if (!vg_name) { - log_error("get_lockd_vgs %s no name", ls->vg_uuid); - rv = -EINVAL; - goto next; - } - - strncpy(ls->vg_name, vg_name, MAX_NAME); - - metadata = dm_config_find_node(reply.cft->root, "metadata"); - if (!metadata) { - log_error("get_lockd_vgs %s name %s no metadata", - ls->vg_uuid, ls->vg_name); - rv = -EINVAL; - goto next; - } - - lock_type = dm_config_find_str(metadata, "metadata/lock_type", NULL); - ls->lm_type = str_to_lm(lock_type); - - if ((ls->lm_type != LD_LM_SANLOCK) && (ls->lm_type != LD_LM_DLM)) { - log_debug("get_lockd_vgs %s not lockd type", ls->vg_name); - continue; - } - - lock_args = dm_config_find_str(metadata, "metadata/lock_args", NULL); - if (lock_args) - strncpy(ls->vg_args, lock_args, MAX_ARGS); - - log_debug("get_lockd_vgs %s lock_type %s lock_args %s", - ls->vg_name, lock_type, lock_args ?: "none"); - - /* - * Make a record (struct resource) of each lv that uses a lock. - * For any lv that uses a lock, we'll check if the lv is active - * and if so try to adopt a lock for it. - */ - - for (md_cn = metadata->child; md_cn; md_cn = md_cn->sib) { - if (strcmp(md_cn->key, "logical_volumes")) - continue; - - for (lv_cn = md_cn->child; lv_cn; lv_cn = lv_cn->sib) { - snprintf(find_str_path, PATH_MAX, "%s/lock_args", lv_cn->key); - lock_args = dm_config_find_str(lv_cn, find_str_path, NULL); - if (!lock_args) - continue; - - snprintf(find_str_path, PATH_MAX, "%s/id", lv_cn->key); - lv_uuid = dm_config_find_str(lv_cn, find_str_path, NULL); - - if (!lv_uuid) { - log_error("get_lock_vgs no lv id for name %s", lv_cn->key); - continue; - } - - if (!(r = alloc_resource())) { - rv = -ENOMEM; - goto next; - } - - r->use_vb = 0; - r->type = LD_RT_LV; - strncpy(r->name, lv_uuid, MAX_NAME); - if (lock_args) - strncpy(r->lv_args, lock_args, MAX_ARGS); - list_add_tail(&r->list, &ls->resources); - log_debug("get_lockd_vgs %s lv %s %s (name %s)", - ls->vg_name, r->name, lock_args ? lock_args : "", lv_cn->key); - } - } - next: - daemon_reply_destroy(reply); - - if (rv < 0) - break; - } -out: - /* Return lockd VG's on the vg_lockd list. */ - - list_for_each_entry_safe(ls, safe, &update_vgs, list) { - list_del(&ls->list); - - if ((ls->lm_type == LD_LM_SANLOCK) || (ls->lm_type == LD_LM_DLM)) - list_add_tail(&ls->list, vg_lockd); - else - free(ls); - } - - return rv; -#endif -} - static char _dm_uuid[DM_UUID_LEN]; static char *get_dm_uuid(char *dm_name) @@ -5236,9 +5215,9 @@ static void adopt_locks(void) INIT_LIST_HEAD(&to_unlock); /* - * Get list of lockspaces from lock managers. - * Get list of VGs from lvmetad with a lockd type. - * Get list of active lockd type LVs from /dev. + * Get list of lockspaces from currently running lock managers. + * Get list of shared VGs from file written by prior lvmlockd. + * Get list of active LVs (in the shared VGs) from the file. */ if (lm_support_dlm() && lm_is_running_dlm()) { @@ -5262,12 +5241,17 @@ static void adopt_locks(void) * Adds a struct lockspace to vg_lockd for each lockd VG. * Adds a struct resource to ls->resources for each LV. */ - rv = get_lockd_vgs(&vg_lockd); + rv = read_adopt_file(&vg_lockd); if (rv < 0) { - log_error("adopt_locks get_lockd_vgs failed"); + log_error("adopt_locks read_adopt_file failed"); goto fail; } + if (list_empty(&vg_lockd)) { + log_debug("No lockspaces in adopt file"); + return; + } + /* * For each resource on each lockspace, check if the * corresponding LV is active. If so, leave the @@ -5506,7 +5490,7 @@ static void adopt_locks(void) goto fail; act->op = LD_OP_LOCK; act->rt = LD_RT_LV; - act->mode = LD_LK_EX; + act->mode = r->adopt_mode; act->flags = (LD_AF_ADOPT | LD_AF_PERSISTENT); act->client_id = INTERNAL_CLIENT_ID; act->lm_type = ls->lm_type; @@ -5604,8 +5588,9 @@ static void adopt_locks(void) * Adopt failed because the orphan has a different mode * than initially requested. Repeat the lock-adopt operation * with the other mode. N.B. this logic depends on first - * trying sh then ex for GL/VG locks, and ex then sh for - * LV locks. + * trying sh then ex for GL/VG locks; for LV locks the mode + * from the adopt file is tried first, the alternate + * (if the mode in adopt file was wrong somehow.) */ if ((act->rt != LD_RT_LV) && (act->mode == LD_LK_SH)) { @@ -5613,9 +5598,12 @@ static void adopt_locks(void) act->mode = LD_LK_EX; rv = add_lock_action(act); - } else if ((act->rt == LD_RT_LV) && (act->mode == LD_LK_EX)) { - /* LV locks: attempt to adopt sh after ex failed. */ - act->mode = LD_LK_SH; + } else if (act->rt == LD_RT_LV) { + /* LV locks: attempt to adopt the other mode. */ + if (act->mode == LD_LK_EX) + act->mode = LD_LK_SH; + else if (act->mode == LD_LK_SH) + act->mode = LD_LK_EX; rv = add_lock_action(act); } else { @@ -5750,10 +5738,13 @@ static void adopt_locks(void) if (count_start_fail || count_adopt_fail) goto fail; + unlink(adopt_file); + write_adopt_file(); log_debug("adopt_locks done"); return; fail: + unlink(adopt_file); log_error("adopt_locks failed, reset host"); } @@ -6028,6 +6019,8 @@ static void usage(char *prog, FILE *file) fprintf(file, " Set path to the pid file. [%s]\n", LVMLOCKD_PIDFILE); fprintf(file, " --socket-path | -s \n"); fprintf(file, " Set path to the socket to listen on. [%s]\n", LVMLOCKD_SOCKET); + fprintf(file, " --adopt-file \n"); + fprintf(file, " Set path to the adopt file. [%s]\n", LVMLOCKD_ADOPT_FILE); fprintf(file, " --syslog-priority | -S err|warning|debug\n"); fprintf(file, " Write log messages from this level up to syslog. [%s]\n", _syslog_num_to_name(LOG_SYSLOG_PRIO)); fprintf(file, " --gl-type | -g \n"); @@ -6063,6 +6056,7 @@ int main(int argc, char *argv[]) {"daemon-debug", no_argument, 0, 'D' }, {"pid-file", required_argument, 0, 'p' }, {"socket-path", required_argument, 0, 's' }, + {"adopt-file", required_argument, 0, 128 }, {"gl-type", required_argument, 0, 'g' }, {"host-id", required_argument, 0, 'i' }, {"host-id-file", required_argument, 0, 'F' }, @@ -6085,6 +6079,9 @@ int main(int argc, char *argv[]) switch (c) { case '0': break; + case 128: + adopt_file = strdup(optarg); + break; case 'h': usage(argv[0], stdout); exit(EXIT_SUCCESS); @@ -6146,6 +6143,9 @@ int main(int argc, char *argv[]) if (!ds.socket_path) ds.socket_path = LVMLOCKD_SOCKET; + if (!adopt_file) + adopt_file = LVMLOCKD_ADOPT_FILE; + /* runs daemon_main/main_loop */ daemon_start(ds); diff --git a/daemons/lvmlockd/lvmlockd-dlm.c b/daemons/lvmlockd/lvmlockd-dlm.c index 75e6dee..7915cc0 100644 --- a/daemons/lvmlockd/lvmlockd-dlm.c +++ b/daemons/lvmlockd/lvmlockd-dlm.c @@ -398,12 +398,18 @@ static int lm_adopt_dlm(struct lockspace *ls, struct resource *r, int ld_mode, (void *)1, (void *)1, (void *)1, NULL, NULL); - if (rv == -1 && errno == -EAGAIN) { + if (rv == -1 && (errno == EAGAIN)) { log_debug("S %s R %s adopt_dlm adopt mode %d try other mode", ls->name, r->name, ld_mode); rv = -EUCLEAN; goto fail; } + if (rv == -1 && (errno == ENOENT)) { + log_debug("S %s R %s adopt_dlm adopt mode %d no lock", + ls->name, r->name, ld_mode); + rv = -ENOENT; + goto fail; + } if (rv < 0) { log_debug("S %s R %s adopt_dlm mode %d flags %x error %d errno %d", ls->name, r->name, mode, flags, rv, errno); diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h index 85e8caf..191c449 100644 --- a/daemons/lvmlockd/lvmlockd-internal.h +++ b/daemons/lvmlockd/lvmlockd-internal.h @@ -11,6 +11,8 @@ #ifndef _LVM_LVMLOCKD_INTERNAL_H #define _LVM_LVMLOCKD_INTERNAL_H +#include "base/memory/container_of.h" + #define MAX_NAME 64 #define MAX_ARGS 64 @@ -145,6 +147,7 @@ struct resource { char name[MAX_NAME+1]; /* vg name or lv name */ int8_t type; /* resource type LD_RT_ */ int8_t mode; + int8_t adopt_mode; unsigned int sh_count; /* number of sh locks on locks list */ uint32_t version; uint32_t last_client_id; /* last client_id to lock or unlock resource */ @@ -216,10 +219,6 @@ struct val_blk { /* lm_unlock flags */ #define LMUF_FREE_VG 0x00000001 -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index 2c8c614..6cb5ff0 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -49,7 +49,7 @@ struct lvmcache_info { /* One per VG */ struct lvmcache_vginfo { - struct dm_list list; /* Join these vginfos together */ + struct dm_list list; /* _vginfos */ struct dm_list infos; /* List head for lvmcache_infos */ struct dm_list outdated_infos; /* vg_read moves info from infos to outdated_infos */ struct dm_list pvsummaries; /* pv_list taken directly from vgsummary */ @@ -58,7 +58,6 @@ struct lvmcache_vginfo { uint32_t status; char vgid[ID_LEN + 1]; char _padding[7]; - struct lvmcache_vginfo *next; /* Another VG with same name? */ char *creation_host; char *system_id; char *lock_type; @@ -66,8 +65,16 @@ struct lvmcache_vginfo { size_t mda_size; int seqno; bool scan_summary_mismatch; /* vgsummary from devs had mismatching seqno or checksum */ + bool has_duplicate_local_vgname; /* this local vg and another local vg have same name */ + bool has_duplicate_foreign_vgname; /* this foreign vg and another foreign vg have same name */ }; +/* + * Each VG found during scan gets a vginfo struct. + * Each vginfo is in _vginfos and _vgid_hash, and + * _vgname_hash (unless disabled due to duplicate vgnames). + */ + static struct dm_hash_table *_pvid_hash = NULL; static struct dm_hash_table *_vgid_hash = NULL; static struct dm_hash_table *_vgname_hash = NULL; @@ -262,16 +269,6 @@ void lvmcache_get_mdas(struct cmd_context *cmd, } } -static void _vginfo_attach_info(struct lvmcache_vginfo *vginfo, - struct lvmcache_info *info) -{ - if (!vginfo) - return; - - info->vginfo = vginfo; - dm_list_add(&vginfo->infos, &info->list); -} - static void _vginfo_detach_info(struct lvmcache_info *info) { if (!dm_list_empty(&info->list)) { @@ -282,57 +279,80 @@ static void _vginfo_detach_info(struct lvmcache_info *info) info->vginfo = NULL; } -/* If vgid supplied, require a match. */ -struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid) +static struct lvmcache_vginfo *_search_vginfos_list(const char *vgname, const char *vgid) { struct lvmcache_vginfo *vginfo; - if (!vgname) - return lvmcache_vginfo_from_vgid(vgid); - - if (!_vgname_hash) { - log_debug_cache(INTERNAL_ERROR "Internal lvmcache is no yet initialized."); - return NULL; - } - - if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) { - log_debug_cache("lvmcache has no info for vgname \"%s\"%s" FMTVGID ".", - vgname, (vgid) ? " with VGID " : "", (vgid) ? : ""); - return NULL; - } - - if (vgid) - do - if (!strncmp(vgid, vginfo->vgid, ID_LEN)) + if (vgid) { + dm_list_iterate_items(vginfo, &_vginfos) { + if (!strcmp(vgid, vginfo->vgid)) return vginfo; - while ((vginfo = vginfo->next)); - - if (!vginfo) - log_debug_cache("lvmcache has not found vgname \"%s\"%s" FMTVGID ".", - vgname, (vgid) ? " with VGID " : "", (vgid) ? : ""); - - return vginfo; + } + } else { + dm_list_iterate_items(vginfo, &_vginfos) { + if (!strcmp(vgname, vginfo->vgname)) + return vginfo; + } + } + return NULL; } -struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid) +static struct lvmcache_vginfo *_vginfo_lookup(const char *vgname, const char *vgid) { struct lvmcache_vginfo *vginfo; char id[ID_LEN + 1] __attribute__((aligned(8))); - if (!_vgid_hash || !vgid) { - log_debug_cache(INTERNAL_ERROR "Internal cache cannot lookup vgid."); - return NULL; + if (vgid) { + /* vgid not necessarily NULL-terminated */ + (void) dm_strncpy(id, vgid, sizeof(id)); + + if ((vginfo = dm_hash_lookup(_vgid_hash, id))) { + if (vgname && strcmp(vginfo->vgname, vgname)) { + /* should never happen */ + log_error(INTERNAL_ERROR "vginfo_lookup vgid %s has two names %s %s", + id, vginfo->vgname, vgname); + return NULL; + } + return vginfo; + } else { + /* lookup by vgid that doesn't exist */ + return NULL; + } } - /* vgid not necessarily NULL-terminated */ - (void) dm_strncpy(id, vgid, sizeof(id)); + if (vgname && !_found_duplicate_vgnames) { + if ((vginfo = dm_hash_lookup(_vgname_hash, vgname))) { + if (vginfo->has_duplicate_local_vgname) { + /* should never happen, found_duplicate_vgnames should be set */ + log_error(INTERNAL_ERROR "vginfo_lookup %s %s has_duplicate_local_vgname", vgname, vgid); + return NULL; + } + return vginfo; + } + } - if (!(vginfo = dm_hash_lookup(_vgid_hash, id))) { - log_debug_cache("lvmcache has no info for vgid \"%s\"", id); - return NULL; + if (vgname && _found_duplicate_vgnames) { + if ((vginfo = _search_vginfos_list(vgname, vgid))) { + if (vginfo->has_duplicate_local_vgname) { + log_debug("vginfo_lookup %s %s has_duplicate_local_vgname return none", vgname, vgid); + return NULL; + } + return vginfo; + } } - return vginfo; + /* lookup by vgname that doesn't exist */ + return NULL; +} + +struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname, const char *vgid) +{ + return _vginfo_lookup(vgname, vgid); +} + +struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid) +{ + return _vginfo_lookup(NULL, vgid); } const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid) @@ -353,17 +373,43 @@ const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgnam { struct lvmcache_vginfo *vginfo; - if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) - return_NULL; + if (_found_duplicate_vgnames) { + if (!(vginfo = _search_vginfos_list(vgname, NULL))) + return_NULL; + } else { + if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) + return_NULL; + } - if (!vginfo->next) - return dm_pool_strdup(cmd->mem, vginfo->vgid); + if (vginfo->has_duplicate_local_vgname) { + /* + * return NULL if there is a local VG with the same name since + * we don't know which to use. + */ + return NULL; + } - /* - * There are multiple VGs with this name to choose from. - * Return an error because we don't know which VG is intended. - */ - return NULL; + if (vginfo->has_duplicate_foreign_vgname) + return NULL; + + return dm_pool_strdup(cmd->mem, vginfo->vgid); +} + +bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname) +{ + struct lvmcache_vginfo *vginfo; + + if (_found_duplicate_vgnames) { + if (!(vginfo = _search_vginfos_list(vgname, vgid))) + return false; + } else { + if (!(vginfo = dm_hash_lookup(_vgname_hash, vgname))) + return false; + } + + if (vginfo->has_duplicate_local_vgname) + return true; + return false; } /* @@ -986,15 +1032,6 @@ int lvmcache_label_scan(struct cmd_context *cmd) log_debug_cache("Finding VG info"); - /* FIXME: can this happen? */ - if (!cmd->filter) { - log_error("label scan is missing filter"); - goto out; - } - - if (!refresh_filters(cmd)) - log_error("Scan failed to refresh device filter."); - /* * Duplicates found during this label scan are added to _initial_duplicates. */ @@ -1057,7 +1094,6 @@ int lvmcache_label_scan(struct cmd_context *cmd) r = 1; - out: dm_list_iterate_items(vginfo, &_vginfos) { if (is_orphan_vg(vginfo->vgname)) continue; @@ -1148,49 +1184,20 @@ int lvmcache_pvid_in_unused_duplicates(const char *pvid) return 0; } -static int _free_vginfo(struct lvmcache_vginfo *vginfo) +static void _free_vginfo(struct lvmcache_vginfo *vginfo) { - struct lvmcache_vginfo *primary_vginfo, *vginfo2; - int r = 1; - - vginfo2 = primary_vginfo = lvmcache_vginfo_from_vgname(vginfo->vgname, NULL); - - if (vginfo == primary_vginfo) { - dm_hash_remove(_vgname_hash, vginfo->vgname); - if (vginfo->next && !dm_hash_insert(_vgname_hash, vginfo->vgname, - vginfo->next)) { - log_error("_vgname_hash re-insertion for %s failed", - vginfo->vgname); - r = 0; - } - } else - while (vginfo2) { - if (vginfo2->next == vginfo) { - vginfo2->next = vginfo->next; - break; - } - vginfo2 = vginfo2->next; - } - - free(vginfo->system_id); free(vginfo->vgname); + free(vginfo->system_id); free(vginfo->creation_host); - - if (*vginfo->vgid && _vgid_hash && - lvmcache_vginfo_from_vgid(vginfo->vgid) == vginfo) - dm_hash_remove(_vgid_hash, vginfo->vgid); - - dm_list_del(&vginfo->list); - + if (vginfo->lock_type) + free(vginfo->lock_type); free(vginfo); - - return r; } /* - * vginfo must be info->vginfo unless info is NULL + * Remove vginfo from standard lists/hashes. */ -static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo) +static void _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vginfo) { if (info) _vginfo_detach_info(info); @@ -1198,12 +1205,16 @@ static int _drop_vginfo(struct lvmcache_info *info, struct lvmcache_vginfo *vgin /* vginfo still referenced? */ if (!vginfo || is_orphan_vg(vginfo->vgname) || !dm_list_empty(&vginfo->infos)) - return 1; + return; - if (!_free_vginfo(vginfo)) - return_0; + if (dm_hash_lookup(_vgname_hash, vginfo->vgname) == vginfo) + dm_hash_remove(_vgname_hash, vginfo->vgname); - return 1; + dm_hash_remove(_vgid_hash, vginfo->vgid); + + dm_list_del(&vginfo->list); /* _vginfos list */ + + _free_vginfo(vginfo); } void lvmcache_del(struct lvmcache_info *info) @@ -1261,180 +1272,150 @@ static int _lvmcache_update_vgid(struct lvmcache_info *info, return 1; } -static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid, - uint32_t vgstatus, const char *creation_host, - struct lvmcache_vginfo *primary_vginfo) +static int _lvmcache_update_vgname(struct cmd_context *cmd, + struct lvmcache_info *info, + const char *vgname, const char *vgid, + const char *system_id, + const struct format_type *fmt) { - struct lvmcache_vginfo *last_vginfo = primary_vginfo; - char uuid_primary[64] __attribute__((aligned(8))); - char uuid_new[64] __attribute__((aligned(8))); - int use_new = 0; - - /* Pre-existing VG takes precedence. Unexported VG takes precedence. */ - if (primary_vginfo) { - if (!id_write_format((const struct id *)vgid, uuid_new, sizeof(uuid_new))) - return_0; + char vgid_str[64] __attribute__((aligned(8))); + char other_str[64] __attribute__((aligned(8))); + struct lvmcache_vginfo *vginfo; + struct lvmcache_vginfo *other; + int vginfo_is_allowed; + int other_is_allowed; - if (!id_write_format((const struct id *)&primary_vginfo->vgid, uuid_primary, - sizeof(uuid_primary))) - return_0; + if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname))) + return 1; - _found_duplicate_vgnames = 1; + if (!id_write_format((const struct id *)vgid, vgid_str, sizeof(vgid_str))) + stack; - /* - * vginfo is kept for each VG with the same name. - * They are saved with the vginfo->next list. - * These checks just decide the ordering of - * that list. - * - * FIXME: it should no longer matter what order - * the vginfo's are kept in, so we can probably - * remove these comparisons and reordering entirely. - * - * If Primary not exported, new exported => keep - * Else Primary exported, new not exported => change - * Else Primary has hostname for this machine => keep - * Else Primary has no hostname, new has one => change - * Else New has hostname for this machine => change - * Else Keep primary. - */ - if (!(primary_vginfo->status & EXPORTED_VG) && - (vgstatus & EXPORTED_VG)) - log_verbose("Cache: Duplicate VG name %s: " - "Existing %s takes precedence over " - "exported %s", new_vginfo->vgname, - uuid_primary, uuid_new); - else if ((primary_vginfo->status & EXPORTED_VG) && - !(vgstatus & EXPORTED_VG)) { - log_verbose("Cache: Duplicate VG name %s: " - "%s takes precedence over exported %s", - new_vginfo->vgname, uuid_new, - uuid_primary); - use_new = 1; - } else if (primary_vginfo->creation_host && - !strcmp(primary_vginfo->creation_host, - primary_vginfo->fmt->cmd->hostname)) - log_verbose("Cache: Duplicate VG name %s: " - "Existing %s (created here) takes precedence " - "over %s", new_vginfo->vgname, uuid_primary, - uuid_new); - else if (!primary_vginfo->creation_host && creation_host) { - log_verbose("Cache: Duplicate VG name %s: " - "%s (with creation_host) takes precedence over %s", - new_vginfo->vgname, uuid_new, - uuid_primary); - use_new = 1; - } else if (creation_host && - !strcmp(creation_host, - primary_vginfo->fmt->cmd->hostname)) { - log_verbose("Cache: Duplicate VG name %s: " - "%s (created here) takes precedence over %s", - new_vginfo->vgname, uuid_new, - uuid_primary); - use_new = 1; - } else { - log_verbose("Cache: Duplicate VG name %s: " - "Prefer existing %s vs new %s", - new_vginfo->vgname, uuid_primary, uuid_new); + /* + * Add vginfo for orphan VG + */ + if (!info) { + if (!(vginfo = zalloc(sizeof(*vginfo)))) { + log_error("lvmcache adding vg list alloc failed %s", vgname); + return 0; } - - if (!use_new) { - while (last_vginfo->next) - last_vginfo = last_vginfo->next; - last_vginfo->next = new_vginfo; - return 1; + if (!(vginfo->vgname = strdup(vgname))) { + free(vginfo); + log_error("lvmcache adding vg name alloc failed %s", vgname); + return 0; } + dm_list_init(&vginfo->infos); + dm_list_init(&vginfo->outdated_infos); + dm_list_init(&vginfo->pvsummaries); + vginfo->fmt = fmt; - dm_hash_remove(_vgname_hash, primary_vginfo->vgname); - } - - if (!dm_hash_insert(_vgname_hash, new_vginfo->vgname, new_vginfo)) { - log_error("cache_update: vg hash insertion failed: %s", - new_vginfo->vgname); - return 0; - } - - if (primary_vginfo) - new_vginfo->next = primary_vginfo; - - return 1; -} + if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) { + free(vginfo->vgname); + free(vginfo); + return_0; + } -static int _lvmcache_update_vgname(struct lvmcache_info *info, - const char *vgname, const char *vgid, - uint32_t vgstatus, const char *creation_host, - const struct format_type *fmt) -{ - struct lvmcache_vginfo *vginfo, *primary_vginfo; - char mdabuf[32]; + if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) { + free(vginfo->vgname); + free(vginfo); + return_0; + } - if (!vgname || (info && info->vginfo && !strcmp(info->vginfo->vgname, vgname))) + /* Ensure orphans appear last on list_iterate */ + dm_list_add(&_vginfos, &vginfo->list); return 1; + } - /* Remove existing vginfo entry */ - if (info) - _drop_vginfo(info, info->vginfo); + _drop_vginfo(info, info->vginfo); - if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid))) { + if (!(vginfo = lvmcache_vginfo_from_vgid(vgid))) { /* * Create a vginfo struct for this VG and put the vginfo * into the hash table. */ + log_debug_cache("lvmcache adding vginfo for %s %s", vgname, vgid_str); + if (!(vginfo = zalloc(sizeof(*vginfo)))) { - log_error("lvmcache_update_vgname: list alloc failed"); + log_error("lvmcache adding vg list alloc failed %s", vgname); return 0; } if (!(vginfo->vgname = strdup(vgname))) { free(vginfo); - log_error("cache vgname alloc failed for %s", vgname); + log_error("lvmcache adding vg name alloc failed %s", vgname); return 0; } dm_list_init(&vginfo->infos); dm_list_init(&vginfo->outdated_infos); dm_list_init(&vginfo->pvsummaries); - /* - * A different VG (different uuid) can exist with the same name. - * In this case, the two VGs will have separate vginfo structs, - * but the second will be linked onto the existing vginfo->next, - * not in the hash. - */ - primary_vginfo = lvmcache_vginfo_from_vgname(vgname, NULL); + if ((other = dm_hash_lookup(_vgname_hash, vgname))) { + log_debug_cache("lvmcache adding vginfo found duplicate VG name %s", vgname); - if (!_insert_vginfo(vginfo, vgid, vgstatus, creation_host, primary_vginfo)) { - free(vginfo->vgname); - free(vginfo); - return 0; + /* + * A different VG (different uuid) can exist with the + * same name. In this case, the two VGs will have + * separate vginfo structs, but one will be in the + * vgname_hash. If both vginfos are local/accessible, + * then _found_duplicate_vgnames is set which will + * disable any further use of the vgname_hash. + */ + + if (!memcmp(other->vgid, vgid, ID_LEN)) { + /* shouldn't happen since we looked up by vgid above */ + log_error(INTERNAL_ERROR "lvmcache_update_vgname %s %s %s %s", + vgname, vgid_str, other->vgname, other->vgid); + free(vginfo->vgname); + free(vginfo); + return 0; + } + + vginfo_is_allowed = is_system_id_allowed(cmd, system_id); + other_is_allowed = is_system_id_allowed(cmd, other->system_id); + + if (vginfo_is_allowed && other_is_allowed) { + if (!id_write_format((const struct id *)other->vgid, other_str, sizeof(other_str))) + stack; + + vginfo->has_duplicate_local_vgname = 1; + other->has_duplicate_local_vgname = 1; + _found_duplicate_vgnames = 1; + + log_warn("WARNING: VG name %s is used by VGs %s and %s.", + vgname, vgid_str, other_str); + log_warn("Fix duplicate VG names with vgrename uuid, a device filter, or system IDs."); + } + + if (!vginfo_is_allowed && !other_is_allowed) { + vginfo->has_duplicate_foreign_vgname = 1; + other->has_duplicate_foreign_vgname = 1; + } + + if (!other_is_allowed && vginfo_is_allowed) { + /* the accessible vginfo must be in vgnames_hash */ + dm_hash_remove(_vgname_hash, vgname); + if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) { + log_error("lvmcache adding vginfo to name hash failed %s", vgname); + return 0; + } + } + } else { + if (!dm_hash_insert(_vgname_hash, vgname, vginfo)) { + log_error("lvmcache adding vg to name hash failed %s", vgname); + free(vginfo->vgname); + free(vginfo); + return 0; + } } - /* Ensure orphans appear last on list_iterate */ - if (is_orphan_vg(vgname)) - dm_list_add(&_vginfos, &vginfo->list); - else - dm_list_add_h(&_vginfos, &vginfo->list); + dm_list_add_h(&_vginfos, &vginfo->list); } - if (info) - _vginfo_attach_info(vginfo, info); - else if (!_lvmcache_update_vgid(NULL, vginfo, vgid)) /* Orphans */ - return_0; - - /* FIXME Check consistency of list! */ vginfo->fmt = fmt; + info->vginfo = vginfo; + dm_list_add(&vginfo->infos, &info->list); - if (info) { - if (info->mdas.n) - sprintf(mdabuf, " with %u mda(s)", dm_list_size(&info->mdas)); - else - mdabuf[0] = '\0'; - log_debug_cache("lvmcache %s: now in VG %s%s%s%s%s.", - dev_name(info->dev), - vgname, vginfo->vgid[0] ? " (" : "", - vginfo->vgid[0] ? vginfo->vgid : "", - vginfo->vgid[0] ? ")" : "", mdabuf); - } else - log_debug_cache("lvmcache: Initialised VG %s.", vgname); + log_debug_cache("lvmcache %s: now in VG %s %s", dev_name(info->dev), vgname, vgid_str); return 1; } @@ -1511,9 +1492,9 @@ out: return 1; } -int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt) +int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt) { - return _lvmcache_update_vgname(NULL, vgname, vgname, 0, "", fmt); + return _lvmcache_update_vgname(cmd, NULL, vgname, vgname, "", fmt); } static void _lvmcache_update_pvsummaries(struct lvmcache_vginfo *vginfo, struct lvmcache_vgsummary *vgsummary) @@ -1532,7 +1513,7 @@ static void _lvmcache_update_pvsummaries(struct lvmcache_vginfo *vginfo, struct * Returning 0 causes the caller to remove the info struct for this * device from lvmcache, which will make it look like a missing device. */ -int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary) +int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary) { const char *vgname = vgsummary->vgname; const char *vgid = (char *)&vgsummary->vgid; @@ -1545,6 +1526,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg vgid = vgname; } + /* FIXME: remove this, it shouldn't be needed */ /* If PV without mdas is already in a real VG, don't make it orphan */ if (is_orphan_vg(vgname) && info->vginfo && mdas_empty_or_ignored(&info->mdas) && @@ -1556,7 +1538,7 @@ int lvmcache_update_vgname_and_id(struct lvmcache_info *info, struct lvmcache_vg * and attaches the info struct for the dev to the vginfo. * Puts the vginfo into the vgname hash table. */ - if (!_lvmcache_update_vgname(info, vgname, vgid, vgsummary->vgstatus, vgsummary->creation_host, info->fmt)) { + if (!_lvmcache_update_vgname(cmd, info, vgname, vgid, vgsummary->system_id, info->fmt)) { /* shouldn't happen, internal error */ log_error("Failed to update VG %s info in lvmcache.", vgname); return 0; @@ -1735,7 +1717,7 @@ int lvmcache_update_vg_from_write(struct volume_group *vg) (void) dm_strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s)); /* FIXME Could pvl->pv->dev->pvid ever be different? */ if ((info = lvmcache_info_from_pvid(pvid_s, pvl->pv->dev, 0)) && - !lvmcache_update_vgname_and_id(info, &vgsummary)) + !lvmcache_update_vgname_and_id(vg->cmd, info, &vgsummary)) return_0; } @@ -1819,7 +1801,7 @@ int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted) * info's for PVs without metadata were not connected to the * vginfo by label_scan, so do it here. */ - if (!lvmcache_update_vgname_and_id(info, &vgsummary)) { + if (!lvmcache_update_vgname_and_id(vg->cmd, info, &vgsummary)) { log_debug_cache("lvmcache_update_vg %s failed to update info for %s", vg->name, dev_name(info->dev)); } @@ -1927,7 +1909,7 @@ static struct lvmcache_info * _create_info(struct labeller *labeller, struct dev return info; } -struct lvmcache_info *lvmcache_add(struct labeller *labeller, +struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller, const char *pvid, struct device *dev, uint64_t label_sector, const char *vgname, const char *vgid, uint32_t vgstatus, int *is_duplicate) @@ -2042,7 +2024,7 @@ update_vginfo: if (vgid) strncpy((char *)&vgsummary.vgid, vgid, sizeof(vgsummary.vgid)); - if (!lvmcache_update_vgname_and_id(info, &vgsummary)) { + if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) { if (created) { dm_hash_remove(_pvid_hash, pvid_s); strcpy(info->dev->pvid, ""); @@ -2055,7 +2037,7 @@ update_vginfo: return info; } -static void _lvmcache_destroy_entry(struct lvmcache_info *info) +static void _lvmcache_destroy_info(struct lvmcache_info *info) { _vginfo_detach_info(info); info->dev->pvid[0] = 0; @@ -2063,20 +2045,11 @@ static void _lvmcache_destroy_entry(struct lvmcache_info *info) free(info); } -static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo) -{ - struct lvmcache_vginfo *next; - - do { - next = vginfo->next; - if (!_free_vginfo(vginfo)) - stack; - } while ((vginfo = next)); -} - void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset) { - log_debug_cache("Dropping VG info"); + struct lvmcache_vginfo *vginfo, *vginfo2; + + log_debug_cache("Destroy lvmcache content"); if (_vgid_hash) { dm_hash_destroy(_vgid_hash); @@ -2084,20 +2057,24 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset) } if (_pvid_hash) { - dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_entry); + dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _lvmcache_destroy_info); dm_hash_destroy(_pvid_hash); _pvid_hash = NULL; } if (_vgname_hash) { - dm_hash_iter(_vgname_hash, - (dm_hash_iterate_fn) _lvmcache_destroy_vgnamelist); dm_hash_destroy(_vgname_hash); _vgname_hash = NULL; } + dm_list_iterate_items_safe(vginfo, vginfo2, &_vginfos) { + dm_list_del(&vginfo->list); + _free_vginfo(vginfo); + } + if (!dm_list_empty(&_vginfos)) - log_error(INTERNAL_ERROR "_vginfos list should be empty"); + log_error(INTERNAL_ERROR "vginfos list should be empty"); + dm_list_init(&_vginfos); /* @@ -2109,6 +2086,8 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset) * We want the same preferred devices to be chosen each time, so save * the unpreferred devs here so that _choose_preferred_devs can use * this to make the same choice each time. + * + * FIXME: I don't think is is needed any more. */ _destroy_device_list(&_prev_unused_duplicate_devs); dm_list_splice(&_prev_unused_duplicate_devs, &_unused_duplicates); @@ -2122,7 +2101,7 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset) stack; dm_list_iterate_items(fmt, &cmd->formats) { - if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt)) + if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt)) stack; } } @@ -2567,36 +2546,6 @@ int lvmcache_vginfo_has_pvid(struct lvmcache_vginfo *vginfo, char *pvid) return 0; } -struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd, - const char *vgname, - struct device *dev, - int use_mda_num) -{ - struct lvmcache_vginfo *vginfo; - struct lvmcache_info *info; - struct metadata_area *mda; - - if (!use_mda_num) - use_mda_num = 1; - - if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL))) - return NULL; - - dm_list_iterate_items(info, &vginfo->infos) { - if (info->dev != dev) - continue; - - dm_list_iterate_items(mda, &info->mdas) { - if ((use_mda_num == 1) && (mda->status & MDA_PRIMARY)) - return mda; - if ((use_mda_num == 2) && !(mda->status & MDA_PRIMARY)) - return mda; - } - return NULL; - } - return NULL; -} - /* * This is used by the metadata repair command to check if * the metadata on a dev needs repair because it's old. diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h index 0c8c789..6cef4d1 100644 --- a/lib/cache/lvmcache.h +++ b/lib/cache/lvmcache.h @@ -71,16 +71,16 @@ int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const int lvmcache_label_rescan_vg_rw(struct cmd_context *cmd, const char *vgname, const char *vgid); /* Add/delete a device */ -struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, +struct lvmcache_info *lvmcache_add(struct cmd_context *cmd, struct labeller *labeller, const char *pvid, struct device *dev, uint64_t label_sector, const char *vgname, const char *vgid, uint32_t vgstatus, int *is_duplicate); -int lvmcache_add_orphan_vginfo(const char *vgname, struct format_type *fmt); +int lvmcache_add_orphan_vginfo(struct cmd_context *cmd, const char *vgname, struct format_type *fmt); void lvmcache_del(struct lvmcache_info *info); void lvmcache_del_dev(struct device *dev); /* Update things */ -int lvmcache_update_vgname_and_id(struct lvmcache_info *info, +int lvmcache_update_vgname_and_id(struct cmd_context *cmd, struct lvmcache_info *info, struct lvmcache_vgsummary *vgsummary); int lvmcache_update_vg_from_read(struct volume_group *vg, unsigned precommitted); int lvmcache_update_vg_from_write(struct volume_group *vg); @@ -161,11 +161,6 @@ struct device *lvmcache_device(struct lvmcache_info *info); unsigned lvmcache_mda_count(struct lvmcache_info *info); uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info); -struct metadata_area *lvmcache_get_mda(struct cmd_context *cmd, - const char *vgname, - struct device *dev, - int use_mda_num); - bool lvmcache_has_duplicate_devs(void); void lvmcache_del_dev_from_duplicates(struct device *dev); bool lvmcache_dev_is_unused_duplicate(struct device *dev); @@ -174,6 +169,7 @@ int lvmcache_get_unused_duplicates(struct cmd_context *cmd, struct dm_list *head int vg_has_duplicate_pvs(struct volume_group *vg); int lvmcache_found_duplicate_vgnames(void); +bool lvmcache_has_duplicate_local_vgname(const char *vgid, const char *vgname); int lvmcache_contains_lock_type_sanlock(struct cmd_context *cmd); diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 88d5b3e..63b6811 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -1276,7 +1276,7 @@ int init_lvmcache_orphans(struct cmd_context *cmd) struct format_type *fmt; dm_list_iterate_items(fmt, &cmd->formats) - if (!lvmcache_add_orphan_vginfo(fmt->orphan_vg_name, fmt)) + if (!lvmcache_add_orphan_vginfo(cmd, fmt->orphan_vg_name, fmt)) return_0; return 1; @@ -1598,6 +1598,7 @@ 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(); diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index 735441f..33b9345 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -86,6 +86,9 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size) int fd = dev->bcache_fd; int do_close = 0; + if (dm_list_empty(&dev->aliases)) + return 0; + if (dev->size_seqno == _dev_size_seqno) { log_very_verbose("%s: using cached size %" PRIu64 " sectors", name, dev->size); diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c index 3a741da..733e62b 100644 --- a/lib/format_text/archiver.c +++ b/lib/format_text/archiver.c @@ -315,7 +315,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd, } dm_list_iterate_items(mda, &tf->metadata_areas_in_use) { - if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL))) + if (!(vg = mda->ops->vg_read(cmd, tf, vg_name, mda, NULL, NULL))) stack; break; } diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c index 268bd64..e448712 100644 --- a/lib/format_text/format-text.c +++ b/lib/format_text/format-text.c @@ -290,7 +290,8 @@ static int _raw_write_mda_header(const struct format_type *fmt, * in the label scanning path. */ -static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area, +static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd, + struct device_area *dev_area, struct mda_header *mdah, int primary_mda, const char *vgname, int *precommitted) @@ -369,7 +370,7 @@ static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area, vgnamebuf, vgname); if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) && - !lvmcache_update_vgname_and_id(info, &vgsummary_orphan)) + !lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan)) stack; return NULL; @@ -447,7 +448,8 @@ static uint64_t _next_rlocn_offset(struct volume_group *vg, struct raw_locn *rlo return new_start; } -static struct volume_group *_vg_read_raw_area(struct format_instance *fid, +static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd, + struct format_instance *fid, const char *vgname, struct device_area *area, struct cached_vg_fmtdata **vg_fmtdata, @@ -468,7 +470,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid, goto out; } - if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) { + if (!(rlocn = _read_metadata_location_vg(cmd, area, mdah, primary_mda, vgname, &precommitted))) { log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev)); goto out; } @@ -503,7 +505,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid, return vg; } -static struct volume_group *_vg_read_raw(struct format_instance *fid, +static struct volume_group *_vg_read_raw(struct cmd_context *cmd, + struct format_instance *fid, const char *vgname, struct metadata_area *mda, struct cached_vg_fmtdata **vg_fmtdata, @@ -512,12 +515,13 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid, struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct volume_group *vg; - vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda)); + vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda)); return vg; } -static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid, +static struct volume_group *_vg_read_precommit_raw(struct cmd_context *cmd, + struct format_instance *fid, const char *vgname, struct metadata_area *mda, struct cached_vg_fmtdata **vg_fmtdata, @@ -526,7 +530,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid, struct mda_context *mdac = (struct mda_context *) mda->metadata_locn; struct volume_group *vg; - vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda)); + vg = _vg_read_raw_area(cmd, fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda)); return vg; } @@ -1321,7 +1325,7 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid, return vg; } -static struct volume_group *_vg_read_file(struct format_instance *fid, +static struct volume_group *_vg_read_file(struct cmd_context *cmd, struct format_instance *fid, const char *vgname, struct metadata_area *mda, struct cached_vg_fmtdata **vg_fmtdata, @@ -1332,7 +1336,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid, return _vg_read_file_name(fid, vgname, tc->path_live); } -static struct volume_group *_vg_read_precommit_file(struct format_instance *fid, +static struct volume_group *_vg_read_precommit_file(struct cmd_context *cmd, struct format_instance *fid, const char *vgname, struct metadata_area *mda, struct cached_vg_fmtdata **vg_fmtdata, @@ -1713,7 +1717,7 @@ static int _set_ext_flags(struct physical_volume *pv, struct lvmcache_info *info } /* Only for orphans - FIXME That's not true any more */ -static int _text_pv_write(const struct format_type *fmt, struct physical_volume *pv) +static int _text_pv_write(struct cmd_context *cmd, const struct format_type *fmt, struct physical_volume *pv) { struct format_instance *fid = pv->fid; const char *pvid = (const char *) (*pv->old_id.uuid ? &pv->old_id : &pv->id); @@ -1725,7 +1729,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume unsigned mda_index; /* Add a new cache entry with PV info or update existing one. */ - if (!(info = lvmcache_add(fmt->labeller, (const char *) &pv->id, + if (!(info = lvmcache_add(cmd, fmt->labeller, (const char *) &pv->id, pv->dev, pv->label_sector, pv->vg_name, is_orphan_vg(pv->vg_name) ? pv->vg_name : pv->vg ? (const char *) &pv->vg->id : NULL, 0, NULL))) return_0; diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c index 9241eca..1674126 100644 --- a/lib/format_text/text_label.c +++ b/lib/format_text/text_label.c @@ -370,7 +370,7 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt, * the metadata is at for those PVs. */ -static int _text_read(struct labeller *labeller, struct device *dev, void *label_buf, +static int _text_read(struct cmd_context *cmd, struct labeller *labeller, struct device *dev, void *label_buf, uint64_t label_sector, int *is_duplicate) { struct lvmcache_vgsummary vgsummary; @@ -410,7 +410,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label * * Other reasons for lvmcache_add to return NULL are internal errors. */ - if (!(info = lvmcache_add(labeller, (char *)pvhdr->pv_uuid, dev, label_sector, + if (!(info = lvmcache_add(cmd, labeller, (char *)pvhdr->pv_uuid, dev, label_sector, FMT_TEXT_ORPHAN_VG_NAME, FMT_TEXT_ORPHAN_VG_NAME, 0, is_duplicate))) return_0; @@ -503,7 +503,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label rv1 = _read_mda_header_and_metadata(fmt, mda1, &vgsummary, &bad_fields); if (rv1 && !vgsummary.zero_offset && !vgsummary.mda_ignored) { - if (!lvmcache_update_vgname_and_id(info, &vgsummary)) { + if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) { /* I believe this is only an internal error. */ dm_list_del(&mda1->list); @@ -554,7 +554,7 @@ static int _text_read(struct labeller *labeller, struct device *dev, void *label rv2 = _read_mda_header_and_metadata(fmt, mda2, &vgsummary, &bad_fields); if (rv2 && !vgsummary.zero_offset && !vgsummary.mda_ignored) { - if (!lvmcache_update_vgname_and_id(info, &vgsummary)) { + if (!lvmcache_update_vgname_and_id(cmd, info, &vgsummary)) { dm_list_del(&mda2->list); /* Are there other cases besides mismatch and internal error? */ diff --git a/lib/label/hints.c b/lib/label/hints.c index 48fb661..9546f48 100644 --- a/lib/label/hints.c +++ b/lib/label/hints.c @@ -351,6 +351,7 @@ static void _unlock_hints(struct cmd_context *cmd) void hints_exit(struct cmd_context *cmd) { + free_hints(&cmd->hints); if (_hints_fd == -1) return; return _unlock_hints(cmd); @@ -419,6 +420,9 @@ static int _dev_in_hint_hash(struct cmd_context *cmd, struct device *dev) { uint64_t devsize = 0; + if (dm_list_empty(&dev->aliases)) + return 0; + if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "regex")) return 0; @@ -1318,6 +1322,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints, */ if (!_read_hint_file(cmd, &hints_list, &needs_refresh)) { log_debug("get_hints: read fail"); + free_hints(&hints_list); _unlock_hints(cmd); return 0; } @@ -1330,6 +1335,7 @@ int get_hints(struct cmd_context *cmd, struct dm_list *hints_out, int *newhints, */ if (needs_refresh) { log_debug("get_hints: needs refresh"); + free_hints(&hints_list); if (!_lock_hints(cmd, LOCK_EX, NONBLOCK)) return 0; diff --git a/lib/label/label.c b/lib/label/label.c index 0458313..4d37cef 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -431,7 +431,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f, * info/vginfo structs. That lvmcache info is used later when the * command wants to read the VG to do something to it. */ - ret = labeller->ops->read(labeller, dev, label_buf, sector, &is_duplicate); + ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate); if (!ret) { if (is_duplicate) { diff --git a/lib/label/label.h b/lib/label/label.h index 4108906..9a4b630 100644 --- a/lib/label/label.h +++ b/lib/label/label.h @@ -64,7 +64,7 @@ struct label_ops { /* * Read a label from a volume. */ - int (*read) (struct labeller * l, struct device * dev, + int (*read) (struct cmd_context *cmd, struct labeller * l, struct device * dev, void *label_buf, uint64_t label_sector, int *is_duplicate); /* diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index e378fe6..dca7954 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -635,7 +635,6 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in const char *vg_lock_args = NULL; const char *opts = NULL; struct pv_list *pvl; - struct device *sector_dev; uint32_t sector_size = 0; unsigned int physical_block_size, logical_block_size; int num_mb = 0; @@ -656,16 +655,11 @@ static int _init_vg_sanlock(struct cmd_context *cmd, struct volume_group *vg, in dm_list_iterate_items(pvl, &vg->pvs) { if (!dev_get_direct_block_sizes(pvl->pv->dev, &physical_block_size, &logical_block_size)) continue; - - if (!sector_size) { - sector_size = logical_block_size; - sector_dev = pvl->pv->dev; - } else if (sector_size != logical_block_size) { - log_error("Inconsistent logical block sizes for %s and %s.", - dev_name(pvl->pv->dev), dev_name(sector_dev)); - return 0; - } + if ((physical_block_size == 4096) || (logical_block_size == 4096)) + sector_size = 4096; } + if (!sector_size) + sector_size = 512; log_debug("Using sector size %u for sanlock LV", sector_size); diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h index 52bc776..083f74a 100644 --- a/lib/metadata/metadata-exported.h +++ b/lib/metadata/metadata-exported.h @@ -744,9 +744,6 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_ const char *vgid, uint32_t read_flags, uint32_t lockd_state); struct volume_group *vg_read_orphans(struct cmd_context *cmd, const char *orphan_vgname); -/* this is historical and being removed, don't use */ -uint32_t vg_read_error(struct volume_group *vg_handle); - /* pe_start and pe_end relate to any existing data so that new metadata * areas can avoid overlap */ struct physical_volume *pv_create(const struct cmd_context *cmd, diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 9c44388..4b8dce9 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -3666,7 +3666,7 @@ int pv_write(struct cmd_context *cmd, return 0; } - if (!pv->fmt->ops->pv_write(pv->fmt, pv)) + if (!pv->fmt->ops->pv_write(cmd, pv->fmt, pv)) return_0; pv->status &= ~UNLABELLED_PV; @@ -4010,17 +4010,6 @@ static int _access_vg_exported(struct cmd_context *cmd, struct volume_group *vg) return 0; } -/* - * Test the validity of a VG handle returned by vg_read() or vg_read_for_update(). - */ -uint32_t vg_read_error(struct volume_group *vg_handle) -{ - if (!vg_handle) - return FAILED_ALLOCATION; - - return SUCCESS; -} - struct format_instance *alloc_fid(const struct format_type *fmt, const struct format_instance_ctx *fic) { @@ -4751,18 +4740,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, lvmcache_label_rescan_vg(cmd, vgname, vgid); } - /* Now determine the correct vgname if none was supplied */ - if (!vgname && !(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) { - log_debug_metadata("Cache did not find VG name from vgid %s", vgid); - return NULL; - } - - /* Determine the correct vgid if none was supplied */ - if (!vgid && !(vgid = lvmcache_vgid_from_vgname(cmd, vgname))) { - log_debug_metadata("Cache did not find VG vgid from name %s", vgname); - return NULL; - } - /* * A "format instance" is an abstraction for a VG location, * i.e. where a VG's metadata exists on disk. @@ -4841,7 +4818,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, log_debug_metadata("Reading VG %s precommit metadata from %s %llu", vgname, dev_name(mda_dev), (unsigned long long)mda->header_start); - vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg); + vg = mda->ops->vg_read_precommit(cmd, fid, vgname, mda, &vg_fmtdata, &use_previous_vg); if (!vg && !use_previous_vg) { log_warn("WARNING: Reading VG %s precommit on %s failed.", vgname, dev_name(mda_dev)); @@ -4852,7 +4829,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd, log_debug_metadata("Reading VG %s metadata from %s %llu", vgname, dev_name(mda_dev), (unsigned long long)mda->header_start); - vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg); + vg = mda->ops->vg_read(cmd, fid, vgname, mda, &vg_fmtdata, &use_previous_vg); if (!vg && !use_previous_vg) { log_warn("WARNING: Reading VG %s on %s failed.", vgname, dev_name(mda_dev)); @@ -4999,6 +4976,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const int missing_pv_dev = 0; int missing_pv_flag = 0; uint32_t failure = 0; + int original_vgid_set = vgid ? 1 : 0; int writing = (vg_read_flags & READ_FOR_UPDATE); int activating = (vg_read_flags & READ_FOR_ACTIVATE); @@ -5033,7 +5011,45 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const goto bad; } + /* I belive this is unused, the name is always set. */ + if (!vg_name && !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid))) { + unlock_vg(cmd, NULL, vg_name); + log_error("VG name not found for vgid %s", vgid); + failure |= FAILED_NOTFOUND; + goto_bad; + } + + /* + * If the command is process all vgs, process_each will get a list of vgname+vgid + * pairs, and then call vg_read() for each vgname+vigd. In this case we know + * which VG to read even if there are duplicate names, and we don't fail. + * + * If the user has requested one VG by name, process_each passes only the vgname + * to vg_read(), and we look up the vgid from lvmcache. lvmcache finds duplicate + * vgnames, doesn't know which is intended, returns a NULL vgid, and we fail. + */ + + if (!vgid) + vgid = lvmcache_vgid_from_vgname(cmd, vg_name); + + if (!vgid) { + unlock_vg(cmd, NULL, vg_name); + /* Some callers don't care if the VG doesn't exist and don't want an error message. */ + if (!(vg_read_flags & READ_OK_NOTFOUND)) + log_error("Volume group \"%s\" not found", vg_name); + failure |= FAILED_NOTFOUND; + goto_bad; + } + + /* + * vgchange -ay (no vgname arg) will activate multiple local VGs with the same + * name, but if the vgs have the same lv name, activating those lvs will fail. + */ + if (activating && original_vgid_set && lvmcache_has_duplicate_local_vgname(vgid, vg_name)) + log_warn("WARNING: activating multiple VGs with the same name is dangerous and may fail."); + if (!(vg = _vg_read(cmd, vg_name, vgid, 0, writing))) { + unlock_vg(cmd, NULL, vg_name); /* Some callers don't care if the VG doesn't exist and don't want an error message. */ if (!(vg_read_flags & READ_OK_NOTFOUND)) log_error("Volume group \"%s\" not found.", vg_name); diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index f199fc4..2c22450 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -76,12 +76,14 @@ struct cached_vg_fmtdata; /* Per-format per-metadata area operations */ struct metadata_area_ops { struct dm_list list; - struct volume_group *(*vg_read) (struct format_instance * fi, + struct volume_group *(*vg_read) (struct cmd_context *cmd, + struct format_instance * fi, const char *vg_name, struct metadata_area * mda, struct cached_vg_fmtdata **vg_fmtdata, unsigned *use_previous_vg); - struct volume_group *(*vg_read_precommit) (struct format_instance * fi, + struct volume_group *(*vg_read_precommit) (struct cmd_context *cmd, + struct format_instance * fi, const char *vg_name, struct metadata_area * mda, struct cached_vg_fmtdata **vg_fmtdata, @@ -326,7 +328,7 @@ struct format_handler { * Write a PV structure to disk. Fails if the PV is in a VG ie * pv->vg_name must be a valid orphan VG name */ - int (*pv_write) (const struct format_type * fmt, + int (*pv_write) (struct cmd_context *cmd, const struct format_type * fmt, struct physical_volume * pv); /* diff --git a/man/lvmlockd.8_main b/man/lvmlockd.8_main index 8ed5400..c21f7a9 100644 --- a/man/lvmlockd.8_main +++ b/man/lvmlockd.8_main @@ -58,6 +58,10 @@ For default settings, see lvmlockd -h. .I path Set path to the socket to listen on. +.B --adopt-file +.I path + Set path to the adopt file. + .B --syslog-priority | -S err|warning|debug Write log messages from this level up to syslog. @@ -76,6 +80,8 @@ For default settings, see lvmlockd -h. .I seconds Override the default sanlock I/O timeout. +.B --adopt | -A 0|1 + Enable (1) or disable (0) lock adoption. .SH USAGE @@ -548,7 +554,13 @@ necessary locks. .B lvmlockd failure If lvmlockd fails or is killed while holding locks, the locks are orphaned -in the lock manager. +in the lock manager. Orphaned locks must be cleared or adopted before the +associated resources can be accessed normally. If lock adoption is +enabled, lvmlockd keeps a record of locks in the adopt-file. A subsequent +instance of lvmlockd will then adopt locks orphaned by the previous +instance. Adoption must be enabled in both instances (--adopt|-A 1). +Without adoption, the lock manager or host would require a reset to clear +orphaned lock state. .B dlm/corosync failure diff --git a/test/shell/duplicate-vgnames.sh b/test/shell/duplicate-vgnames.sh new file mode 100644 index 0000000..0f98f9c --- /dev/null +++ b/test/shell/duplicate-vgnames.sh @@ -0,0 +1,660 @@ +#!/usr/bin/env bash + +# Copyright (C) 2008-2013 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. + +SKIP_WITH_LVMLOCKD=1 +SKIP_WITH_LVMPOLLD=1 + +. lib/inittest + +aux prepare_devs 7 + +# test setups: +# # local vgs named foo # foreign vg named foo +# a. 0 1 +# b. 0 2 +# c. 1 1 +# d. 1 2 +# e. 2 0 +# f. 2 1 +# g. 2 2 +# h. 3 3 +# +# commands to run for each test setup: +# +# vgs +# all cases show all local +# +# vgs --foreign +# all cases show all local and foreign +# +# vgs foo +# a. not found +# b. not found +# c. show 1 local +# d. show 1 local +# e-g. dup error +# +# vgs --foreign foo +# a. show 1 foreign +# b. dup error +# c. show 1 local +# d. show 1 local +# e-g. dup error +# +# vgchange -ay +# a. none +# b. none +# c. activate 1 local +# d. activate 1 local +# e-g. activate 2 local +# (if both local vgs have lvs with same name the second will fail to activate) +# +# vgchange -ay foo +# a. none +# b. none +# c. activate 1 local +# d. activate 1 local +# e-g. dup error +# +# lvcreate foo +# a. none +# b. none +# c. create 1 local +# d. create 1 local +# e-g. dup error +# +# vgremove foo +# a. none +# b. none +# c. remove 1 local +# d. remove 1 local +# e-g. dup error +# (in a couple cases test that vgremove -S vg_uuid=N works for local vg when local dups exist) + + +# a. 0 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 + +vgs -o+uuid |tee out +not grep $vg1 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +vgs --foreign -o+uuid $vg1 |tee out +grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +not grep active out +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +not grep active out +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 + +not vgremove $vg1 +vgs --foreign -o+uuid |tee out +grep $UUID1 out +vgremove -y -S vg_uuid=$UUID1 +vgs --foreign -o+uuid |tee out +grep $UUID1 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" + +# b. 0 local, 2 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux enable_dev "$dev1" + +vgs -o+uuid |tee out +not grep $vg1 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +not vgs --foreign -o+uuid $vg1 |tee out +not grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +not grep active out +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +not grep active out +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 +grep $UUID2 out | not grep $lv2 + +not vgremove $vg1 +vgs --foreign -o+uuid |tee out +grep $UUID1 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + +# c. 1 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux enable_dev "$dev1" + +vgs -o+uuid |tee out +cat out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out + +vgs -o+uuid $vg1 |tee out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out +vgs --foreign -o+uuid $vg1 |tee out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | not grep active +vgchange -an + +vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | not grep active +vgchange -an + +lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | grep $lv2 +grep $UUID2 out | not grep $lv2 + +vgremove -y $vg1 +vgs -o+uuid |tee out +not grep $UUID1 out +vgs --foreign -o+uuid |tee out +grep $UUID2 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + +# d. 1 local, 2 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n $lv1 -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" + +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out +not grep $UUID3 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out + +vgs -o+uuid $vg1 |tee out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out +not grep $UUID3 out +vgs --foreign -o+uuid $vg1 |tee out +grep $vg1 out +grep $UUID1 out +not grep $UUID2 out +not grep $UUID3 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | not grep active +grep $UUID3 out | not grep active +vgchange -an + +vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | not grep active +grep $UUID3 out | not grep active +vgchange -an + +lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | grep $lv2 +grep $UUID2 out | not grep $lv2 +grep $UUID3 out | not grep $lv2 + +vgremove -y $vg1 +vgs -o+uuid |tee out +not grep $UUID1 out +vgs --foreign -o+uuid |tee out +grep $UUID2 out +grep $UUID3 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" +aux wipefs_a "$dev4" + +# e. 2 local, 0 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +# diff lvname to prevent clash in vgchange -ay +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux enable_dev "$dev1" + +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +not vgs --foreign -o+uuid $vg1 |tee out +not grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | grep active +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | not grep active +grep $UUID2 out | not grep active +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 +grep $UUID2 out | not grep $lv2 + +not vgremove $vg1 +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +vgremove -y -S vg_uuid=$UUID1 +vgs -o+uuid |tee out +not grep $UUID1 out +grep $UUID2 out +vgremove -y -S vg_uuid=$UUID2 +vgs -o+uuid |tee out +not grep $UUID1 out +not grep $UUID2 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + +# f. 2 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +# diff lvname to prevent clash in vgchange -ay +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n $lv1 -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" + +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +not group $UUID3 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +not vgs --foreign -o+uuid $vg1 |tee out +not grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | grep active +grep $UUID3 out | not grep active +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | not grep active +grep $UUID2 out | not grep active +grep $UUID3 out | not grep active +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 +grep $UUID2 out | not grep $lv2 +grep $UUID3 out | not grep $lv2 + +not vgremove $vg1 +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgremove -y -S vg_uuid=$UUID1 +vgs --foreign -o+uuid |tee out +not grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgremove -y -S vg_uuid=$UUID2 +vgs --foreign -o+uuid |tee out +not grep $UUID1 out +not grep $UUID2 out +grep $UUID3 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" +aux wipefs_a "$dev4" + +# g. 2 local, 2 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +# diff lvname to prevent clash in vgchange -ay +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n $lv1 -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev3" +vgcreate $vg1 "$dev4" +lvcreate -n $lv1 -l1 -an $vg1 +UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" +aux enable_dev "$dev3" + +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +not group $UUID3 out +not group $UUID4 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +grep $UUID4 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +not vgs --foreign -o+uuid $vg1 |tee out +not grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | grep active +grep $UUID3 out | not grep active +grep $UUID4 out | not grep active +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | not grep active +grep $UUID2 out | not grep active +grep $UUID3 out | not grep active +grep $UUID4 out | not grep active +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 +grep $UUID2 out | not grep $lv2 +grep $UUID3 out | not grep $lv2 +grep $UUID4 out | not grep $lv2 + +not vgremove $vg1 +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +grep $UUID4 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" +aux wipefs_a "$dev4" +aux wipefs_a "$dev5" + +# h. 3 local, 3 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +# diff lvname to prevent clash in vgchange -ay +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +# diff lvname to prevent clash in vgchange -ay +lvcreate -n ${lv1}_bb -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev3" +vgcreate $vg1 "$dev4" +lvcreate -n $lv1 -l1 -an $vg1 +UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev4" +vgcreate $vg1 "$dev5" +lvcreate -n $lv1 -l1 -an $vg1 +UUID5=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux disable_dev "$dev5" +vgcreate $vg1 "$dev6" +lvcreate -n $lv1 -l1 -an $vg1 +UUID6=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other3" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" +aux enable_dev "$dev3" +aux enable_dev "$dev4" +aux enable_dev "$dev5" + +vgs -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not group $UUID4 out +not group $UUID5 out +not group $UUID6 out +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +grep $UUID4 out +grep $UUID5 out +grep $UUID6 out + +not vgs -o+uuid $vg1 |tee out +not grep $vg1 out +not vgs --foreign -o+uuid $vg1 |tee out +not grep $vg1 out + +vgchange -ay +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | grep active +grep $UUID2 out | grep active +grep $UUID3 out | grep active +grep $UUID4 out | not grep active +grep $UUID5 out | not grep active +grep $UUID6 out | not grep active +vgchange -an + +not vgchange -ay $vg1 +lvs --foreign -o vguuid,active |tee out +grep $UUID1 out | not grep active +grep $UUID2 out | not grep active +grep $UUID3 out | not grep active +grep $UUID4 out | not grep active +grep $UUID5 out | not grep active +grep $UUID6 out | not grep active +vgchange -an + +not lvcreate -l1 -an -n $lv2 $vg1 +lvs --foreign -o vguuid,name |tee out +grep $UUID1 out | not grep $lv2 +grep $UUID2 out | not grep $lv2 +grep $UUID3 out | not grep $lv2 +grep $UUID4 out | not grep $lv2 +grep $UUID5 out | not grep $lv2 +grep $UUID6 out | not grep $lv2 + +not vgremove $vg1 +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +grep $UUID4 out +grep $UUID5 out +grep $UUID6 out + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" +aux wipefs_a "$dev4" +aux wipefs_a "$dev5" +aux wipefs_a "$dev6" + +# vgreduce test with 1 local and 1 foreign vg. +# setup +vgcreate $vg1 "$dev1" "$dev7" +lvcreate -n $lv1 -l1 -an $vg1 "$dev1" +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +PV1UUID=$(pvs --noheading -o uuid "$dev1") +PV7UUID=$(pvs --noheading -o uuid "$dev7") +aux disable_dev "$dev1" +aux disable_dev "$dev7" +vgcreate $vg1 "$dev2" +PV2UUID=$(pvs --noheading -o uuid "$dev2") +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev7" + +vgs --foreign -o+uuid |tee out +grep $vg1 out +grep $UUID1 out +grep $UUID2 out +pvs --foreign -o+uuid |tee out +grep $PV1UUID out +grep $PV7UUID out +grep $PV2UUID out + +vgreduce $vg1 "$dev7" + +pvs --foreign -o+uuid |tee out +grep $PV1UUID out +grep $PV7UUID out +grep $PV2UUID out + +grep $PV7UUID out >out2 +not grep $vg1 out2 + +vgremove -ff $vg1 + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev7" diff --git a/test/shell/duplicate-vgrename.sh b/test/shell/duplicate-vgrename.sh new file mode 100644 index 0000000..8628220 --- /dev/null +++ b/test/shell/duplicate-vgrename.sh @@ -0,0 +1,319 @@ +#!/usr/bin/env bash + +# Copyright (C) 2008-2013 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. + +SKIP_WITH_LVMLOCKD=1 +SKIP_WITH_LVMPOLLD=1 + +. lib/inittest + +aux prepare_devs 4 + +# a. 0 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 + +not vgrename $vg1 $vg2 +vgs --foreign -o+uuid |tee out +grep $UUID1 out +not vgrename $UUID1 $vg2 +vgs --foreign -o+uuid |tee out +grep $UUID1 out + +lvs --foreign + +aux wipefs_a "$dev1" + +# b. 0 local, 2 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux enable_dev "$dev1" + +not vgrename $vg1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +not grep $vg2 out +grep $UUID1 out +grep $UUID2 out +not vgrename $UUID1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +not grep $vg2 out +grep $UUID1 out +grep $UUID2 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" + +# c. 1 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux enable_dev "$dev1" + +vgrename $vg1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +not vgrename $vg2 $vg1 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" + +# d. 1 local, 2 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n $lv1 -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n $lv1 -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other2" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" + +vgrename $vg1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $vg2 $vg1 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + +# e. 2 local, 0 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux enable_dev "$dev1" + +not vgrename $vg1 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +not grep $vg2 out +grep $UUID1 out +grep $UUID2 out +vgrename $UUID1 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +not vgrename $UUID2 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" + +# f. 2 local, 1 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n $lv1 -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +vgchange -y --systemid "other" $vg1 +aux enable_dev "$dev1" +aux enable_dev "$dev2" +lvs --foreign + +not vgrename $vg1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +not grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgrename $UUID1 $vg2 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgrename $vg1 $vg3 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $vg2 $vg1 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $vg2 $vg3 +vgs --foreign -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + +# g. 3 local, 0 foreign +# setup +vgcreate $vg1 "$dev1" +lvcreate -n $lv1 -l1 -an $vg1 +UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev1" +vgcreate $vg1 "$dev2" +lvcreate -n ${lv1}_b -l1 -an $vg1 +UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux disable_dev "$dev2" +vgcreate $vg1 "$dev3" +lvcreate -n ${lv1}_c -l1 -an $vg1 +UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs) +aux enable_dev "$dev1" +aux enable_dev "$dev2" + +not vgrename $vg1 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +not grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgrename $UUID1 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $vg1 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $vg1 $vg3 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +not grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +not vgrename $UUID2 $vg2 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +not grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out +vgrename $UUID2 $vg3 +vgs -o+uuid |tee out +lvs --foreign +grep $vg1 out +grep $vg2 out +grep $vg3 out +grep $UUID1 out +grep $UUID2 out +grep $UUID3 out + +lvs --foreign + +aux wipefs_a "$dev1" +aux wipefs_a "$dev2" +aux wipefs_a "$dev3" + diff --git a/test/shell/integrity-dmeventd.sh b/test/shell/integrity-dmeventd.sh index 58899ca..ed2436a 100644 --- a/test/shell/integrity-dmeventd.sh +++ b/test/shell/integrity-dmeventd.sh @@ -22,9 +22,9 @@ mkdir -p $mnt aux prepare_devs 6 64 -for i in `seq 1 16384`; do echo -n "A" >> fileA; done -for i in `seq 1 16384`; do echo -n "B" >> fileB; done -for i in `seq 1 16384`; do echo -n "C" >> fileC; done +printf "%0.sA" {1..16384} >> fileA +printf "%0.sB" {1..16384} >> fileB +printf "%0.sC" {1..16384} >> fileC # generate random data dd if=/dev/urandom of=randA bs=512K count=2 diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh index 0c36e4d..7a333c1 100644 --- a/test/shell/integrity-large.sh +++ b/test/shell/integrity-large.sh @@ -25,9 +25,9 @@ mkdir -p $mnt # raid1 LV needs to be extended to 512MB to test imeta being exended aux prepare_devs 4 600 -for i in `seq 1 16384`; do echo -n "A" >> fileA; done -for i in `seq 1 16384`; do echo -n "B" >> fileB; done -for i in `seq 1 16384`; do echo -n "C" >> fileC; done +printf "%0.sA" {1..16384} >> fileA +printf "%0.sB" {1..16384} >> fileB +printf "%0.sC" {1..16384} >> fileC # generate random data dd if=/dev/urandom of=randA bs=512K count=2 diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh index 73b0a67..a176f18 100644 --- a/test/shell/integrity-misc.sh +++ b/test/shell/integrity-misc.sh @@ -22,9 +22,9 @@ mkdir -p $mnt aux prepare_devs 5 64 -for i in `seq 1 16384`; do echo -n "A" >> fileA; done -for i in `seq 1 16384`; do echo -n "B" >> fileB; done -for i in `seq 1 16384`; do echo -n "C" >> fileC; done +printf "%0.sA" {1..16384} >> fileA +printf "%0.sB" {1..16384} >> fileB +printf "%0.sC" {1..16384} >> fileC # generate random data dd if=/dev/urandom of=randA bs=512K count=2 diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh index 7e4f2cb..6baccf0 100644 --- a/test/shell/integrity.sh +++ b/test/shell/integrity.sh @@ -23,9 +23,9 @@ mkdir -p $mnt aux prepare_devs 5 64 -for i in `seq 1 16384`; do echo -n "A" >> fileA; done -for i in `seq 1 16384`; do echo -n "B" >> fileB; done -for i in `seq 1 16384`; do echo -n "C" >> fileC; done +printf "%0.sA" {1..16384} >> fileA +printf "%0.sB" {1..16384} >> fileB +printf "%0.sC" {1..16384} >> fileC # generate random data dd if=/dev/urandom of=randA bs=512K count=2 diff --git a/test/shell/process-each-duplicate-vgnames.sh b/test/shell/process-each-duplicate-vgnames.sh deleted file mode 100644 index a59c3bd..0000000 --- a/test/shell/process-each-duplicate-vgnames.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2008-2013 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. - -test_description='Test vgs with duplicate vg names' -SKIP_WITH_LVMLOCKD=1 -SKIP_WITH_LVMPOLLD=1 - -. lib/inittest - -aux prepare_devs 2 - -pvcreate "$dev1" -pvcreate "$dev2" - -aux disable_dev "$dev1" "$dev2" - -aux enable_dev "$dev1" -vgcreate $vg1 "$dev1" -UUID1=$(vgs --noheading -o vg_uuid $vg1) -aux disable_dev "$dev1" - -aux enable_dev "$dev2" -vgcreate $vg1 "$dev2" -UUID2=$(vgs --noheading -o vg_uuid $vg1) - -aux enable_dev "$dev1" -pvscan --cache "$dev1" -pvs "$dev1" -pvs "$dev2" - -vgs -o+vg_uuid | tee err -grep $UUID1 err -grep $UUID2 err - -# should we specify and test which should be displayed? -# vgs --noheading -o vg_uuid $vg1 >err -# grep $UUID1 err - -aux disable_dev "$dev2" -vgs -o+vg_uuid | tee err -grep $UUID1 err -not grep $UUID2 err -aux enable_dev "$dev2" -pvscan --cache "$dev2" - -aux disable_dev "$dev1" -vgs -o+vg_uuid | tee err -grep $UUID2 err -not grep $UUID1 err -aux enable_dev "$dev1" diff --git a/test/shell/thin-foreign-repair.sh b/test/shell/thin-foreign-repair.sh index 147a9a0..8b4018e 100644 --- a/test/shell/thin-foreign-repair.sh +++ b/test/shell/thin-foreign-repair.sh @@ -56,7 +56,9 @@ dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0" mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN" -dmsetup remove "$THIN" +aux udev_wait + +dmsetup remove "$THIN" || { sleep .5 ; dmsetup remove "$THIN" } lvchange -an $vg/pool diff --git a/tools/command.c b/tools/command.c index 50791b1..511dda1 100644 --- a/tools/command.c +++ b/tools/command.c @@ -2319,7 +2319,8 @@ static void _print_val_man(struct command_name *cname, int opt_enum, int val_enu } if (strchr(str, '|')) { - line = strdup(str); + if (!(line = strdup(str))) + return; _split_line(line, &line_argc, line_argv, '|'); for (i = 0; i < line_argc; i++) { if (i) @@ -3606,9 +3607,12 @@ int main(int argc, char *argv[]) goto out_free; } - if (optind < argc) - cmdname = strdup(argv[optind++]); - else { + if (optind < argc) { + if (!(cmdname = strdup(argv[optind++]))) { + log_error("Out of memory."); + goto out_free; + } + } else { log_error("Missing command name."); goto out_free; } diff --git a/tools/lvconvert.c b/tools/lvconvert.c index e969b44..cf93538 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -5589,7 +5589,8 @@ static struct logical_volume *_lv_writecache_create(struct cmd_context *cmd, memcpy(&seg->writecache_settings, settings, sizeof(struct writecache_settings)); - add_seg_to_segs_using_this_lv(lv_fast, seg); + if (!add_seg_to_segs_using_this_lv(lv_fast, seg)) + return_NULL; return lv_wcorig; } diff --git a/tools/pvck.c b/tools/pvck.c index 71bfc1b..a0f567e 100644 --- a/tools/pvck.c +++ b/tools/pvck.c @@ -3065,11 +3065,9 @@ int pvck(struct cmd_context *cmd, int argc, char **argv) label_scan_setup_bcache(); - if (arg_is_set(cmd, dump_ARG)) { + if ((dump = arg_str_value(cmd, dump_ARG, NULL))) { cmd->use_hints = 0; - dump = arg_str_value(cmd, dump_ARG, NULL); - if (!strcmp(dump, "metadata")) ret = _dump_metadata(cmd, dump, &set, labelsector, dev, def, PRINT_CURRENT, 0); @@ -3096,11 +3094,9 @@ int pvck(struct cmd_context *cmd, int argc, char **argv) return ECMD_PROCESSED; } - if (arg_is_set(cmd, repairtype_ARG)) { + if ((repair = arg_str_value(cmd, repairtype_ARG, NULL))) { cmd->use_hints = 0; - repair = arg_str_value(cmd, repairtype_ARG, NULL); - if (!strcmp(repair, "label_header")) ret = _repair_label_header(cmd, repair, &set, labelsector, dev); diff --git a/tools/pvscan.c b/tools/pvscan.c index 1bf543c..4d811da 100644 --- a/tools/pvscan.c +++ b/tools/pvscan.c @@ -582,7 +582,7 @@ static int _online_pvscan_single(struct metadata_area *mda, void *baton) if (mda_is_ignored(mda)) return 1; - vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL); + vg = mda->ops->vg_read(b->cmd, b->fid, "", mda, NULL, NULL); if (!vg) { /* * Many or most cases of bad metadata would be found in diff --git a/tools/toollib.c b/tools/toollib.c index 96d0d6d..89b6374 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -1853,8 +1853,6 @@ static int _resolve_duplicate_vgnames(struct cmd_context *cmd, if (lvmcache_vg_is_foreign(cmd, vgnl->vg_name, vgnl->vgid)) { if (!id_write_format((const struct id*)vgnl->vgid, uuid, sizeof(uuid))) stack; - log_warn("WARNING: Ignoring foreign VG with matching name %s UUID %s.", - vgnl->vg_name, uuid); dm_list_del(&vgnl->list); } else { found++; diff --git a/tools/vgchange.c b/tools/vgchange.c index a10bf11..58c8ddc 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -991,8 +991,13 @@ static int _vgchange_locktype_single(struct cmd_context *cmd, const char *vg_nam * deactivate it. */ if (vg->lock_type && !strcmp(vg->lock_type, "sanlock") && - (cmd->command->command_enum == vgchange_locktype_CMD)) - deactivate_lv(cmd, vg->sanlock_lv); + (cmd->command->command_enum == vgchange_locktype_CMD)) { + if (!deactivate_lv(cmd, vg->sanlock_lv)) { + log_error("Failed to deativate %s.", + display_lvname(vg->sanlock_lv)); + return ECMD_FAILED; + } + } log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name); diff --git a/tools/vgimportclone.c b/tools/vgimportclone.c index be01861..ee1c28f 100644 --- a/tools/vgimportclone.c +++ b/tools/vgimportclone.c @@ -315,6 +315,8 @@ retry_name: goto_out; log_debug("Using new VG name %s.", vp.new_vgname); + lvmcache_destroy(cmd, 1, 0); + /* * Create a device filter so that we are only working with the devices * in arg_import. With the original devs hidden (that arg_import were @@ -325,7 +327,7 @@ retry_name: init_internal_filtering(1); dm_list_iterate_items(vd, &vp.arg_import) internal_filter_allow(cmd->mem, vd->dev); - lvmcache_destroy(cmd, 1, 0); + refresh_filters(cmd); log_debug("Changing VG %s to %s.", vp.old_vgname, vp.new_vgname); diff --git a/tools/vgmerge.c b/tools/vgmerge.c index 903504c..895018a 100644 --- a/tools/vgmerge.c +++ b/tools/vgmerge.c @@ -21,10 +21,8 @@ static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd, struct volume_group *vg; log_verbose("Checking for volume group \"%s\"", vg_name); vg = vg_read_for_update(cmd, vg_name, NULL, 0, 0); - if (vg_read_error(vg)) { - release_vg(vg); + if (!vg) return NULL; - } if (vg_is_shared(vg)) { log_error("vgmerge not allowed for lock_type %s", vg->lock_type); diff --git a/tools/vgrename.c b/tools/vgrename.c index 8b76d0b..f442f73 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -183,7 +183,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) vg_name_new = skip_dev_dir(cmd, argv[1], NULL); if (!validate_vg_rename_params(cmd, vg_name_old, vg_name_new)) - return_0; + return_ECMD_FAILED; if (!(vp.vg_name_old = dm_pool_strdup(cmd->mem, vg_name_old))) return_ECMD_FAILED; diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 3dc19ec..1a422e6 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -691,7 +691,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0, 0); - if (vg_read_error(vg_to)) { + if (!vg_to) { log_error("Volume group \"%s\" became inconsistent: " "please fix manually", vg_name_to); goto bad; -- 1.8.3.1