xref: /netbsd-src/external/gpl2/lvm2/dist/lib/locking/cluster_locking.c (revision 7c604eea85b4f330dc75ffe65e947f4d73758aa0)
1*7c604eeaShaad /*	$NetBSD: cluster_locking.c,v 1.1.1.3 2009/12/02 00:26:24 haad Exp $	*/
256a34939Shaad 
356a34939Shaad /*
456a34939Shaad  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5*7c604eeaShaad  * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
656a34939Shaad  *
756a34939Shaad  * This file is part of LVM2.
856a34939Shaad  *
956a34939Shaad  * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad  * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad  * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad  *
1356a34939Shaad  * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad  * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1656a34939Shaad  */
1756a34939Shaad 
1856a34939Shaad /*
1956a34939Shaad  * Locking functions for LVM.
2056a34939Shaad  * The main purpose of this part of the library is to serialise LVM
2156a34939Shaad  * management operations across a cluster.
2256a34939Shaad  */
2356a34939Shaad 
2456a34939Shaad #include "lib.h"
2556a34939Shaad #include "clvm.h"
2656a34939Shaad #include "lvm-string.h"
2756a34939Shaad #include "locking.h"
2856a34939Shaad #include "locking_types.h"
29*7c604eeaShaad #include "toolcontext.h"
3056a34939Shaad 
3156a34939Shaad #include <assert.h>
3256a34939Shaad #include <stddef.h>
3356a34939Shaad #include <sys/socket.h>
3456a34939Shaad #include <sys/un.h>
3556a34939Shaad #include <unistd.h>
3656a34939Shaad 
3756a34939Shaad #ifndef CLUSTER_LOCKING_INTERNAL
3856a34939Shaad int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags);
39*7c604eeaShaad int query_resource(const char *resource, int *mode);
4056a34939Shaad void locking_end(void);
4156a34939Shaad int locking_init(int type, struct config_tree *cf, uint32_t *flags);
4256a34939Shaad #endif
4356a34939Shaad 
4456a34939Shaad typedef struct lvm_response {
4556a34939Shaad 	char node[255];
4656a34939Shaad 	char *response;
4756a34939Shaad 	int status;
4856a34939Shaad 	int len;
4956a34939Shaad } lvm_response_t;
5056a34939Shaad 
5156a34939Shaad /*
5256a34939Shaad  * This gets stuck at the start of memory we allocate so we
5356a34939Shaad  * can sanity-check it at deallocation time
5456a34939Shaad  */
5556a34939Shaad #define LVM_SIGNATURE 0x434C564D
5656a34939Shaad 
5756a34939Shaad /*
5856a34939Shaad  * NOTE: the LVMD uses the socket FD as the client ID, this means
5956a34939Shaad  * that any client that calls fork() will inherit the context of
6056a34939Shaad  * it's parent.
6156a34939Shaad  */
6256a34939Shaad static int _clvmd_sock = -1;
6356a34939Shaad 
6456a34939Shaad /* FIXME Install SIGPIPE handler? */
6556a34939Shaad 
6656a34939Shaad /* Open connection to the Cluster Manager daemon */
_open_local_sock(void)6756a34939Shaad static int _open_local_sock(void)
6856a34939Shaad {
6956a34939Shaad 	int local_socket;
7056a34939Shaad 	struct sockaddr_un sockaddr;
7156a34939Shaad 
7256a34939Shaad 	/* Open local socket */
7356a34939Shaad 	if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
7456a34939Shaad 		log_error("Local socket creation failed: %s", strerror(errno));
7556a34939Shaad 		return -1;
7656a34939Shaad 	}
7756a34939Shaad 
7856a34939Shaad 	memset(&sockaddr, 0, sizeof(sockaddr));
7956a34939Shaad 	memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
8056a34939Shaad 
8156a34939Shaad 	sockaddr.sun_family = AF_UNIX;
8256a34939Shaad 
8356a34939Shaad 	if (connect(local_socket,(struct sockaddr *) &sockaddr,
8456a34939Shaad 		    sizeof(sockaddr))) {
8556a34939Shaad 		int saved_errno = errno;
8656a34939Shaad 
8756a34939Shaad 		log_error("connect() failed on local socket: %s",
8856a34939Shaad 			  strerror(errno));
8956a34939Shaad 		if (close(local_socket))
9056a34939Shaad 			stack;
9156a34939Shaad 
9256a34939Shaad 		errno = saved_errno;
9356a34939Shaad 		return -1;
9456a34939Shaad 	}
9556a34939Shaad 
9656a34939Shaad 	return local_socket;
9756a34939Shaad }
9856a34939Shaad 
9956a34939Shaad /* Send a request and return the status */
_send_request(char * inbuf,int inlen,char ** retbuf)10056a34939Shaad static int _send_request(char *inbuf, int inlen, char **retbuf)
10156a34939Shaad {
10256a34939Shaad 	char outbuf[PIPE_BUF] __attribute((aligned(8)));
10356a34939Shaad 	struct clvm_header *outheader = (struct clvm_header *) outbuf;
10456a34939Shaad 	int len;
10556a34939Shaad 	int off;
10656a34939Shaad 	int buflen;
10756a34939Shaad 	int err;
10856a34939Shaad 
10956a34939Shaad 	/* Send it to CLVMD */
11056a34939Shaad  rewrite:
11156a34939Shaad 	if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
11256a34939Shaad 		if (err == -1 && errno == EINTR)
11356a34939Shaad 			goto rewrite;
11456a34939Shaad 		log_error("Error writing data to clvmd: %s", strerror(errno));
11556a34939Shaad 		return 0;
11656a34939Shaad 	}
11756a34939Shaad 
11856a34939Shaad 	/* Get the response */
11956a34939Shaad  reread:
12056a34939Shaad 	if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
12156a34939Shaad 		if (errno == EINTR)
12256a34939Shaad 			goto reread;
12356a34939Shaad 		log_error("Error reading data from clvmd: %s", strerror(errno));
12456a34939Shaad 		return 0;
12556a34939Shaad 	}
12656a34939Shaad 
12756a34939Shaad 	if (len == 0) {
12856a34939Shaad 		log_error("EOF reading CLVMD");
12956a34939Shaad 		errno = ENOTCONN;
13056a34939Shaad 		return 0;
13156a34939Shaad 	}
13256a34939Shaad 
13356a34939Shaad 	/* Allocate buffer */
13456a34939Shaad 	buflen = len + outheader->arglen;
13556a34939Shaad 	*retbuf = dm_malloc(buflen);
13656a34939Shaad 	if (!*retbuf) {
13756a34939Shaad 		errno = ENOMEM;
13856a34939Shaad 		return 0;
13956a34939Shaad 	}
14056a34939Shaad 
14156a34939Shaad 	/* Copy the header */
14256a34939Shaad 	memcpy(*retbuf, outbuf, len);
14356a34939Shaad 	outheader = (struct clvm_header *) *retbuf;
14456a34939Shaad 
14556a34939Shaad 	/* Read the returned values */
14656a34939Shaad 	off = 1;		/* we've already read the first byte */
14756a34939Shaad 	while (off <= outheader->arglen && len > 0) {
14856a34939Shaad 		len = read(_clvmd_sock, outheader->args + off,
14956a34939Shaad 			   buflen - off - offsetof(struct clvm_header, args));
15056a34939Shaad 		if (len > 0)
15156a34939Shaad 			off += len;
15256a34939Shaad 	}
15356a34939Shaad 
15456a34939Shaad 	/* Was it an error ? */
15556a34939Shaad 	if (outheader->status != 0) {
15656a34939Shaad 		errno = outheader->status;
15756a34939Shaad 
15856a34939Shaad 		/* Only return an error here if there are no node-specific
15956a34939Shaad 		   errors present in the message that might have more detail */
16056a34939Shaad 		if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
16156a34939Shaad 			log_error("cluster request failed: %s", strerror(errno));
16256a34939Shaad 			return 0;
16356a34939Shaad 		}
16456a34939Shaad 
16556a34939Shaad 	}
16656a34939Shaad 
16756a34939Shaad 	return 1;
16856a34939Shaad }
16956a34939Shaad 
17056a34939Shaad /* Build the structure header and parse-out wildcard node names */
171bec4d750Shaad /* FIXME: Cleanup implicit casts of clvmd_cmd (int, char, uint8_t, etc). */
_build_header(struct clvm_header * head,int clvmd_cmd,const char * node,int len)172bec4d750Shaad static void _build_header(struct clvm_header *head, int clvmd_cmd, const char *node,
17356a34939Shaad 			  int len)
17456a34939Shaad {
175bec4d750Shaad 	head->cmd = clvmd_cmd;
17656a34939Shaad 	head->status = 0;
17756a34939Shaad 	head->flags = 0;
17856a34939Shaad 	head->clientid = 0;
17956a34939Shaad 	head->arglen = len;
18056a34939Shaad 
18156a34939Shaad 	if (node) {
18256a34939Shaad 		/*
18356a34939Shaad 		 * Allow a couple of special node names:
18456a34939Shaad 		 * "*" for all nodes,
18556a34939Shaad 		 * "." for the local node only
18656a34939Shaad 		 */
18756a34939Shaad 		if (strcmp(node, "*") == 0) {
18856a34939Shaad 			head->node[0] = '\0';
18956a34939Shaad 		} else if (strcmp(node, ".") == 0) {
19056a34939Shaad 			head->node[0] = '\0';
19156a34939Shaad 			head->flags = CLVMD_FLAG_LOCAL;
19256a34939Shaad 		} else
19356a34939Shaad 			strcpy(head->node, node);
19456a34939Shaad 	} else
19556a34939Shaad 		head->node[0] = '\0';
19656a34939Shaad }
19756a34939Shaad 
19856a34939Shaad /*
19956a34939Shaad  * Send a message to a(or all) node(s) in the cluster and wait for replies
20056a34939Shaad  */
_cluster_request(char clvmd_cmd,const char * node,void * data,int len,lvm_response_t ** response,int * num)201bec4d750Shaad static int _cluster_request(char clvmd_cmd, const char *node, void *data, int len,
20256a34939Shaad 			   lvm_response_t ** response, int *num)
20356a34939Shaad {
20456a34939Shaad 	char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
20556a34939Shaad 	char *inptr;
20656a34939Shaad 	char *retbuf = NULL;
20756a34939Shaad 	int status;
20856a34939Shaad 	int i;
20956a34939Shaad 	int num_responses = 0;
21056a34939Shaad 	struct clvm_header *head = (struct clvm_header *) outbuf;
21156a34939Shaad 	lvm_response_t *rarray;
21256a34939Shaad 
21356a34939Shaad 	*num = 0;
21456a34939Shaad 
21556a34939Shaad 	if (_clvmd_sock == -1)
21656a34939Shaad 		_clvmd_sock = _open_local_sock();
21756a34939Shaad 
21856a34939Shaad 	if (_clvmd_sock == -1)
21956a34939Shaad 		return 0;
22056a34939Shaad 
221bec4d750Shaad 	_build_header(head, clvmd_cmd, node, len);
22256a34939Shaad 	memcpy(head->node + strlen(head->node) + 1, data, len);
22356a34939Shaad 
22456a34939Shaad 	status = _send_request(outbuf, sizeof(struct clvm_header) +
22556a34939Shaad 			      strlen(head->node) + len, &retbuf);
22656a34939Shaad 	if (!status)
22756a34939Shaad 		goto out;
22856a34939Shaad 
22956a34939Shaad 	/* Count the number of responses we got */
23056a34939Shaad 	head = (struct clvm_header *) retbuf;
23156a34939Shaad 	inptr = head->args;
23256a34939Shaad 	while (inptr[0]) {
23356a34939Shaad 		num_responses++;
23456a34939Shaad 		inptr += strlen(inptr) + 1;
23556a34939Shaad 		inptr += sizeof(int);
23656a34939Shaad 		inptr += strlen(inptr) + 1;
23756a34939Shaad 	}
23856a34939Shaad 
23956a34939Shaad 	/*
24056a34939Shaad 	 * Allocate response array.
24156a34939Shaad 	 * With an extra pair of INTs on the front to sanity
24256a34939Shaad 	 * check the pointer when we are given it back to free
24356a34939Shaad 	 */
24456a34939Shaad 	*response = dm_malloc(sizeof(lvm_response_t) * num_responses);
24556a34939Shaad 	if (!*response) {
24656a34939Shaad 		errno = ENOMEM;
24756a34939Shaad 		status = 0;
24856a34939Shaad 		goto out;
24956a34939Shaad 	}
25056a34939Shaad 
25156a34939Shaad 	rarray = *response;
25256a34939Shaad 
25356a34939Shaad 	/* Unpack the response into an lvm_response_t array */
25456a34939Shaad 	inptr = head->args;
25556a34939Shaad 	i = 0;
25656a34939Shaad 	while (inptr[0]) {
25756a34939Shaad 		strcpy(rarray[i].node, inptr);
25856a34939Shaad 		inptr += strlen(inptr) + 1;
25956a34939Shaad 
26056a34939Shaad 		memcpy(&rarray[i].status, inptr, sizeof(int));
26156a34939Shaad 		inptr += sizeof(int);
26256a34939Shaad 
26356a34939Shaad 		rarray[i].response = dm_malloc(strlen(inptr) + 1);
26456a34939Shaad 		if (rarray[i].response == NULL) {
26556a34939Shaad 			/* Free up everything else and return error */
26656a34939Shaad 			int j;
26756a34939Shaad 			for (j = 0; j < i; j++)
26856a34939Shaad 				dm_free(rarray[i].response);
26956a34939Shaad 			free(*response);
27056a34939Shaad 			errno = ENOMEM;
27156a34939Shaad 			status = -1;
27256a34939Shaad 			goto out;
27356a34939Shaad 		}
27456a34939Shaad 
27556a34939Shaad 		strcpy(rarray[i].response, inptr);
27656a34939Shaad 		rarray[i].len = strlen(inptr);
27756a34939Shaad 		inptr += strlen(inptr) + 1;
27856a34939Shaad 		i++;
27956a34939Shaad 	}
28056a34939Shaad 	*num = num_responses;
28156a34939Shaad 	*response = rarray;
28256a34939Shaad 
28356a34939Shaad       out:
28456a34939Shaad 	if (retbuf)
28556a34939Shaad 		dm_free(retbuf);
28656a34939Shaad 
28756a34939Shaad 	return status;
28856a34939Shaad }
28956a34939Shaad 
29056a34939Shaad /* Free reply array */
_cluster_free_request(lvm_response_t * response,int num)29156a34939Shaad static int _cluster_free_request(lvm_response_t * response, int num)
29256a34939Shaad {
29356a34939Shaad 	int i;
29456a34939Shaad 
29556a34939Shaad 	for (i = 0; i < num; i++) {
29656a34939Shaad 		dm_free(response[i].response);
29756a34939Shaad 	}
29856a34939Shaad 
29956a34939Shaad 	dm_free(response);
30056a34939Shaad 
30156a34939Shaad 	return 1;
30256a34939Shaad }
30356a34939Shaad 
_lock_for_cluster(struct cmd_context * cmd,unsigned char clvmd_cmd,uint32_t flags,const char * name)304*7c604eeaShaad static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd,
305*7c604eeaShaad 			     uint32_t flags, const char *name)
30656a34939Shaad {
30756a34939Shaad 	int status;
30856a34939Shaad 	int i;
30956a34939Shaad 	char *args;
31056a34939Shaad 	const char *node = "";
31156a34939Shaad 	int len;
31256a34939Shaad 	int saved_errno = errno;
31356a34939Shaad 	lvm_response_t *response = NULL;
31456a34939Shaad 	int num_responses;
31556a34939Shaad 
31656a34939Shaad 	assert(name);
31756a34939Shaad 
31856a34939Shaad 	len = strlen(name) + 3;
31956a34939Shaad 	args = alloca(len);
32056a34939Shaad 	strcpy(args + 2, name);
32156a34939Shaad 
32256a34939Shaad 	args[0] = flags & 0x7F; /* Maskoff lock flags */
32356a34939Shaad 	args[1] = flags & 0xC0; /* Bitmap flags */
32456a34939Shaad 
32556a34939Shaad 	if (mirror_in_sync())
32656a34939Shaad 		args[1] |= LCK_MIRROR_NOSYNC_MODE;
32756a34939Shaad 
32856a34939Shaad 	if (dmeventd_monitor_mode())
32956a34939Shaad 		args[1] |= LCK_DMEVENTD_MONITOR_MODE;
33056a34939Shaad 
331*7c604eeaShaad 	if (cmd->partial_activation)
332*7c604eeaShaad 		args[1] |= LCK_PARTIAL_MODE;
333*7c604eeaShaad 
33456a34939Shaad 	/*
33556a34939Shaad 	 * VG locks are just that: locks, and have no side effects
33656a34939Shaad 	 * so we only need to do them on the local node because all
33756a34939Shaad 	 * locks are cluster-wide.
33856a34939Shaad 	 * Also, if the lock is exclusive it makes no sense to try to
33956a34939Shaad 	 * acquire it on all nodes, so just do that on the local node too.
34056a34939Shaad 	 * One exception, is that P_ locks /do/ get distributed across
34156a34939Shaad 	 * the cluster because they might have side-effects.
34256a34939Shaad 	 */
34356a34939Shaad 	if (strncmp(name, "P_", 2) &&
344bec4d750Shaad 	    (clvmd_cmd == CLVMD_CMD_LOCK_VG ||
34556a34939Shaad 	     (flags & LCK_TYPE_MASK) == LCK_EXCL ||
34656a34939Shaad 	     (flags & LCK_LOCAL) ||
34756a34939Shaad 	     !(flags & LCK_CLUSTER_VG)))
34856a34939Shaad 		node = ".";
34956a34939Shaad 
350bec4d750Shaad 	status = _cluster_request(clvmd_cmd, node, args, len,
35156a34939Shaad 				  &response, &num_responses);
35256a34939Shaad 
35356a34939Shaad 	/* If any nodes were down then display them and return an error */
35456a34939Shaad 	for (i = 0; i < num_responses; i++) {
35556a34939Shaad 		if (response[i].status == EHOSTDOWN) {
35656a34939Shaad 			log_error("clvmd not running on node %s",
35756a34939Shaad 				  response[i].node);
35856a34939Shaad 			status = 0;
35956a34939Shaad 			errno = response[i].status;
36056a34939Shaad 		} else if (response[i].status) {
36156a34939Shaad 			log_error("Error locking on node %s: %s",
36256a34939Shaad 				  response[i].node,
36356a34939Shaad 				  response[i].response[0] ?
36456a34939Shaad 				  	response[i].response :
36556a34939Shaad 				  	strerror(response[i].status));
36656a34939Shaad 			status = 0;
36756a34939Shaad 			errno = response[i].status;
36856a34939Shaad 		}
36956a34939Shaad 	}
37056a34939Shaad 
37156a34939Shaad 	saved_errno = errno;
37256a34939Shaad 	_cluster_free_request(response, num_responses);
37356a34939Shaad 	errno = saved_errno;
37456a34939Shaad 
37556a34939Shaad 	return status;
37656a34939Shaad }
37756a34939Shaad 
37856a34939Shaad /* API entry point for LVM */
37956a34939Shaad #ifdef CLUSTER_LOCKING_INTERNAL
_lock_resource(struct cmd_context * cmd,const char * resource,uint32_t flags)38056a34939Shaad static int _lock_resource(struct cmd_context *cmd, const char *resource,
38156a34939Shaad 			  uint32_t flags)
38256a34939Shaad #else
38356a34939Shaad int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
38456a34939Shaad #endif
38556a34939Shaad {
38656a34939Shaad 	char lockname[PATH_MAX];
387bec4d750Shaad 	int clvmd_cmd = 0;
38856a34939Shaad 	const char *lock_scope;
38956a34939Shaad 	const char *lock_type = "";
39056a34939Shaad 
39156a34939Shaad 	assert(strlen(resource) < sizeof(lockname));
39256a34939Shaad 	assert(resource);
39356a34939Shaad 
39456a34939Shaad 	switch (flags & LCK_SCOPE_MASK) {
39556a34939Shaad 	case LCK_VG:
396*7c604eeaShaad 		if (flags == LCK_VG_BACKUP) {
397*7c604eeaShaad 			log_very_verbose("Requesting backup of VG metadata for %s",
398*7c604eeaShaad 					 resource);
399*7c604eeaShaad 			return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP,
400*7c604eeaShaad 						 LCK_CLUSTER_VG, resource);
401*7c604eeaShaad 		}
402*7c604eeaShaad 
40356a34939Shaad 		/* If the VG name is empty then lock the unused PVs */
40456a34939Shaad 		if (*resource == '#' || (flags & LCK_CACHE))
40556a34939Shaad 			dm_snprintf(lockname, sizeof(lockname), "P_%s",
40656a34939Shaad 				    resource);
40756a34939Shaad 		else
40856a34939Shaad 			dm_snprintf(lockname, sizeof(lockname), "V_%s",
40956a34939Shaad 				    resource);
41056a34939Shaad 
41156a34939Shaad 		lock_scope = "VG";
412bec4d750Shaad 		clvmd_cmd = CLVMD_CMD_LOCK_VG;
41356a34939Shaad 		flags &= LCK_TYPE_MASK;
41456a34939Shaad 		break;
41556a34939Shaad 
41656a34939Shaad 	case LCK_LV:
417bec4d750Shaad 		clvmd_cmd = CLVMD_CMD_LOCK_LV;
41856a34939Shaad 		strcpy(lockname, resource);
41956a34939Shaad 		lock_scope = "LV";
42056a34939Shaad 		flags &= 0xffdf;	/* Mask off HOLD flag */
42156a34939Shaad 		break;
42256a34939Shaad 
42356a34939Shaad 	default:
42456a34939Shaad 		log_error("Unrecognised lock scope: %d",
42556a34939Shaad 			  flags & LCK_SCOPE_MASK);
42656a34939Shaad 		return 0;
42756a34939Shaad 	}
42856a34939Shaad 
42956a34939Shaad 	switch(flags & LCK_TYPE_MASK) {
43056a34939Shaad 	case LCK_UNLOCK:
43156a34939Shaad 		lock_type = "UN";
43256a34939Shaad 		break;
43356a34939Shaad 	case LCK_NULL:
43456a34939Shaad 		lock_type = "NL";
43556a34939Shaad 		break;
43656a34939Shaad 	case LCK_READ:
43756a34939Shaad 		lock_type = "CR";
43856a34939Shaad 		break;
43956a34939Shaad 	case LCK_PREAD:
44056a34939Shaad 		lock_type = "PR";
44156a34939Shaad 		break;
44256a34939Shaad 	case LCK_WRITE:
44356a34939Shaad 		lock_type = "PW";
44456a34939Shaad 		break;
44556a34939Shaad 	case LCK_EXCL:
44656a34939Shaad 		lock_type = "EX";
44756a34939Shaad 		break;
44856a34939Shaad 	default:
44956a34939Shaad 		log_error("Unrecognised lock type: %u",
45056a34939Shaad 			  flags & LCK_TYPE_MASK);
45156a34939Shaad 		return 0;
45256a34939Shaad 	}
45356a34939Shaad 
45456a34939Shaad 	log_very_verbose("Locking %s %s %s %s%s%s%s (0x%x)", lock_scope, lockname,
45556a34939Shaad 			 lock_type,
45656a34939Shaad 			 flags & LCK_NONBLOCK ? "" : "B",
45756a34939Shaad 			 flags & LCK_HOLD ? "H" : "",
45856a34939Shaad 			 flags & LCK_LOCAL ? "L" : "",
45956a34939Shaad 			 flags & LCK_CLUSTER_VG ? "C" : "",
46056a34939Shaad 			 flags);
46156a34939Shaad 
46256a34939Shaad 	/* Send a message to the cluster manager */
463*7c604eeaShaad 	return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname);
464*7c604eeaShaad }
465*7c604eeaShaad 
decode_lock_type(const char * response)466*7c604eeaShaad static int decode_lock_type(const char *response)
467*7c604eeaShaad {
468*7c604eeaShaad 	if (!response)
469*7c604eeaShaad 		return LCK_NULL;
470*7c604eeaShaad 	else if (strcmp(response, "EX"))
471*7c604eeaShaad 		return LCK_EXCL;
472*7c604eeaShaad 	else if (strcmp(response, "CR"))
473*7c604eeaShaad 		return LCK_READ;
474*7c604eeaShaad 	else if (strcmp(response, "PR"))
475*7c604eeaShaad 		return LCK_PREAD;
476*7c604eeaShaad 
477*7c604eeaShaad 	stack;
478*7c604eeaShaad 	return 0;
479*7c604eeaShaad }
480*7c604eeaShaad 
481*7c604eeaShaad #ifdef CLUSTER_LOCKING_INTERNAL
_query_resource(const char * resource,int * mode)482*7c604eeaShaad static int _query_resource(const char *resource, int *mode)
483*7c604eeaShaad #else
484*7c604eeaShaad int query_resource(const char *resource, int *mode)
485*7c604eeaShaad #endif
486*7c604eeaShaad {
487*7c604eeaShaad 	int i, status, len, num_responses, saved_errno;
488*7c604eeaShaad 	const char *node = "";
489*7c604eeaShaad 	char *args;
490*7c604eeaShaad 	lvm_response_t *response = NULL;
491*7c604eeaShaad 
492*7c604eeaShaad 	saved_errno = errno;
493*7c604eeaShaad 	len = strlen(resource) + 3;
494*7c604eeaShaad 	args = alloca(len);
495*7c604eeaShaad 	strcpy(args + 2, resource);
496*7c604eeaShaad 
497*7c604eeaShaad 	args[0] = 0;
498*7c604eeaShaad 	args[1] = LCK_CLUSTER_VG;
499*7c604eeaShaad 
500*7c604eeaShaad 	status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len,
501*7c604eeaShaad 				  &response, &num_responses);
502*7c604eeaShaad 	*mode = LCK_NULL;
503*7c604eeaShaad 	for (i = 0; i < num_responses; i++) {
504*7c604eeaShaad 		if (response[i].status == EHOSTDOWN)
505*7c604eeaShaad 			continue;
506*7c604eeaShaad 
507*7c604eeaShaad 		if (!response[i].response[0])
508*7c604eeaShaad 			continue;
509*7c604eeaShaad 
510*7c604eeaShaad 		/*
511*7c604eeaShaad 		 * All nodes should use CR, or exactly one node
512*7c604eeaShaad 		 * should held EX. (PR is obsolete)
513*7c604eeaShaad 		 * If two nodes node reports different locks,
514*7c604eeaShaad 		 * something is broken - just return more important mode.
515*7c604eeaShaad 		 */
516*7c604eeaShaad 		if (decode_lock_type(response[i].response) > *mode)
517*7c604eeaShaad 			*mode = decode_lock_type(response[i].response);
518*7c604eeaShaad 
519*7c604eeaShaad 		log_debug("Lock held for %s, node %s : %s", resource,
520*7c604eeaShaad 			  response[i].node, response[i].response);
521*7c604eeaShaad 	}
522*7c604eeaShaad 
523*7c604eeaShaad 	_cluster_free_request(response, num_responses);
524*7c604eeaShaad 	errno = saved_errno;
525*7c604eeaShaad 
526*7c604eeaShaad 	return status;
52756a34939Shaad }
52856a34939Shaad 
52956a34939Shaad #ifdef CLUSTER_LOCKING_INTERNAL
_locking_end(void)53056a34939Shaad static void _locking_end(void)
53156a34939Shaad #else
53256a34939Shaad void locking_end(void)
53356a34939Shaad #endif
53456a34939Shaad {
53556a34939Shaad 	if (_clvmd_sock != -1 && close(_clvmd_sock))
53656a34939Shaad 		stack;
53756a34939Shaad 
53856a34939Shaad 	_clvmd_sock = -1;
53956a34939Shaad }
54056a34939Shaad 
54156a34939Shaad #ifdef CLUSTER_LOCKING_INTERNAL
_reset_locking(void)54256a34939Shaad static void _reset_locking(void)
54356a34939Shaad #else
54456a34939Shaad void reset_locking(void)
54556a34939Shaad #endif
54656a34939Shaad {
54756a34939Shaad 	if (close(_clvmd_sock))
54856a34939Shaad 		stack;
54956a34939Shaad 
55056a34939Shaad 	_clvmd_sock = _open_local_sock();
55156a34939Shaad 	if (_clvmd_sock == -1)
55256a34939Shaad 		stack;
55356a34939Shaad }
55456a34939Shaad 
55556a34939Shaad #ifdef CLUSTER_LOCKING_INTERNAL
init_cluster_locking(struct locking_type * locking,struct cmd_context * cmd)55656a34939Shaad int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
55756a34939Shaad {
55856a34939Shaad 	locking->lock_resource = _lock_resource;
559*7c604eeaShaad 	locking->query_resource = _query_resource;
56056a34939Shaad 	locking->fin_locking = _locking_end;
56156a34939Shaad 	locking->reset_locking = _reset_locking;
56256a34939Shaad 	locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
56356a34939Shaad 
56456a34939Shaad 	_clvmd_sock = _open_local_sock();
56556a34939Shaad 	if (_clvmd_sock == -1)
56656a34939Shaad 		return 0;
56756a34939Shaad 
56856a34939Shaad 	return 1;
56956a34939Shaad }
57056a34939Shaad #else
locking_init(int type,struct config_tree * cf,uint32_t * flags)57156a34939Shaad int locking_init(int type, struct config_tree *cf, uint32_t *flags)
57256a34939Shaad {
57356a34939Shaad 	_clvmd_sock = _open_local_sock();
57456a34939Shaad 	if (_clvmd_sock == -1)
57556a34939Shaad 		return 0;
57656a34939Shaad 
57756a34939Shaad 	/* Ask LVM to lock memory before calling us */
57856a34939Shaad 	*flags |= LCK_PRE_MEMLOCK;
57956a34939Shaad 	*flags |= LCK_CLUSTERED;
58056a34939Shaad 
58156a34939Shaad 	return 1;
58256a34939Shaad }
58356a34939Shaad #endif
584