From c054e7cc564afaab3cc215834d3c36ef082181a6 Mon Sep 17 00:00:00 2001 From: Jonathan Earl Brassow Date: Fri, 18 Feb 2011 00:36:04 +0000 Subject: [PATCH] Fix for bug 677739: removing final exclusive cmirror snapshot, results in clvmd deadlock When a logical volume is activated exclusively in a cluster, the local (non-cluster-aware) target is used. However, when creating a snapshot on the exclusive LV, the resulting suspend/resume fails to load the appropriate device-mapper table - instead loading the cluster-aware target. This patch adds an 'exclusive' parameter to the pertinent resume functions to allow for the right target type to be loaded. --- WHATS_NEW | 1 + daemons/clvmd/lvm-functions.c | 6 ++++-- lib/activate/activate.c | 27 +++++++++++++++++++++++---- lib/activate/activate.h | 3 ++- lib/locking/file_locking.c | 2 +- lib/locking/no_locking.c | 2 +- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index aff09b666..ba89ece20 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,6 @@ Version 2.02.85 - =================================== + Fix to make resuming exclusive cluster mirror use local target type. Version 2.02.84 - 9th February 2011 =================================== diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c index 81e8b884f..b5a0e4ec6 100644 --- a/daemons/clvmd/lvm-functions.c +++ b/daemons/clvmd/lvm-functions.c @@ -399,7 +399,7 @@ error: /* Resume the LV if it was active */ static int do_resume_lv(char *resource, unsigned char lock_flags) { - int oldmode; + int oldmode, origin_only, exclusive; /* Is it open ? */ oldmode = get_current_lock(resource); @@ -407,8 +407,10 @@ static int do_resume_lv(char *resource, unsigned char lock_flags) DEBUGLOG("do_resume_lv, lock not already held\n"); return 0; /* We don't need to do anything */ } + origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0; + exclusive = (oldmode == LCK_EXCL) ? 1 : 0; - if (!lv_resume_if_active(cmd, resource, (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0)) + if (!lv_resume_if_active(cmd, resource, origin_only, exclusive)) return EIO; return 0; diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 9edb0114f..cdd499d07 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -1156,8 +1156,18 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s) } ***********/ + /* + * _lv_resume + * @cmd + * @lvid_s + * @origin_only + * @exclusive: This parameter only has an affect in cluster-context. + * It forces local target type to be used (instead of + * cluster-aware type). + * @error_if_not_active + */ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s, - unsigned origin_only, + unsigned origin_only, unsigned exclusive, int error_if_not_active) { struct logical_volume *lv; @@ -1189,6 +1199,14 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s, goto out; } + /* + * When targets are activated exclusively in a cluster, the + * non-clustered target should be used. This only happens + * if ACTIVATE_EXCL is set in lv->status. + */ + if (exclusive) + lv->status |= ACTIVATE_EXCL; + if (!_lv_activate_lv(lv, origin_only)) goto_out; @@ -1206,14 +1224,15 @@ out: } /* Returns success if the device is not active */ -int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only) +int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, + unsigned origin_only, unsigned exclusive) { - return _lv_resume(cmd, lvid_s, origin_only, 0); + return _lv_resume(cmd, lvid_s, origin_only, exclusive, 0); } int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only) { - return _lv_resume(cmd, lvid_s, origin_only, 1); + return _lv_resume(cmd, lvid_s, origin_only, 0, 1); } static int _lv_has_open_snapshots(struct logical_volume *lv) diff --git a/lib/activate/activate.h b/lib/activate/activate.h index c054c6db7..53ab19262 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -56,7 +56,8 @@ void activation_exit(void); /* int lv_suspend(struct cmd_context *cmd, const char *lvid_s); */ int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); int lv_resume(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); -int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, unsigned origin_only); +int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s, + unsigned origin_only, unsigned exclusive); int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive); int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive); diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c index 68b0420b8..95883b919 100644 --- a/lib/locking/file_locking.c +++ b/lib/locking/file_locking.c @@ -293,7 +293,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource, switch (flags & LCK_TYPE_MASK) { case LCK_UNLOCK: log_very_verbose("Unlocking LV %s%s", resource, origin_only ? " without snapshots" : ""); - if (!lv_resume_if_active(cmd, resource, origin_only)) + if (!lv_resume_if_active(cmd, resource, origin_only, 0)) return 0; break; case LCK_NULL: diff --git a/lib/locking/no_locking.c b/lib/locking/no_locking.c index 3ad0d38b2..65ac29fb0 100644 --- a/lib/locking/no_locking.c +++ b/lib/locking/no_locking.c @@ -46,7 +46,7 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource, case LCK_NULL: return lv_deactivate(cmd, resource); case LCK_UNLOCK: - return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0); + return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0); case LCK_READ: return lv_activate_with_filter(cmd, resource, 0); case LCK_WRITE: