]> sourceware.org Git - lvm2.git/commitdiff
Allow snapshots in a cluster as long as they are exclusively
authorJonathan Earl Brassow <jbrassow@redhat.com>
Fri, 4 Feb 2011 20:30:17 +0000 (20:30 +0000)
committerJonathan Earl Brassow <jbrassow@redhat.com>
Fri, 4 Feb 2011 20:30:17 +0000 (20:30 +0000)
activated.

In order to achieve this, we need to be able to query whether
the origin is active exclusively (a condition of being able to
add an exclusive snapshot).

Once we are able to query the exclusive activation of an LV, we
can safely create/activate the snapshot.

A change to 'hold_lock' was also made so that a request to aquire
a WRITE lock did not replace an EX lock, which is already a form
of write lock.

WHATS_NEW
daemons/clvmd/lvm-functions.c
lib/activate/activate.c
lib/activate/activate.h
lib/activate/dev_manager.c
lib/locking/locking.c
lib/locking/locking.h
lib/metadata/lv_manip.c
tools/vgchange.c

index 54f05f06854f643ee8f2e9a90101988d69c1a822..a43433f03fcd3982449e820898acb4daa5596dd8 100644 (file)
--- 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.
index 1fa234837ea29d2ae0fb92c5a8b0af6ef21d6167..81e8b884f39e0c72b99ea873b4d60ad305154432 100644 (file)
@@ -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 */
index d8f31bab1575a893d9dca354aa205387d301d61b..9edb0114ff2bda8a6fb389ddec69bffbb4d440a7 100644 (file)
@@ -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
index 2bc73dd81a3fd4b566bda15a4997ac6646dcd3ae..c054c6db736ed7118e30235cc20667237d03b405 100644 (file)
@@ -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);
index 1fbefc4edc90c7b27a56e65ad6ce435785a2b396..b485404817172f5eac403bb888359a74b67c7dce 100644 (file)
@@ -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"))
index 645f25d5709a9b9749a45e4c6d3cb537b2a00041..520b25eebbfeba7826ae219afe63f42761d244f3 100644 (file)
@@ -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;
 }
index 51a7198c15b513309034d5db3c542023a8a510b7..f30a76ce762fc24936aff5f8a30cf4c56d4a02a9 100644 (file)
@@ -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:
index f6bb68c27b2642dde56e0d455f97db9f83c4d32d..eb2a3e4a3bc652801d30b819d190e32e6ebaeb42 100644 (file)
@@ -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;
+                       }
                }
        }
 
index f2d399c4e27e81ea6c2c2dd197fffa1861e16161..4266d63339a469cf7aefa93e30d29eed8eb41dd9 100644 (file)
@@ -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) {
This page took 0.050386 seconds and 5 git commands to generate.