summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WHATS_NEW1
-rw-r--r--daemons/clvmd/lvm-functions.c14
-rw-r--r--lib/activate/activate.c103
-rw-r--r--lib/activate/activate.h2
-rw-r--r--lib/activate/dev_manager.c4
-rw-r--r--lib/locking/locking.c5
-rw-r--r--lib/locking/locking.h2
-rw-r--r--lib/metadata/lv_manip.c12
-rw-r--r--tools/vgchange.c10
9 files changed, 122 insertions, 31 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index 54f05f06..a43433f0 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.83 -
===================================
+ Allow exclusive activation of snapshots in a cluster.
Add --addnodeonresume, --addnodeoncreate options for dmsetup create.
Use cluster-wide message to request device name sync.
Fix operation node stacking for consecutive dm ops.
diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
index 1fa23483..81e8b884 100644
--- a/daemons/clvmd/lvm-functions.c
+++ b/daemons/clvmd/lvm-functions.c
@@ -240,9 +240,17 @@ static int hold_lock(char *resource, int mode, int flags)
lvi = lookup_info(resource);
- if (lvi && lvi->lock_mode == mode) {
- DEBUGLOG("hold_lock, lock mode %d already held\n", mode);
- return 0;
+ if (lvi) {
+ if (lvi->lock_mode == mode) {
+ DEBUGLOG("hold_lock, lock mode %d already held\n",
+ mode);
+ return 0;
+ }
+ if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
+ DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
+ "ignoring LCK_WRITE request");
+ return 0;
+ }
}
/* Only allow explicit conversions */
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index d8f31bab..9edb0114 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -708,39 +708,108 @@ int lvs_in_vg_opened(const struct volume_group *vg)
}
/*
+ * _lv_is_active
+ * @lv: logical volume being queried
+ * @locally: set if active locally (when provided)
+ * @exclusive: set if active exclusively (when provided)
+ *
* Determine whether an LV is active locally or in a cluster.
- * Assumes vg lock held.
- * Returns:
- * 0 - not active locally or on any node in cluster
- * 1 - active either locally or some node in the cluster
+ * In addition to the return code which indicates whether or
+ * not the LV is active somewhere, two other values are set
+ * to yield more information about the status of the activation:
+ * return locally exclusively status
+ * ====== ======= =========== ======
+ * 0 0 0 not active
+ * 1 0 0 active remotely
+ * 1 0 1 exclusive remotely
+ * 1 1 0 active locally and possibly remotely
+ * 1 1 1 exclusive locally (or local && !cluster)
+ * The VG lock must be held to call this function.
+ *
+ * Returns: 0 or 1
*/
-int lv_is_active(struct logical_volume *lv)
+static int _lv_is_active(struct logical_volume *lv,
+ int *locally, int *exclusive)
{
- int ret;
+ int r, l, e; /* remote, local, and exclusive */
+
+ r = l = e = 0;
if (_lv_active(lv->vg->cmd, lv))
- return 1;
+ l = 1;
- if (!vg_is_clustered(lv->vg))
- return 0;
+ if (!vg_is_clustered(lv->vg)) {
+ e = 1; /* exclusive by definition */
+ goto out;
+ }
+
+ /* Active locally, and the caller doesn't care about exclusive */
+ if (l && !exclusive)
+ goto out;
- if ((ret = remote_lock_held(lv->lvid.s)) >= 0)
- return ret;
+ if ((r = remote_lock_held(lv->lvid.s, &e)) >= 0)
+ goto out;
/*
- * Old compatibility code if locking doesn't support lock query
- * FIXME: check status to not deactivate already activate device
+ * If lock query is not supported (due to interfacing with old
+ * code), then we cannot evaluate exclusivity properly.
+ *
+ * Old users of this function will never be affected by this,
+ * since they are only concerned about active vs. not active.
+ * New users of this function who specifically ask for 'exclusive'
+ * will be given an error message.
*/
+ if (l) {
+ if (exclusive)
+ log_error("Unable to determine exclusivity of %s",
+ lv->name);
+ goto out;
+ }
+
if (activate_lv_excl(lv->vg->cmd, lv)) {
if (!deactivate_lv(lv->vg->cmd, lv))
stack;
return 0;
}
- /*
- * Exclusive local activation failed so assume it is active elsewhere.
- */
- return 1;
+out:
+ if (locally)
+ *locally = l;
+ if (exclusive)
+ *exclusive = e;
+
+ log_very_verbose("%s/%s is %sactive%s%s",
+ lv->vg->name, lv->name,
+ (r || l) ? "" : "not ",
+ (exclusive && e) ? " exclusive" : "",
+ e ? (l ? " locally" : " remotely") : "");
+
+ return r || l;
+}
+
+int lv_is_active(struct logical_volume *lv)
+{
+ return _lv_is_active(lv, NULL, NULL);
+}
+
+/*
+int lv_is_active_locally(struct logical_volume *lv)
+{
+ int l;
+ return _lv_is_active(lv, &l, NULL) && l;
+}
+*/
+
+int lv_is_active_exclusive_locally(struct logical_volume *lv)
+{
+ int l, e;
+ return _lv_is_active(lv, &l, &e) && l && e;
+}
+
+int lv_is_active_exclusive_remotely(struct logical_volume *lv)
+{
+ int l, e;
+ return _lv_is_active(lv, &l, &e) && !l && e;
}
#ifdef DMEVENTD
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index 2bc73dd8..c054c6db 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -94,6 +94,8 @@ int lvs_in_vg_activated(struct volume_group *vg);
int lvs_in_vg_opened(const struct volume_group *vg);
int lv_is_active(struct logical_volume *lv);
+int lv_is_active_exclusive_locally(struct logical_volume *lv);
+int lv_is_active_exclusive_remotely(struct logical_volume *lv);
int lv_has_target_type(struct dm_pool *mem, struct logical_volume *lv,
const char *layer, const char *target_type);
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 1fbefc4e..b4854048 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -1390,10 +1390,6 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
/* If this is a snapshot origin, add real LV */
/* If this is a snapshot origin + merging snapshot, add cow + real LV */
} else if (lv_is_origin(seg->lv) && !layer) {
- if (vg_is_clustered(seg->lv->vg)) {
- log_error("Clustered snapshots are not yet supported");
- return 0;
- }
if (lv_is_merging_origin(seg->lv)) {
if (!_add_new_lv_to_dtree(dm, dtree,
find_merging_cow(seg->lv)->cow, "cow"))
diff --git a/lib/locking/locking.c b/lib/locking/locking.c
index 645f25d5..520b25ee 100644
--- a/lib/locking/locking.c
+++ b/lib/locking/locking.c
@@ -545,7 +545,7 @@ int locking_is_clustered(void)
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
}
-int remote_lock_held(const char *vol)
+int remote_lock_held(const char *vol, int *exclusive)
{
int mode = LCK_NULL;
@@ -563,5 +563,8 @@ int remote_lock_held(const char *vol)
return 1;
}
+ if (exclusive)
+ *exclusive = (mode == LCK_EXCL);
+
return mode == LCK_NULL ? 0 : 1;
}
diff --git a/lib/locking/locking.h b/lib/locking/locking.h
index 51a7198c..f30a76ce 100644
--- a/lib/locking/locking.h
+++ b/lib/locking/locking.h
@@ -25,7 +25,7 @@ void reset_locking(void);
int vg_write_lock_held(void);
int locking_is_clustered(void);
-int remote_lock_held(const char *vol);
+int remote_lock_held(const char *vol, int *exclusive);
/*
* LCK_VG:
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index f6bb68c2..eb2a3e4a 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -3164,11 +3164,6 @@ int lv_create_single(struct volume_group *vg,
"device-mapper kernel driver");
return 0;
}
- /* FIXME Allow exclusive activation. */
- if (vg_is_clustered(vg)) {
- log_error("Clustered snapshots are not yet supported.");
- return 0;
- }
/* Must zero cow */
status |= LVM_WRITE;
@@ -3217,6 +3212,13 @@ int lv_create_single(struct volume_group *vg,
return 0;
}
origin_active = info.exists;
+
+ if (vg_is_clustered(vg) &&
+ !lv_is_active_exclusive_locally(org)) {
+ log_error("%s must be active exclusively to"
+ " create snapshot", org->name);
+ return 0;
+ }
}
}
diff --git a/tools/vgchange.c b/tools/vgchange.c
index f2d399c4..4266d633 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -115,6 +115,16 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
((lv->status & PVMOVE) ))
continue;
+ /*
+ * If the LV is active exclusive remotely,
+ * then ignore it here
+ */
+ if (lv_is_active_exclusive_remotely(lv)) {
+ log_verbose("%s/%s is exclusively active on"
+ " a remote node", vg->name, lv->name);
+ continue;
+ }
+
expected_count++;
if (activate == CHANGE_AN) {