From 88a085c48551b811cf8532f7a0540062cc6e2d42 Mon Sep 17 00:00:00 2001 From: David Teigland Date: Thu, 31 Oct 2024 20:29:00 -0500 Subject: [PATCH] lvmlockd: optimize new lv lease search When converting a VG to locktype sanlock, a new lease is allocated for each existing lv. Finding a new lease location involved searching the lvmlock LV from the start for an unused location, which would be very slow with many LVs. Improve this by starting each search from the last used location. --- daemons/lvmlockd/lvmlockd-core.c | 6 ++++- daemons/lvmlockd/lvmlockd-internal.h | 5 ++-- daemons/lvmlockd/lvmlockd-sanlock.c | 34 +++++++++++++++++----------- lib/locking/lvmlockd.c | 8 +++++-- lib/locking/lvmlockd.h | 2 +- lib/metadata/metadata.c | 4 +++- tools/lvconvert.c | 2 +- 7 files changed, 40 insertions(+), 21 deletions(-) diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c index 560491661..699179f39 100644 --- a/daemons/lvmlockd/lvmlockd-core.c +++ b/daemons/lvmlockd/lvmlockd-core.c @@ -3649,7 +3649,7 @@ static int work_init_lv(struct action *act) if (lm_type == LD_LM_SANLOCK) { /* ls is NULL if the lockspace is not started, which happens for vgchange --locktype sanlock. */ - rv = lm_init_lv_sanlock(ls, ls_name, act->vg_name, act->lv_uuid, vg_args, lv_args); + rv = lm_init_lv_sanlock(ls, ls_name, act->vg_name, act->lv_uuid, vg_args, lv_args, act->prev_lv_args); memcpy(act->lv_args, lv_args, MAX_ARGS); return rv; @@ -5019,6 +5019,10 @@ static void client_recv_action(struct client *cl) if (str && strcmp(str, "none")) strncpy(act->lv_args, str, MAX_ARGS); + str = daemon_request_str(req, "prev_lv_args", NULL); + if (str && strcmp(str, "none")) + strncpy(act->prev_lv_args, str, MAX_ARGS); + /* start_vg will include lvmlocal.conf local/host_id here */ val = daemon_request_int(req, "host_id", 0); if (val) diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h index 99267d6e2..eb0d4415a 100644 --- a/daemons/lvmlockd/lvmlockd-internal.h +++ b/daemons/lvmlockd/lvmlockd-internal.h @@ -150,6 +150,7 @@ struct action { char lv_uuid[MAX_NAME+1]; char vg_args[MAX_ARGS+1]; char lv_args[MAX_ARGS+1]; + char prev_lv_args[MAX_ARGS+1]; char vg_sysid[MAX_NAME+1]; struct pvs pvs; /* PV list for idm */ }; @@ -507,7 +508,7 @@ static inline int lm_refresh_lv_check_dlm(struct action *act) #ifdef LOCKDSANLOCK_SUPPORT int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args, int opt_align_mb); -int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args); +int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args); int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r); int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_prepare_lockspace_sanlock(struct lockspace *ls); @@ -542,7 +543,7 @@ static inline int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flag return -1; } -static inline int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args) +static inline int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args) { return -1; } diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c index ff4149b72..e97b0035d 100644 --- a/daemons/lvmlockd/lvmlockd-sanlock.c +++ b/daemons/lvmlockd/lvmlockd-sanlock.c @@ -773,7 +773,7 @@ int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_ar * can be saved in the lv's lock_args in the vg metadata. */ -int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args) +int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args, char *prev_args) { char disk_path[SANLK_PATH_LEN]; struct lm_sanlock *lms; @@ -781,11 +781,13 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char char lock_lv_name[MAX_ARGS+1]; char lock_args_version[MAX_VERSION+1]; uint64_t offset; + uint64_t prev_offset = 0; int sector_size; int align_size; int align_mb; uint32_t ss_flags; uint32_t rs_flags; + uint32_t tries = 1; int rv; memset(&rd, 0, sizeof(rd)); @@ -825,10 +827,7 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char offset = ls->free_lock_offset; } else { /* FIXME: optimize repeated init_lv for vgchange --locktype sanlock, - to avoid finding align_size/rs_flags/free_lock_offset each time. - Since the lockspace is not started, there's no ls struct to save - all these in between calls. We could have the command send back - the last offset it used, what about the other two? */ + to avoid finding align_size/rs_flags each time. */ rv = get_sizes_lockspace(disk_path, §or_size, &align_size, &align_mb, &ss_flags, &rs_flags); if (rv < 0) { @@ -837,8 +836,14 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char return rv; } - /* Starts searching from the start for every init_lv. */ - offset = align_size * LV_LOCK_BEGIN; + /* + * With a prev offset, start search after that. + * Without a prev offset, start search from the beginning. + */ + if (prev_args && !lock_lv_offset_from_args(prev_args, &prev_offset)) + offset = prev_offset + align_size; + else + offset = align_size * LV_LOCK_BEGIN; } strcpy_name_len(rd.rs.lockspace_name, ls_name, SANLK_NAME_LEN); @@ -878,8 +883,8 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char * indicating an uninitialized paxos structure on disk. */ if ((rv == SANLK_LEADER_MAGIC) || !strcmp(rd.rs.name, "#unused")) { - log_debug("S %s init_lv_san %s found unused area at %llu", - ls_name, lv_name, (unsigned long long)offset); + log_debug("S %s init_lv_san %s found unused area at %llu try %u", + ls_name, lv_name, (unsigned long long)offset, tries); strcpy_name_len(rd.rs.name, lv_name, SANLK_NAME_LEN); rd.rs.flags = rs_flags; @@ -896,6 +901,7 @@ int lm_init_lv_sanlock(struct lockspace *ls, char *ls_name, char *vg_name, char } offset += align_size; + tries++; } return rv; @@ -1293,6 +1299,7 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes) struct sanlk_resourced rd; uint64_t offset; uint64_t start_offset; + uint32_t tries = 0; int rv; int round = 0; @@ -1371,8 +1378,8 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes) * an invalid paxos structure on disk. */ if (rv == SANLK_LEADER_MAGIC) { - log_debug("S %s find_free_lock_san found empty area at %llu", - ls->name, (unsigned long long)offset); + log_debug("S %s find_free_lock_san found empty area at %llu try %u", + ls->name, (unsigned long long)offset, tries); ls->free_lock_offset = offset; return 0; } @@ -1384,12 +1391,13 @@ int lm_find_free_lock_sanlock(struct lockspace *ls, uint64_t lv_size_bytes) } if (!strcmp(rd.rs.name, "#unused")) { - log_debug("S %s find_free_lock_san found unused area at %llu", - ls->name, (unsigned long long)offset); + log_debug("S %s find_free_lock_san found unused area at %llu try %u", + ls->name, (unsigned long long)offset, tries); ls->free_lock_offset = offset; return 0; } + tries++; offset += lms->align_size; } diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index d92c37087..7e297d9cd 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -3073,6 +3073,7 @@ int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv, static int _init_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, struct id *lv_id, + const char *last_args, const char **lock_args_ret) { char lv_uuid[64] __attribute__((aligned(8))); @@ -3095,6 +3096,7 @@ static int _init_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg, "vg_name = %s", vg->name, "lv_name = %s", lv_name, "lv_uuid = %s", lv_uuid, + "prev_lv_args = %s", last_args ? last_args : "none", "vg_lock_type = %s", "sanlock", "vg_lock_args = %s", vg->lock_args, NULL); @@ -3181,7 +3183,9 @@ static int _free_lv(struct cmd_context *cmd, struct volume_group *vg, int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, - const char *lock_type, const char **lock_args) + const char *lock_type, + const char *last_args, + const char **lock_args) { if (!lock_type) return 1; @@ -3190,7 +3194,7 @@ int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, else if (!strcmp(lock_type, "idm")) *lock_args = "idm"; else if (!strcmp(lock_type, "sanlock")) - return _init_lv_sanlock(cmd, vg, lv->name, &lv->lvid.id[1], lock_args); + return _init_lv_sanlock(cmd, vg, lv->name, &lv->lvid.id[1], last_args, lock_args); return 1; } diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index 96ca2b296..c864c75e3 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -111,7 +111,7 @@ int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv, int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct lvcreate_params *lp); int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, - struct logical_volume *lv, const char *lock_type, const char **lock_args); + struct logical_volume *lv, const char *lock_type, const char *last_args, const char **lock_args); int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, struct id *lv_id, const char *lock_args); int lockd_free_lv_after_update(struct cmd_context *cmd, struct volume_group *vg, diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 9639b926b..511ebd8ae 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -2944,12 +2944,14 @@ int vg_write(struct volume_group *vg) log_debug("Writing metadata for VG %s.", vg->name); if (vg_is_shared(vg)) { + const char *last_args = NULL; dm_list_iterate_items(lvl, &vg->lvs) { if (lvl->lv->lock_args && !strcmp(lvl->lv->lock_args, "pending")) { - if (!lockd_init_lv_args(vg->cmd, vg, lvl->lv, vg->lock_type, &lvl->lv->lock_args)) { + if (!lockd_init_lv_args(vg->cmd, vg, lvl->lv, vg->lock_type, last_args, &lvl->lv->lock_args)) { log_error("Cannot allocate lock for new LV."); return 0; } + last_args = lvl->lv->lock_args; lvl->lv->new_lock_args = 1; } } diff --git a/tools/lvconvert.c b/tools/lvconvert.c index 60b93e89f..8dd8eea1b 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -3512,7 +3512,7 @@ static int _lvconvert_to_pool(struct cmd_context *cmd, metadata_lv->lock_args = NULL; if (to_thin) { - if (!lockd_init_lv_args(cmd, vg, pool_lv, vg->lock_type, &pool_lv->lock_args)) { + if (!lockd_init_lv_args(cmd, vg, pool_lv, vg->lock_type, NULL, &pool_lv->lock_args)) { log_error("Cannot allocate lock for new pool LV."); goto bad; }