summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WHATS_NEW1
-rw-r--r--daemons/clvmd/clvm.h1
-rw-r--r--daemons/clvmd/clvmd-command.c11
-rw-r--r--daemons/clvmd/clvmd.c3
-rw-r--r--daemons/clvmd/lvm-functions.c20
-rw-r--r--daemons/clvmd/lvm-functions.h1
-rw-r--r--lib/activate/activate.c16
-rw-r--r--lib/locking/cluster_locking.c67
-rw-r--r--lib/locking/locking.c18
-rw-r--r--lib/locking/locking.h2
-rw-r--r--lib/locking/locking_types.h4
11 files changed, 127 insertions, 17 deletions
diff --git a/WHATS_NEW b/WHATS_NEW
index e4981738..ad804ea9 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.46 -
================================
+ Introduce CLVMD_CMD_LOCK_QUERY command for clvmd.
Use lvconvert --repair in dmeventd mirror DSO.
Fix pvmove to revert operation if temporary mirror creation fails.
Fix metadata export for VG with missing PVs.
diff --git a/daemons/clvmd/clvm.h b/daemons/clvmd/clvm.h
index 481d644a..04ab2835 100644
--- a/daemons/clvmd/clvm.h
+++ b/daemons/clvmd/clvm.h
@@ -62,6 +62,7 @@ static const char CLVMD_SOCKNAME[] = "\0clvmd";
/* Lock/Unlock commands */
#define CLVMD_CMD_LOCK_LV 50
#define CLVMD_CMD_LOCK_VG 51
+#define CLVMD_CMD_LOCK_QUERY 52
/* Misc functions */
#define CLVMD_CMD_REFRESH 40
diff --git a/daemons/clvmd/clvmd-command.c b/daemons/clvmd/clvmd-command.c
index dffff216..2266a2be 100644
--- a/daemons/clvmd/clvmd-command.c
+++ b/daemons/clvmd/clvmd-command.c
@@ -90,6 +90,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
int status = 0;
char *lockname;
+ const char *locktype;
struct utsname nodeinfo;
unsigned char lock_cmd;
unsigned char lock_flags;
@@ -144,6 +145,14 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
}
break;
+ case CLVMD_CMD_LOCK_QUERY:
+ lockname = &args[2];
+ if (buflen < 3)
+ return EIO;
+ if ((locktype = do_lock_query(lockname)))
+ *retlen = 1 + snprintf(*buf, buflen, "%s", locktype);
+ break;
+
case CLVMD_CMD_REFRESH:
do_refresh_cache();
break;
@@ -278,6 +287,7 @@ int do_pre_command(struct local_client *client)
case CLVMD_CMD_GET_CLUSTERNAME:
case CLVMD_CMD_SET_DEBUG:
case CLVMD_CMD_VG_BACKUP:
+ case CLVMD_CMD_LOCK_QUERY:
break;
default:
@@ -308,6 +318,7 @@ int do_post_command(struct local_client *client)
case CLVMD_CMD_LOCK_VG:
case CLVMD_CMD_VG_BACKUP:
+ case CLVMD_CMD_LOCK_QUERY:
/* Nothing to do here */
break;
diff --git a/daemons/clvmd/clvmd.c b/daemons/clvmd/clvmd.c
index 1738255a..b34d26ab 100644
--- a/daemons/clvmd/clvmd.c
+++ b/daemons/clvmd/clvmd.c
@@ -257,6 +257,9 @@ static const char *decode_cmd(unsigned char cmdl)
case CLVMD_CMD_UNLOCK:
command = "UNLOCK";
break;
+ case CLVMD_CMD_LOCK_QUERY:
+ command = "LOCK_QUERY";
+ break;
default:
command = "unknown";
break;
diff --git a/daemons/clvmd/lvm-functions.c b/daemons/clvmd/lvm-functions.c
index 7e2eb2d6..29e5e6cd 100644
--- a/daemons/clvmd/lvm-functions.c
+++ b/daemons/clvmd/lvm-functions.c
@@ -434,6 +434,26 @@ static int do_deactivate_lv(char *resource, unsigned char lock_flags)
return 0;
}
+const char *do_lock_query(char *resource)
+{
+ int mode;
+ const char *type = NULL;
+
+ mode = get_current_lock(resource);
+ switch (mode) {
+ case LKM_NLMODE: type = "NL"; break;
+ case LKM_CRMODE: type = "CR"; break;
+ case LKM_CWMODE: type = "CW"; break;
+ case LKM_PRMODE: type = "PR"; break;
+ case LKM_PWMODE: type = "PW"; break;
+ case LKM_EXMODE: type = "EX"; break;
+ }
+
+ DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "?");
+
+ return type;
+}
+
/* This is the LOCK_LV part that happens on all nodes in the cluster -
it is responsible for the interaction with device-mapper and LVM */
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
diff --git a/daemons/clvmd/lvm-functions.h b/daemons/clvmd/lvm-functions.h
index 0b6866af..5da104c0 100644
--- a/daemons/clvmd/lvm-functions.h
+++ b/daemons/clvmd/lvm-functions.h
@@ -22,6 +22,7 @@ extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
char *resource);
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
char *resource);
+extern const char *do_lock_query(char *resource);
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
char *resource);
extern int do_check_lvm1(const char *vgname);
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 34f979a8..d42f46e9 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -695,21 +695,7 @@ int lv_is_active(struct logical_volume *lv)
if (!vg_is_clustered(lv->vg))
return 0;
- /*
- * FIXME: Cluster does not report per-node LV activation status.
- * Currently the best we can do is try exclusive local activation.
- * If that succeeds, we know the LV is not active elsewhere in the
- * cluster.
- */
- if (activate_lv_excl(lv->vg->cmd, lv)) {
- deactivate_lv(lv->vg->cmd, lv);
- return 0;
- }
-
- /*
- * Exclusive local activation failed so assume it is active elsewhere.
- */
- return 1;
+ return remote_lock_held(lv->lvid.s);
}
/*
diff --git a/lib/locking/cluster_locking.c b/lib/locking/cluster_locking.c
index 1f0e841d..25a7d5ba 100644
--- a/lib/locking/cluster_locking.c
+++ b/lib/locking/cluster_locking.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -33,6 +33,7 @@
#ifndef CLUSTER_LOCKING_INTERNAL
int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags);
+int lock_resource_query(const char *resource, int *mode);
void locking_end(void);
int locking_init(int type, struct config_tree *cf, uint32_t *flags);
#endif
@@ -455,6 +456,69 @@ int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
return _lock_for_cluster(clvmd_cmd, flags, lockname);
}
+static int decode_lock_type(const char *response)
+{
+ if (!response)
+ return LCK_NULL;
+ else if (strcmp(response, "EX"))
+ return LCK_EXCL;
+ else if (strcmp(response, "CR"))
+ return LCK_READ;
+ else if (strcmp(response, "PR"))
+ return LCK_PREAD;
+
+ stack;
+ return 0;
+}
+
+#ifdef CLUSTER_LOCKING_INTERNAL
+static int _lock_resource_query(const char *resource, int *mode)
+#else
+int lock_resource_query(const char *resource, int *mode)
+#endif
+{
+ int i, status, len, num_responses, saved_errno;
+ const char *node = "";
+ char *args;
+ lvm_response_t *response = NULL;
+
+ saved_errno = errno;
+ len = strlen(resource) + 3;
+ args = alloca(len);
+ strcpy(args + 2, resource);
+
+ args[0] = 0;
+ args[1] = LCK_CLUSTER_VG;
+
+ status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len,
+ &response, &num_responses);
+ *mode = LCK_NULL;
+ for (i = 0; i < num_responses; i++) {
+ if (response[i].status == EHOSTDOWN)
+ continue;
+
+ if (!response[i].response[0])
+ continue;
+
+ /*
+ * All nodes should use CR, or exactly one node
+ * should held EX. (PR is obsolete)
+ * If two nodes node reports different locks,
+ * something is broken - just return more important mode.
+ */
+ if (decode_lock_type(response[i].response) > *mode)
+ *mode = decode_lock_type(response[i].response);
+
+ log_debug("Lock held for %s, node %s : %s", resource,
+ response[i].node, response[i].response);
+ }
+
+ _cluster_free_request(response, num_responses);
+ errno = saved_errno;
+
+ return status;
+}
+
#ifdef CLUSTER_LOCKING_INTERNAL
static void _locking_end(void)
#else
@@ -485,6 +549,7 @@ void reset_locking(void)
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
{
locking->lock_resource = _lock_resource;
+ locking->lock_resource_query = _lock_resource_query;
locking->fin_locking = _locking_end;
locking->reset_locking = _reset_locking;
locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
diff --git a/lib/locking/locking.c b/lib/locking/locking.c
index 37136ee5..d57726da 100644
--- a/lib/locking/locking.c
+++ b/lib/locking/locking.c
@@ -482,3 +482,21 @@ int locking_is_clustered(void)
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
}
+int remote_lock_held(const char *vol)
+{
+ int mode = LCK_NULL;
+
+ if (!locking_is_clustered())
+ return 0;
+
+ /*
+ * If an error occured, expect that volume is active
+ */
+ if (!_locking.lock_resource_query ||
+ !_locking.lock_resource_query(vol, &mode)) {
+ stack;
+ return 1;
+ }
+
+ return mode == LCK_NULL ? 0 : 1;
+}
diff --git a/lib/locking/locking.h b/lib/locking/locking.h
index ee7f5a12..57738a6e 100644
--- a/lib/locking/locking.h
+++ b/lib/locking/locking.h
@@ -25,6 +25,8 @@ void reset_locking(void);
int vg_write_lock_held(void);
int locking_is_clustered(void);
+int remote_lock_held(const char *vol);
+
/*
* LCK_VG:
* Lock/unlock on-disk volume group data.
diff --git a/lib/locking/locking_types.h b/lib/locking/locking_types.h
index f7836296..425a7722 100644
--- a/lib/locking/locking_types.h
+++ b/lib/locking/locking_types.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -18,6 +18,7 @@
typedef int (*lock_resource_fn) (struct cmd_context * cmd, const char *resource,
uint32_t flags);
+typedef int (*lock_resource_query_fn) (const char *resource, int *mode);
typedef void (*fin_lock_fn) (void);
typedef void (*reset_lock_fn) (void);
@@ -28,6 +29,7 @@ typedef void (*reset_lock_fn) (void);
struct locking_type {
uint32_t flags;
lock_resource_fn lock_resource;
+ lock_resource_query_fn lock_resource_query;
reset_lock_fn reset_locking;
fin_lock_fn fin_locking;