mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
Add infrastructure for queriying for remote locks.
Current code, when need to ensure that volume is not active on remote node, it need to try to exclusive activate volume. Patch adds simple clvmd command which queries all nodes for lock for given resource. The lock type is returned in reply in text. (But code currently uses CR and EX modes only.)
This commit is contained in:
parent
d00e023894
commit
ba856910e0
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user