1d6f15486SAlex Hornung /* $NetBSD: cluster_locking.c,v 1.1.1.3 2009/12/02 00:26:24 haad Exp $ */
2d6f15486SAlex Hornung
3d6f15486SAlex Hornung /*
4d6f15486SAlex Hornung * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5d6f15486SAlex Hornung * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6d6f15486SAlex Hornung *
7d6f15486SAlex Hornung * This file is part of LVM2.
8d6f15486SAlex Hornung *
9d6f15486SAlex Hornung * This copyrighted material is made available to anyone wishing to use,
10d6f15486SAlex Hornung * modify, copy, or redistribute it subject to the terms and conditions
11d6f15486SAlex Hornung * of the GNU Lesser General Public License v.2.1.
12d6f15486SAlex Hornung *
13d6f15486SAlex Hornung * You should have received a copy of the GNU Lesser General Public License
14d6f15486SAlex Hornung * along with this program; if not, write to the Free Software Foundation,
15d6f15486SAlex Hornung * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16d6f15486SAlex Hornung */
17d6f15486SAlex Hornung
18d6f15486SAlex Hornung /*
19d6f15486SAlex Hornung * Locking functions for LVM.
20d6f15486SAlex Hornung * The main purpose of this part of the library is to serialise LVM
21d6f15486SAlex Hornung * management operations across a cluster.
22d6f15486SAlex Hornung */
23d6f15486SAlex Hornung
24d6f15486SAlex Hornung #include "lib.h"
25d6f15486SAlex Hornung #include "clvm.h"
26d6f15486SAlex Hornung #include "lvm-string.h"
27d6f15486SAlex Hornung #include "locking.h"
28d6f15486SAlex Hornung #include "locking_types.h"
29d6f15486SAlex Hornung #include "toolcontext.h"
30d6f15486SAlex Hornung
31d6f15486SAlex Hornung #include <assert.h>
32d6f15486SAlex Hornung #include <stddef.h>
33d6f15486SAlex Hornung #include <sys/socket.h>
34d6f15486SAlex Hornung #include <sys/un.h>
35d6f15486SAlex Hornung #include <unistd.h>
36d6f15486SAlex Hornung
37d6f15486SAlex Hornung #ifndef CLUSTER_LOCKING_INTERNAL
38d6f15486SAlex Hornung int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags);
39d6f15486SAlex Hornung int query_resource(const char *resource, int *mode);
40d6f15486SAlex Hornung void locking_end(void);
41d6f15486SAlex Hornung int locking_init(int type, struct config_tree *cf, uint32_t *flags);
42d6f15486SAlex Hornung #endif
43d6f15486SAlex Hornung
44d6f15486SAlex Hornung typedef struct lvm_response {
45d6f15486SAlex Hornung char node[255];
46d6f15486SAlex Hornung char *response;
47d6f15486SAlex Hornung int status;
48d6f15486SAlex Hornung int len;
49d6f15486SAlex Hornung } lvm_response_t;
50d6f15486SAlex Hornung
51d6f15486SAlex Hornung /*
52d6f15486SAlex Hornung * This gets stuck at the start of memory we allocate so we
53d6f15486SAlex Hornung * can sanity-check it at deallocation time
54d6f15486SAlex Hornung */
55d6f15486SAlex Hornung #define LVM_SIGNATURE 0x434C564D
56d6f15486SAlex Hornung
57d6f15486SAlex Hornung /*
58d6f15486SAlex Hornung * NOTE: the LVMD uses the socket FD as the client ID, this means
59d6f15486SAlex Hornung * that any client that calls fork() will inherit the context of
60d6f15486SAlex Hornung * it's parent.
61d6f15486SAlex Hornung */
62d6f15486SAlex Hornung static int _clvmd_sock = -1;
63d6f15486SAlex Hornung
64d6f15486SAlex Hornung /* FIXME Install SIGPIPE handler? */
65d6f15486SAlex Hornung
66d6f15486SAlex Hornung /* Open connection to the Cluster Manager daemon */
_open_local_sock(void)67d6f15486SAlex Hornung static int _open_local_sock(void)
68d6f15486SAlex Hornung {
69d6f15486SAlex Hornung int local_socket;
70d6f15486SAlex Hornung struct sockaddr_un sockaddr;
71d6f15486SAlex Hornung
72d6f15486SAlex Hornung /* Open local socket */
73d6f15486SAlex Hornung if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
74d6f15486SAlex Hornung log_error("Local socket creation failed: %s", strerror(errno));
75d6f15486SAlex Hornung return -1;
76d6f15486SAlex Hornung }
77d6f15486SAlex Hornung
78d6f15486SAlex Hornung memset(&sockaddr, 0, sizeof(sockaddr));
79d6f15486SAlex Hornung memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
80d6f15486SAlex Hornung
81d6f15486SAlex Hornung sockaddr.sun_family = AF_UNIX;
82d6f15486SAlex Hornung
83d6f15486SAlex Hornung if (connect(local_socket,(struct sockaddr *) &sockaddr,
84d6f15486SAlex Hornung sizeof(sockaddr))) {
85d6f15486SAlex Hornung int saved_errno = errno;
86d6f15486SAlex Hornung
87d6f15486SAlex Hornung log_error("connect() failed on local socket: %s",
88d6f15486SAlex Hornung strerror(errno));
89d6f15486SAlex Hornung if (close(local_socket))
90d6f15486SAlex Hornung stack;
91d6f15486SAlex Hornung
92d6f15486SAlex Hornung errno = saved_errno;
93d6f15486SAlex Hornung return -1;
94d6f15486SAlex Hornung }
95d6f15486SAlex Hornung
96d6f15486SAlex Hornung return local_socket;
97d6f15486SAlex Hornung }
98d6f15486SAlex Hornung
99d6f15486SAlex Hornung /* Send a request and return the status */
_send_request(char * inbuf,int inlen,char ** retbuf)100d6f15486SAlex Hornung static int _send_request(char *inbuf, int inlen, char **retbuf)
101d6f15486SAlex Hornung {
102d6f15486SAlex Hornung char outbuf[PIPE_BUF] __attribute((aligned(8)));
103d6f15486SAlex Hornung struct clvm_header *outheader = (struct clvm_header *) outbuf;
104d6f15486SAlex Hornung int len;
105d6f15486SAlex Hornung int off;
106d6f15486SAlex Hornung int buflen;
107d6f15486SAlex Hornung int err;
108d6f15486SAlex Hornung
109d6f15486SAlex Hornung /* Send it to CLVMD */
110d6f15486SAlex Hornung rewrite:
111d6f15486SAlex Hornung if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
112d6f15486SAlex Hornung if (err == -1 && errno == EINTR)
113d6f15486SAlex Hornung goto rewrite;
114d6f15486SAlex Hornung log_error("Error writing data to clvmd: %s", strerror(errno));
115d6f15486SAlex Hornung return 0;
116d6f15486SAlex Hornung }
117d6f15486SAlex Hornung
118d6f15486SAlex Hornung /* Get the response */
119d6f15486SAlex Hornung reread:
120d6f15486SAlex Hornung if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
121d6f15486SAlex Hornung if (errno == EINTR)
122d6f15486SAlex Hornung goto reread;
123d6f15486SAlex Hornung log_error("Error reading data from clvmd: %s", strerror(errno));
124d6f15486SAlex Hornung return 0;
125d6f15486SAlex Hornung }
126d6f15486SAlex Hornung
127d6f15486SAlex Hornung if (len == 0) {
128d6f15486SAlex Hornung log_error("EOF reading CLVMD");
129d6f15486SAlex Hornung errno = ENOTCONN;
130d6f15486SAlex Hornung return 0;
131d6f15486SAlex Hornung }
132d6f15486SAlex Hornung
133d6f15486SAlex Hornung /* Allocate buffer */
134d6f15486SAlex Hornung buflen = len + outheader->arglen;
135d6f15486SAlex Hornung *retbuf = dm_malloc(buflen);
136d6f15486SAlex Hornung if (!*retbuf) {
137d6f15486SAlex Hornung errno = ENOMEM;
138d6f15486SAlex Hornung return 0;
139d6f15486SAlex Hornung }
140d6f15486SAlex Hornung
141d6f15486SAlex Hornung /* Copy the header */
142d6f15486SAlex Hornung memcpy(*retbuf, outbuf, len);
143d6f15486SAlex Hornung outheader = (struct clvm_header *) *retbuf;
144d6f15486SAlex Hornung
145d6f15486SAlex Hornung /* Read the returned values */
146d6f15486SAlex Hornung off = 1; /* we've already read the first byte */
147d6f15486SAlex Hornung while (off <= outheader->arglen && len > 0) {
148d6f15486SAlex Hornung len = read(_clvmd_sock, outheader->args + off,
149d6f15486SAlex Hornung buflen - off - offsetof(struct clvm_header, args));
150d6f15486SAlex Hornung if (len > 0)
151d6f15486SAlex Hornung off += len;
152d6f15486SAlex Hornung }
153d6f15486SAlex Hornung
154d6f15486SAlex Hornung /* Was it an error ? */
155d6f15486SAlex Hornung if (outheader->status != 0) {
156d6f15486SAlex Hornung errno = outheader->status;
157d6f15486SAlex Hornung
158d6f15486SAlex Hornung /* Only return an error here if there are no node-specific
159d6f15486SAlex Hornung errors present in the message that might have more detail */
160d6f15486SAlex Hornung if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
161d6f15486SAlex Hornung log_error("cluster request failed: %s", strerror(errno));
162d6f15486SAlex Hornung return 0;
163d6f15486SAlex Hornung }
164d6f15486SAlex Hornung
165d6f15486SAlex Hornung }
166d6f15486SAlex Hornung
167d6f15486SAlex Hornung return 1;
168d6f15486SAlex Hornung }
169d6f15486SAlex Hornung
170d6f15486SAlex Hornung /* Build the structure header and parse-out wildcard node names */
171d6f15486SAlex Hornung /* 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)172d6f15486SAlex Hornung static void _build_header(struct clvm_header *head, int clvmd_cmd, const char *node,
173d6f15486SAlex Hornung int len)
174d6f15486SAlex Hornung {
175d6f15486SAlex Hornung head->cmd = clvmd_cmd;
176d6f15486SAlex Hornung head->status = 0;
177d6f15486SAlex Hornung head->flags = 0;
178d6f15486SAlex Hornung head->clientid = 0;
179d6f15486SAlex Hornung head->arglen = len;
180d6f15486SAlex Hornung
181d6f15486SAlex Hornung if (node) {
182d6f15486SAlex Hornung /*
183d6f15486SAlex Hornung * Allow a couple of special node names:
184d6f15486SAlex Hornung * "*" for all nodes,
185d6f15486SAlex Hornung * "." for the local node only
186d6f15486SAlex Hornung */
187d6f15486SAlex Hornung if (strcmp(node, "*") == 0) {
188d6f15486SAlex Hornung head->node[0] = '\0';
189d6f15486SAlex Hornung } else if (strcmp(node, ".") == 0) {
190d6f15486SAlex Hornung head->node[0] = '\0';
191d6f15486SAlex Hornung head->flags = CLVMD_FLAG_LOCAL;
192d6f15486SAlex Hornung } else
193d6f15486SAlex Hornung strcpy(head->node, node);
194d6f15486SAlex Hornung } else
195d6f15486SAlex Hornung head->node[0] = '\0';
196d6f15486SAlex Hornung }
197d6f15486SAlex Hornung
198d6f15486SAlex Hornung /*
199d6f15486SAlex Hornung * Send a message to a(or all) node(s) in the cluster and wait for replies
200d6f15486SAlex Hornung */
_cluster_request(char clvmd_cmd,const char * node,void * data,int len,lvm_response_t ** response,int * num)201d6f15486SAlex Hornung static int _cluster_request(char clvmd_cmd, const char *node, void *data, int len,
202d6f15486SAlex Hornung lvm_response_t ** response, int *num)
203d6f15486SAlex Hornung {
204d6f15486SAlex Hornung char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
205d6f15486SAlex Hornung char *inptr;
206d6f15486SAlex Hornung char *retbuf = NULL;
207d6f15486SAlex Hornung int status;
208d6f15486SAlex Hornung int i;
209d6f15486SAlex Hornung int num_responses = 0;
210d6f15486SAlex Hornung struct clvm_header *head = (struct clvm_header *) outbuf;
211d6f15486SAlex Hornung lvm_response_t *rarray;
212d6f15486SAlex Hornung
213d6f15486SAlex Hornung *num = 0;
214d6f15486SAlex Hornung
215d6f15486SAlex Hornung if (_clvmd_sock == -1)
216d6f15486SAlex Hornung _clvmd_sock = _open_local_sock();
217d6f15486SAlex Hornung
218d6f15486SAlex Hornung if (_clvmd_sock == -1)
219d6f15486SAlex Hornung return 0;
220d6f15486SAlex Hornung
221d6f15486SAlex Hornung _build_header(head, clvmd_cmd, node, len);
222d6f15486SAlex Hornung memcpy(head->node + strlen(head->node) + 1, data, len);
223d6f15486SAlex Hornung
224d6f15486SAlex Hornung status = _send_request(outbuf, sizeof(struct clvm_header) +
225d6f15486SAlex Hornung strlen(head->node) + len, &retbuf);
226d6f15486SAlex Hornung if (!status)
227d6f15486SAlex Hornung goto out;
228d6f15486SAlex Hornung
229d6f15486SAlex Hornung /* Count the number of responses we got */
230d6f15486SAlex Hornung head = (struct clvm_header *) retbuf;
231d6f15486SAlex Hornung inptr = head->args;
232d6f15486SAlex Hornung while (inptr[0]) {
233d6f15486SAlex Hornung num_responses++;
234d6f15486SAlex Hornung inptr += strlen(inptr) + 1;
235d6f15486SAlex Hornung inptr += sizeof(int);
236d6f15486SAlex Hornung inptr += strlen(inptr) + 1;
237d6f15486SAlex Hornung }
238d6f15486SAlex Hornung
239d6f15486SAlex Hornung /*
240d6f15486SAlex Hornung * Allocate response array.
241d6f15486SAlex Hornung * With an extra pair of INTs on the front to sanity
242d6f15486SAlex Hornung * check the pointer when we are given it back to free
243d6f15486SAlex Hornung */
244d6f15486SAlex Hornung *response = dm_malloc(sizeof(lvm_response_t) * num_responses);
245d6f15486SAlex Hornung if (!*response) {
246d6f15486SAlex Hornung errno = ENOMEM;
247d6f15486SAlex Hornung status = 0;
248d6f15486SAlex Hornung goto out;
249d6f15486SAlex Hornung }
250d6f15486SAlex Hornung
251d6f15486SAlex Hornung rarray = *response;
252d6f15486SAlex Hornung
253d6f15486SAlex Hornung /* Unpack the response into an lvm_response_t array */
254d6f15486SAlex Hornung inptr = head->args;
255d6f15486SAlex Hornung i = 0;
256d6f15486SAlex Hornung while (inptr[0]) {
257d6f15486SAlex Hornung strcpy(rarray[i].node, inptr);
258d6f15486SAlex Hornung inptr += strlen(inptr) + 1;
259d6f15486SAlex Hornung
260d6f15486SAlex Hornung memcpy(&rarray[i].status, inptr, sizeof(int));
261d6f15486SAlex Hornung inptr += sizeof(int);
262d6f15486SAlex Hornung
263d6f15486SAlex Hornung rarray[i].response = dm_malloc(strlen(inptr) + 1);
264d6f15486SAlex Hornung if (rarray[i].response == NULL) {
265d6f15486SAlex Hornung /* Free up everything else and return error */
266d6f15486SAlex Hornung int j;
267d6f15486SAlex Hornung for (j = 0; j < i; j++)
268*e1c19072SSascha Wildner dm_free(rarray[j].response);
269d6f15486SAlex Hornung free(*response);
270d6f15486SAlex Hornung errno = ENOMEM;
271d6f15486SAlex Hornung status = -1;
272d6f15486SAlex Hornung goto out;
273d6f15486SAlex Hornung }
274d6f15486SAlex Hornung
275d6f15486SAlex Hornung strcpy(rarray[i].response, inptr);
276d6f15486SAlex Hornung rarray[i].len = strlen(inptr);
277d6f15486SAlex Hornung inptr += strlen(inptr) + 1;
278d6f15486SAlex Hornung i++;
279d6f15486SAlex Hornung }
280d6f15486SAlex Hornung *num = num_responses;
281d6f15486SAlex Hornung *response = rarray;
282d6f15486SAlex Hornung
283d6f15486SAlex Hornung out:
284d6f15486SAlex Hornung if (retbuf)
285d6f15486SAlex Hornung dm_free(retbuf);
286d6f15486SAlex Hornung
287d6f15486SAlex Hornung return status;
288d6f15486SAlex Hornung }
289d6f15486SAlex Hornung
290d6f15486SAlex Hornung /* Free reply array */
_cluster_free_request(lvm_response_t * response,int num)291d6f15486SAlex Hornung static int _cluster_free_request(lvm_response_t * response, int num)
292d6f15486SAlex Hornung {
293d6f15486SAlex Hornung int i;
294d6f15486SAlex Hornung
295d6f15486SAlex Hornung for (i = 0; i < num; i++) {
296d6f15486SAlex Hornung dm_free(response[i].response);
297d6f15486SAlex Hornung }
298d6f15486SAlex Hornung
299d6f15486SAlex Hornung dm_free(response);
300d6f15486SAlex Hornung
301d6f15486SAlex Hornung return 1;
302d6f15486SAlex Hornung }
303d6f15486SAlex Hornung
_lock_for_cluster(struct cmd_context * cmd,unsigned char clvmd_cmd,uint32_t flags,const char * name)304d6f15486SAlex Hornung static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd,
305d6f15486SAlex Hornung uint32_t flags, const char *name)
306d6f15486SAlex Hornung {
307d6f15486SAlex Hornung int status;
308d6f15486SAlex Hornung int i;
309d6f15486SAlex Hornung char *args;
310d6f15486SAlex Hornung const char *node = "";
311d6f15486SAlex Hornung int len;
312d6f15486SAlex Hornung int saved_errno = errno;
313d6f15486SAlex Hornung lvm_response_t *response = NULL;
314d6f15486SAlex Hornung int num_responses;
315d6f15486SAlex Hornung
316d6f15486SAlex Hornung assert(name);
317d6f15486SAlex Hornung
318d6f15486SAlex Hornung len = strlen(name) + 3;
319d6f15486SAlex Hornung args = alloca(len);
320d6f15486SAlex Hornung strcpy(args + 2, name);
321d6f15486SAlex Hornung
322d6f15486SAlex Hornung args[0] = flags & 0x7F; /* Maskoff lock flags */
323d6f15486SAlex Hornung args[1] = flags & 0xC0; /* Bitmap flags */
324d6f15486SAlex Hornung
325d6f15486SAlex Hornung if (mirror_in_sync())
326d6f15486SAlex Hornung args[1] |= LCK_MIRROR_NOSYNC_MODE;
327d6f15486SAlex Hornung
328d6f15486SAlex Hornung if (dmeventd_monitor_mode())
329d6f15486SAlex Hornung args[1] |= LCK_DMEVENTD_MONITOR_MODE;
330d6f15486SAlex Hornung
331d6f15486SAlex Hornung if (cmd->partial_activation)
332d6f15486SAlex Hornung args[1] |= LCK_PARTIAL_MODE;
333d6f15486SAlex Hornung
334d6f15486SAlex Hornung /*
335d6f15486SAlex Hornung * VG locks are just that: locks, and have no side effects
336d6f15486SAlex Hornung * so we only need to do them on the local node because all
337d6f15486SAlex Hornung * locks are cluster-wide.
338d6f15486SAlex Hornung * Also, if the lock is exclusive it makes no sense to try to
339d6f15486SAlex Hornung * acquire it on all nodes, so just do that on the local node too.
340d6f15486SAlex Hornung * One exception, is that P_ locks /do/ get distributed across
341d6f15486SAlex Hornung * the cluster because they might have side-effects.
342d6f15486SAlex Hornung */
343d6f15486SAlex Hornung if (strncmp(name, "P_", 2) &&
344d6f15486SAlex Hornung (clvmd_cmd == CLVMD_CMD_LOCK_VG ||
345d6f15486SAlex Hornung (flags & LCK_TYPE_MASK) == LCK_EXCL ||
346d6f15486SAlex Hornung (flags & LCK_LOCAL) ||
347d6f15486SAlex Hornung !(flags & LCK_CLUSTER_VG)))
348d6f15486SAlex Hornung node = ".";
349d6f15486SAlex Hornung
350d6f15486SAlex Hornung status = _cluster_request(clvmd_cmd, node, args, len,
351d6f15486SAlex Hornung &response, &num_responses);
352d6f15486SAlex Hornung
353d6f15486SAlex Hornung /* If any nodes were down then display them and return an error */
354d6f15486SAlex Hornung for (i = 0; i < num_responses; i++) {
355d6f15486SAlex Hornung if (response[i].status == EHOSTDOWN) {
356d6f15486SAlex Hornung log_error("clvmd not running on node %s",
357d6f15486SAlex Hornung response[i].node);
358d6f15486SAlex Hornung status = 0;
359d6f15486SAlex Hornung errno = response[i].status;
360d6f15486SAlex Hornung } else if (response[i].status) {
361d6f15486SAlex Hornung log_error("Error locking on node %s: %s",
362d6f15486SAlex Hornung response[i].node,
363d6f15486SAlex Hornung response[i].response[0] ?
364d6f15486SAlex Hornung response[i].response :
365d6f15486SAlex Hornung strerror(response[i].status));
366d6f15486SAlex Hornung status = 0;
367d6f15486SAlex Hornung errno = response[i].status;
368d6f15486SAlex Hornung }
369d6f15486SAlex Hornung }
370d6f15486SAlex Hornung
371d6f15486SAlex Hornung saved_errno = errno;
372d6f15486SAlex Hornung _cluster_free_request(response, num_responses);
373d6f15486SAlex Hornung errno = saved_errno;
374d6f15486SAlex Hornung
375d6f15486SAlex Hornung return status;
376d6f15486SAlex Hornung }
377d6f15486SAlex Hornung
378d6f15486SAlex Hornung /* API entry point for LVM */
379d6f15486SAlex Hornung #ifdef CLUSTER_LOCKING_INTERNAL
_lock_resource(struct cmd_context * cmd,const char * resource,uint32_t flags)380d6f15486SAlex Hornung static int _lock_resource(struct cmd_context *cmd, const char *resource,
381d6f15486SAlex Hornung uint32_t flags)
382d6f15486SAlex Hornung #else
383d6f15486SAlex Hornung int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
384d6f15486SAlex Hornung #endif
385d6f15486SAlex Hornung {
386d6f15486SAlex Hornung char lockname[PATH_MAX];
387d6f15486SAlex Hornung int clvmd_cmd = 0;
388d6f15486SAlex Hornung const char *lock_scope;
389d6f15486SAlex Hornung const char *lock_type = "";
390d6f15486SAlex Hornung
391d6f15486SAlex Hornung assert(strlen(resource) < sizeof(lockname));
392d6f15486SAlex Hornung assert(resource);
393d6f15486SAlex Hornung
394d6f15486SAlex Hornung switch (flags & LCK_SCOPE_MASK) {
395d6f15486SAlex Hornung case LCK_VG:
396d6f15486SAlex Hornung if (flags == LCK_VG_BACKUP) {
397d6f15486SAlex Hornung log_very_verbose("Requesting backup of VG metadata for %s",
398d6f15486SAlex Hornung resource);
399d6f15486SAlex Hornung return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP,
400d6f15486SAlex Hornung LCK_CLUSTER_VG, resource);
401d6f15486SAlex Hornung }
402d6f15486SAlex Hornung
403d6f15486SAlex Hornung /* If the VG name is empty then lock the unused PVs */
404d6f15486SAlex Hornung if (*resource == '#' || (flags & LCK_CACHE))
405d6f15486SAlex Hornung dm_snprintf(lockname, sizeof(lockname), "P_%s",
406d6f15486SAlex Hornung resource);
407d6f15486SAlex Hornung else
408d6f15486SAlex Hornung dm_snprintf(lockname, sizeof(lockname), "V_%s",
409d6f15486SAlex Hornung resource);
410d6f15486SAlex Hornung
411d6f15486SAlex Hornung lock_scope = "VG";
412d6f15486SAlex Hornung clvmd_cmd = CLVMD_CMD_LOCK_VG;
413d6f15486SAlex Hornung flags &= LCK_TYPE_MASK;
414d6f15486SAlex Hornung break;
415d6f15486SAlex Hornung
416d6f15486SAlex Hornung case LCK_LV:
417d6f15486SAlex Hornung clvmd_cmd = CLVMD_CMD_LOCK_LV;
418d6f15486SAlex Hornung strcpy(lockname, resource);
419d6f15486SAlex Hornung lock_scope = "LV";
420d6f15486SAlex Hornung flags &= 0xffdf; /* Mask off HOLD flag */
421d6f15486SAlex Hornung break;
422d6f15486SAlex Hornung
423d6f15486SAlex Hornung default:
424d6f15486SAlex Hornung log_error("Unrecognised lock scope: %d",
425d6f15486SAlex Hornung flags & LCK_SCOPE_MASK);
426d6f15486SAlex Hornung return 0;
427d6f15486SAlex Hornung }
428d6f15486SAlex Hornung
429d6f15486SAlex Hornung switch(flags & LCK_TYPE_MASK) {
430d6f15486SAlex Hornung case LCK_UNLOCK:
431d6f15486SAlex Hornung lock_type = "UN";
432d6f15486SAlex Hornung break;
433d6f15486SAlex Hornung case LCK_NULL:
434d6f15486SAlex Hornung lock_type = "NL";
435d6f15486SAlex Hornung break;
436d6f15486SAlex Hornung case LCK_READ:
437d6f15486SAlex Hornung lock_type = "CR";
438d6f15486SAlex Hornung break;
439d6f15486SAlex Hornung case LCK_PREAD:
440d6f15486SAlex Hornung lock_type = "PR";
441d6f15486SAlex Hornung break;
442d6f15486SAlex Hornung case LCK_WRITE:
443d6f15486SAlex Hornung lock_type = "PW";
444d6f15486SAlex Hornung break;
445d6f15486SAlex Hornung case LCK_EXCL:
446d6f15486SAlex Hornung lock_type = "EX";
447d6f15486SAlex Hornung break;
448d6f15486SAlex Hornung default:
449d6f15486SAlex Hornung log_error("Unrecognised lock type: %u",
450d6f15486SAlex Hornung flags & LCK_TYPE_MASK);
451d6f15486SAlex Hornung return 0;
452d6f15486SAlex Hornung }
453d6f15486SAlex Hornung
454d6f15486SAlex Hornung log_very_verbose("Locking %s %s %s %s%s%s%s (0x%x)", lock_scope, lockname,
455d6f15486SAlex Hornung lock_type,
456d6f15486SAlex Hornung flags & LCK_NONBLOCK ? "" : "B",
457d6f15486SAlex Hornung flags & LCK_HOLD ? "H" : "",
458d6f15486SAlex Hornung flags & LCK_LOCAL ? "L" : "",
459d6f15486SAlex Hornung flags & LCK_CLUSTER_VG ? "C" : "",
460d6f15486SAlex Hornung flags);
461d6f15486SAlex Hornung
462d6f15486SAlex Hornung /* Send a message to the cluster manager */
463d6f15486SAlex Hornung return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname);
464d6f15486SAlex Hornung }
465d6f15486SAlex Hornung
decode_lock_type(const char * response)466d6f15486SAlex Hornung static int decode_lock_type(const char *response)
467d6f15486SAlex Hornung {
468d6f15486SAlex Hornung if (!response)
469d6f15486SAlex Hornung return LCK_NULL;
470d6f15486SAlex Hornung else if (strcmp(response, "EX"))
471d6f15486SAlex Hornung return LCK_EXCL;
472d6f15486SAlex Hornung else if (strcmp(response, "CR"))
473d6f15486SAlex Hornung return LCK_READ;
474d6f15486SAlex Hornung else if (strcmp(response, "PR"))
475d6f15486SAlex Hornung return LCK_PREAD;
476d6f15486SAlex Hornung
477d6f15486SAlex Hornung stack;
478d6f15486SAlex Hornung return 0;
479d6f15486SAlex Hornung }
480d6f15486SAlex Hornung
481d6f15486SAlex Hornung #ifdef CLUSTER_LOCKING_INTERNAL
_query_resource(const char * resource,int * mode)482d6f15486SAlex Hornung static int _query_resource(const char *resource, int *mode)
483d6f15486SAlex Hornung #else
484d6f15486SAlex Hornung int query_resource(const char *resource, int *mode)
485d6f15486SAlex Hornung #endif
486d6f15486SAlex Hornung {
487d6f15486SAlex Hornung int i, status, len, num_responses, saved_errno;
488d6f15486SAlex Hornung const char *node = "";
489d6f15486SAlex Hornung char *args;
490d6f15486SAlex Hornung lvm_response_t *response = NULL;
491d6f15486SAlex Hornung
492d6f15486SAlex Hornung saved_errno = errno;
493d6f15486SAlex Hornung len = strlen(resource) + 3;
494d6f15486SAlex Hornung args = alloca(len);
495d6f15486SAlex Hornung strcpy(args + 2, resource);
496d6f15486SAlex Hornung
497d6f15486SAlex Hornung args[0] = 0;
498d6f15486SAlex Hornung args[1] = LCK_CLUSTER_VG;
499d6f15486SAlex Hornung
500d6f15486SAlex Hornung status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len,
501d6f15486SAlex Hornung &response, &num_responses);
502d6f15486SAlex Hornung *mode = LCK_NULL;
503d6f15486SAlex Hornung for (i = 0; i < num_responses; i++) {
504d6f15486SAlex Hornung if (response[i].status == EHOSTDOWN)
505d6f15486SAlex Hornung continue;
506d6f15486SAlex Hornung
507d6f15486SAlex Hornung if (!response[i].response[0])
508d6f15486SAlex Hornung continue;
509d6f15486SAlex Hornung
510d6f15486SAlex Hornung /*
511d6f15486SAlex Hornung * All nodes should use CR, or exactly one node
512d6f15486SAlex Hornung * should held EX. (PR is obsolete)
513d6f15486SAlex Hornung * If two nodes node reports different locks,
514d6f15486SAlex Hornung * something is broken - just return more important mode.
515d6f15486SAlex Hornung */
516d6f15486SAlex Hornung if (decode_lock_type(response[i].response) > *mode)
517d6f15486SAlex Hornung *mode = decode_lock_type(response[i].response);
518d6f15486SAlex Hornung
519d6f15486SAlex Hornung log_debug("Lock held for %s, node %s : %s", resource,
520d6f15486SAlex Hornung response[i].node, response[i].response);
521d6f15486SAlex Hornung }
522d6f15486SAlex Hornung
523d6f15486SAlex Hornung _cluster_free_request(response, num_responses);
524d6f15486SAlex Hornung errno = saved_errno;
525d6f15486SAlex Hornung
526d6f15486SAlex Hornung return status;
527d6f15486SAlex Hornung }
528d6f15486SAlex Hornung
529d6f15486SAlex Hornung #ifdef CLUSTER_LOCKING_INTERNAL
_locking_end(void)530d6f15486SAlex Hornung static void _locking_end(void)
531d6f15486SAlex Hornung #else
532d6f15486SAlex Hornung void locking_end(void)
533d6f15486SAlex Hornung #endif
534d6f15486SAlex Hornung {
535d6f15486SAlex Hornung if (_clvmd_sock != -1 && close(_clvmd_sock))
536d6f15486SAlex Hornung stack;
537d6f15486SAlex Hornung
538d6f15486SAlex Hornung _clvmd_sock = -1;
539d6f15486SAlex Hornung }
540d6f15486SAlex Hornung
541d6f15486SAlex Hornung #ifdef CLUSTER_LOCKING_INTERNAL
_reset_locking(void)542d6f15486SAlex Hornung static void _reset_locking(void)
543d6f15486SAlex Hornung #else
544d6f15486SAlex Hornung void reset_locking(void)
545d6f15486SAlex Hornung #endif
546d6f15486SAlex Hornung {
547d6f15486SAlex Hornung if (close(_clvmd_sock))
548d6f15486SAlex Hornung stack;
549d6f15486SAlex Hornung
550d6f15486SAlex Hornung _clvmd_sock = _open_local_sock();
551d6f15486SAlex Hornung if (_clvmd_sock == -1)
552d6f15486SAlex Hornung stack;
553d6f15486SAlex Hornung }
554d6f15486SAlex Hornung
555d6f15486SAlex Hornung #ifdef CLUSTER_LOCKING_INTERNAL
init_cluster_locking(struct locking_type * locking,struct cmd_context * cmd)556d6f15486SAlex Hornung int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd)
557d6f15486SAlex Hornung {
558d6f15486SAlex Hornung locking->lock_resource = _lock_resource;
559d6f15486SAlex Hornung locking->query_resource = _query_resource;
560d6f15486SAlex Hornung locking->fin_locking = _locking_end;
561d6f15486SAlex Hornung locking->reset_locking = _reset_locking;
562d6f15486SAlex Hornung locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
563d6f15486SAlex Hornung
564d6f15486SAlex Hornung _clvmd_sock = _open_local_sock();
565d6f15486SAlex Hornung if (_clvmd_sock == -1)
566d6f15486SAlex Hornung return 0;
567d6f15486SAlex Hornung
568d6f15486SAlex Hornung return 1;
569d6f15486SAlex Hornung }
570d6f15486SAlex Hornung #else
locking_init(int type,struct config_tree * cf,uint32_t * flags)571d6f15486SAlex Hornung int locking_init(int type, struct config_tree *cf, uint32_t *flags)
572d6f15486SAlex Hornung {
573d6f15486SAlex Hornung _clvmd_sock = _open_local_sock();
574d6f15486SAlex Hornung if (_clvmd_sock == -1)
575d6f15486SAlex Hornung return 0;
576d6f15486SAlex Hornung
577d6f15486SAlex Hornung /* Ask LVM to lock memory before calling us */
578d6f15486SAlex Hornung *flags |= LCK_PRE_MEMLOCK;
579d6f15486SAlex Hornung *flags |= LCK_CLUSTERED;
580d6f15486SAlex Hornung
581d6f15486SAlex Hornung return 1;
582d6f15486SAlex Hornung }
583d6f15486SAlex Hornung #endif
584