1*86d7f5d3SJohn Marino /*	$NetBSD: locking.c,v 1.1.1.3 2009/12/02 00:26:25 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "lib.h"
19*86d7f5d3SJohn Marino #include "locking.h"
20*86d7f5d3SJohn Marino #include "locking_types.h"
21*86d7f5d3SJohn Marino #include "lvm-string.h"
22*86d7f5d3SJohn Marino #include "activate.h"
23*86d7f5d3SJohn Marino #include "toolcontext.h"
24*86d7f5d3SJohn Marino #include "memlock.h"
25*86d7f5d3SJohn Marino #include "defaults.h"
26*86d7f5d3SJohn Marino #include "lvmcache.h"
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino #include <assert.h>
29*86d7f5d3SJohn Marino #include <signal.h>
30*86d7f5d3SJohn Marino #include <sys/stat.h>
31*86d7f5d3SJohn Marino #include <limits.h>
32*86d7f5d3SJohn Marino #include <unistd.h>
33*86d7f5d3SJohn Marino 
34*86d7f5d3SJohn Marino static struct locking_type _locking;
35*86d7f5d3SJohn Marino static sigset_t _oldset;
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino static int _vg_lock_count = 0;		/* Number of locks held */
38*86d7f5d3SJohn Marino static int _vg_write_lock_held = 0;	/* VG write lock held? */
39*86d7f5d3SJohn Marino static int _signals_blocked = 0;
40*86d7f5d3SJohn Marino static int _blocking_supported = 0;
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino static volatile sig_atomic_t _sigint_caught = 0;
43*86d7f5d3SJohn Marino static volatile sig_atomic_t _handler_installed;
44*86d7f5d3SJohn Marino static struct sigaction _oldhandler;
45*86d7f5d3SJohn Marino static int _oldmasked;
46*86d7f5d3SJohn Marino 
47*86d7f5d3SJohn Marino typedef enum {
48*86d7f5d3SJohn Marino         LV_NOOP,
49*86d7f5d3SJohn Marino         LV_SUSPEND,
50*86d7f5d3SJohn Marino         LV_RESUME
51*86d7f5d3SJohn Marino } lv_operation_t;
52*86d7f5d3SJohn Marino 
_catch_sigint(int unused)53*86d7f5d3SJohn Marino static void _catch_sigint(int unused __attribute__((unused)))
54*86d7f5d3SJohn Marino {
55*86d7f5d3SJohn Marino 	_sigint_caught = 1;
56*86d7f5d3SJohn Marino }
57*86d7f5d3SJohn Marino 
sigint_caught(void)58*86d7f5d3SJohn Marino int sigint_caught(void) {
59*86d7f5d3SJohn Marino 	return _sigint_caught;
60*86d7f5d3SJohn Marino }
61*86d7f5d3SJohn Marino 
sigint_clear(void)62*86d7f5d3SJohn Marino void sigint_clear(void)
63*86d7f5d3SJohn Marino {
64*86d7f5d3SJohn Marino 	_sigint_caught = 0;
65*86d7f5d3SJohn Marino }
66*86d7f5d3SJohn Marino 
67*86d7f5d3SJohn Marino /*
68*86d7f5d3SJohn Marino  * Temporarily allow keyboard interrupts to be intercepted and noted;
69*86d7f5d3SJohn Marino  * saves interrupt handler state for sigint_restore().  Users should
70*86d7f5d3SJohn Marino  * use the sigint_caught() predicate to check whether interrupt was
71*86d7f5d3SJohn Marino  * requested and act appropriately.  Interrupt flags are never
72*86d7f5d3SJohn Marino  * cleared automatically by this code, but the tools clear the flag
73*86d7f5d3SJohn Marino  * before running each command in lvm_run_command().  All other places
74*86d7f5d3SJohn Marino  * where the flag needs to be cleared need to call sigint_clear().
75*86d7f5d3SJohn Marino  */
76*86d7f5d3SJohn Marino 
sigint_allow(void)77*86d7f5d3SJohn Marino void sigint_allow(void)
78*86d7f5d3SJohn Marino {
79*86d7f5d3SJohn Marino 	struct sigaction handler;
80*86d7f5d3SJohn Marino 	sigset_t sigs;
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino 	/*
83*86d7f5d3SJohn Marino 	 * Do not overwrite the backed-up handler data -
84*86d7f5d3SJohn Marino 	 * just increase nesting count.
85*86d7f5d3SJohn Marino 	 */
86*86d7f5d3SJohn Marino 	if (_handler_installed) {
87*86d7f5d3SJohn Marino 		_handler_installed++;
88*86d7f5d3SJohn Marino 		return;
89*86d7f5d3SJohn Marino 	}
90*86d7f5d3SJohn Marino 
91*86d7f5d3SJohn Marino 	/* Grab old sigaction for SIGINT: shall not fail. */
92*86d7f5d3SJohn Marino 	sigaction(SIGINT, NULL, &handler);
93*86d7f5d3SJohn Marino 	handler.sa_flags &= ~SA_RESTART; /* Clear restart flag */
94*86d7f5d3SJohn Marino 	handler.sa_handler = _catch_sigint;
95*86d7f5d3SJohn Marino 
96*86d7f5d3SJohn Marino 	_handler_installed = 1;
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino 	/* Override the signal handler: shall not fail. */
99*86d7f5d3SJohn Marino 	sigaction(SIGINT, &handler, &_oldhandler);
100*86d7f5d3SJohn Marino 
101*86d7f5d3SJohn Marino 	/* Unmask SIGINT.  Remember to mask it again on restore. */
102*86d7f5d3SJohn Marino 	sigprocmask(0, NULL, &sigs);
103*86d7f5d3SJohn Marino 	if ((_oldmasked = sigismember(&sigs, SIGINT))) {
104*86d7f5d3SJohn Marino 		sigdelset(&sigs, SIGINT);
105*86d7f5d3SJohn Marino 		sigprocmask(SIG_SETMASK, &sigs, NULL);
106*86d7f5d3SJohn Marino 	}
107*86d7f5d3SJohn Marino }
108*86d7f5d3SJohn Marino 
sigint_restore(void)109*86d7f5d3SJohn Marino void sigint_restore(void)
110*86d7f5d3SJohn Marino {
111*86d7f5d3SJohn Marino 	if (!_handler_installed)
112*86d7f5d3SJohn Marino 		return;
113*86d7f5d3SJohn Marino 
114*86d7f5d3SJohn Marino 	if (_handler_installed > 1) {
115*86d7f5d3SJohn Marino 		_handler_installed--;
116*86d7f5d3SJohn Marino 		return;
117*86d7f5d3SJohn Marino 	}
118*86d7f5d3SJohn Marino 
119*86d7f5d3SJohn Marino 	/* Nesting count went down to 0. */
120*86d7f5d3SJohn Marino 	_handler_installed = 0;
121*86d7f5d3SJohn Marino 
122*86d7f5d3SJohn Marino 	if (_oldmasked) {
123*86d7f5d3SJohn Marino 		sigset_t sigs;
124*86d7f5d3SJohn Marino 		sigprocmask(0, NULL, &sigs);
125*86d7f5d3SJohn Marino 		sigaddset(&sigs, SIGINT);
126*86d7f5d3SJohn Marino 		sigprocmask(SIG_SETMASK, &sigs, NULL);
127*86d7f5d3SJohn Marino 	}
128*86d7f5d3SJohn Marino 
129*86d7f5d3SJohn Marino 	sigaction(SIGINT, &_oldhandler, NULL);
130*86d7f5d3SJohn Marino }
131*86d7f5d3SJohn Marino 
_block_signals(uint32_t flags __attribute ((unused)))132*86d7f5d3SJohn Marino static void _block_signals(uint32_t flags __attribute((unused)))
133*86d7f5d3SJohn Marino {
134*86d7f5d3SJohn Marino 	sigset_t set;
135*86d7f5d3SJohn Marino 
136*86d7f5d3SJohn Marino 	if (_signals_blocked)
137*86d7f5d3SJohn Marino 		return;
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino 	if (sigfillset(&set)) {
140*86d7f5d3SJohn Marino 		log_sys_error("sigfillset", "_block_signals");
141*86d7f5d3SJohn Marino 		return;
142*86d7f5d3SJohn Marino 	}
143*86d7f5d3SJohn Marino 
144*86d7f5d3SJohn Marino 	if (sigprocmask(SIG_SETMASK, &set, &_oldset)) {
145*86d7f5d3SJohn Marino 		log_sys_error("sigprocmask", "_block_signals");
146*86d7f5d3SJohn Marino 		return;
147*86d7f5d3SJohn Marino 	}
148*86d7f5d3SJohn Marino 
149*86d7f5d3SJohn Marino 	_signals_blocked = 1;
150*86d7f5d3SJohn Marino 
151*86d7f5d3SJohn Marino 	return;
152*86d7f5d3SJohn Marino }
153*86d7f5d3SJohn Marino 
_unblock_signals(void)154*86d7f5d3SJohn Marino static void _unblock_signals(void)
155*86d7f5d3SJohn Marino {
156*86d7f5d3SJohn Marino 	/* Don't unblock signals while any locks are held */
157*86d7f5d3SJohn Marino 	if (!_signals_blocked || _vg_lock_count)
158*86d7f5d3SJohn Marino 		return;
159*86d7f5d3SJohn Marino 
160*86d7f5d3SJohn Marino 	if (sigprocmask(SIG_SETMASK, &_oldset, NULL)) {
161*86d7f5d3SJohn Marino 		log_sys_error("sigprocmask", "_block_signals");
162*86d7f5d3SJohn Marino 		return;
163*86d7f5d3SJohn Marino 	}
164*86d7f5d3SJohn Marino 
165*86d7f5d3SJohn Marino 	_signals_blocked = 0;
166*86d7f5d3SJohn Marino 
167*86d7f5d3SJohn Marino 	return;
168*86d7f5d3SJohn Marino }
169*86d7f5d3SJohn Marino 
_lock_memory(lv_operation_t lv_op)170*86d7f5d3SJohn Marino static void _lock_memory(lv_operation_t lv_op)
171*86d7f5d3SJohn Marino {
172*86d7f5d3SJohn Marino 	if (!(_locking.flags & LCK_PRE_MEMLOCK))
173*86d7f5d3SJohn Marino 		return;
174*86d7f5d3SJohn Marino 
175*86d7f5d3SJohn Marino 	if (lv_op == LV_SUSPEND)
176*86d7f5d3SJohn Marino 		memlock_inc();
177*86d7f5d3SJohn Marino }
178*86d7f5d3SJohn Marino 
_unlock_memory(lv_operation_t lv_op)179*86d7f5d3SJohn Marino static void _unlock_memory(lv_operation_t lv_op)
180*86d7f5d3SJohn Marino {
181*86d7f5d3SJohn Marino 	if (!(_locking.flags & LCK_PRE_MEMLOCK))
182*86d7f5d3SJohn Marino 		return;
183*86d7f5d3SJohn Marino 
184*86d7f5d3SJohn Marino 	if (lv_op == LV_RESUME)
185*86d7f5d3SJohn Marino 		memlock_dec();
186*86d7f5d3SJohn Marino }
187*86d7f5d3SJohn Marino 
reset_locking(void)188*86d7f5d3SJohn Marino void reset_locking(void)
189*86d7f5d3SJohn Marino {
190*86d7f5d3SJohn Marino 	int was_locked = _vg_lock_count;
191*86d7f5d3SJohn Marino 
192*86d7f5d3SJohn Marino 	_vg_lock_count = 0;
193*86d7f5d3SJohn Marino 	_vg_write_lock_held = 0;
194*86d7f5d3SJohn Marino 
195*86d7f5d3SJohn Marino 	_locking.reset_locking();
196*86d7f5d3SJohn Marino 
197*86d7f5d3SJohn Marino 	if (was_locked)
198*86d7f5d3SJohn Marino 		_unblock_signals();
199*86d7f5d3SJohn Marino }
200*86d7f5d3SJohn Marino 
_update_vg_lock_count(const char * resource,uint32_t flags)201*86d7f5d3SJohn Marino static void _update_vg_lock_count(const char *resource, uint32_t flags)
202*86d7f5d3SJohn Marino {
203*86d7f5d3SJohn Marino 	/* Ignore locks not associated with updating VG metadata */
204*86d7f5d3SJohn Marino 	if ((flags & LCK_SCOPE_MASK) != LCK_VG ||
205*86d7f5d3SJohn Marino 	    (flags & LCK_CACHE) ||
206*86d7f5d3SJohn Marino 	    !strcmp(resource, VG_GLOBAL))
207*86d7f5d3SJohn Marino 		return;
208*86d7f5d3SJohn Marino 
209*86d7f5d3SJohn Marino 	if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
210*86d7f5d3SJohn Marino 		_vg_lock_count--;
211*86d7f5d3SJohn Marino 	else
212*86d7f5d3SJohn Marino 		_vg_lock_count++;
213*86d7f5d3SJohn Marino 
214*86d7f5d3SJohn Marino 	/* We don't bother to reset this until all VG locks are dropped */
215*86d7f5d3SJohn Marino 	if ((flags & LCK_TYPE_MASK) == LCK_WRITE)
216*86d7f5d3SJohn Marino 		_vg_write_lock_held = 1;
217*86d7f5d3SJohn Marino 	else if (!_vg_lock_count)
218*86d7f5d3SJohn Marino 		_vg_write_lock_held = 0;
219*86d7f5d3SJohn Marino }
220*86d7f5d3SJohn Marino 
221*86d7f5d3SJohn Marino /*
222*86d7f5d3SJohn Marino  * Select a locking type
223*86d7f5d3SJohn Marino  * type: locking type; if < 0, then read config tree value
224*86d7f5d3SJohn Marino  */
init_locking(int type,struct cmd_context * cmd)225*86d7f5d3SJohn Marino int init_locking(int type, struct cmd_context *cmd)
226*86d7f5d3SJohn Marino {
227*86d7f5d3SJohn Marino 	if (type < 0)
228*86d7f5d3SJohn Marino 		type = find_config_tree_int(cmd, "global/locking_type", 1);
229*86d7f5d3SJohn Marino 
230*86d7f5d3SJohn Marino 	_blocking_supported = find_config_tree_int(cmd,
231*86d7f5d3SJohn Marino 	    "global/wait_for_locks", DEFAULT_WAIT_FOR_LOCKS);
232*86d7f5d3SJohn Marino 
233*86d7f5d3SJohn Marino 	switch (type) {
234*86d7f5d3SJohn Marino 	case 0:
235*86d7f5d3SJohn Marino 		init_no_locking(&_locking, cmd);
236*86d7f5d3SJohn Marino 		log_warn("WARNING: Locking disabled. Be careful! "
237*86d7f5d3SJohn Marino 			  "This could corrupt your metadata.");
238*86d7f5d3SJohn Marino 		return 1;
239*86d7f5d3SJohn Marino 
240*86d7f5d3SJohn Marino 	case 1:
241*86d7f5d3SJohn Marino 		log_very_verbose("%sFile-based locking selected.",
242*86d7f5d3SJohn Marino 				 _blocking_supported ? "" : "Non-blocking ");
243*86d7f5d3SJohn Marino 
244*86d7f5d3SJohn Marino 		if (!init_file_locking(&_locking, cmd))
245*86d7f5d3SJohn Marino 			break;
246*86d7f5d3SJohn Marino 		return 1;
247*86d7f5d3SJohn Marino 
248*86d7f5d3SJohn Marino #ifdef HAVE_LIBDL
249*86d7f5d3SJohn Marino 	case 2:
250*86d7f5d3SJohn Marino 		if (!is_static()) {
251*86d7f5d3SJohn Marino 			log_very_verbose("External locking selected.");
252*86d7f5d3SJohn Marino 			if (init_external_locking(&_locking, cmd))
253*86d7f5d3SJohn Marino 				return 1;
254*86d7f5d3SJohn Marino 		}
255*86d7f5d3SJohn Marino 		if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
256*86d7f5d3SJohn Marino 			    find_config_tree_int(cmd, "global/fallback_to_clustered_locking",
257*86d7f5d3SJohn Marino 						 DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING)))
258*86d7f5d3SJohn Marino 			break;
259*86d7f5d3SJohn Marino #endif
260*86d7f5d3SJohn Marino 
261*86d7f5d3SJohn Marino #ifdef CLUSTER_LOCKING_INTERNAL
262*86d7f5d3SJohn Marino 		log_very_verbose("Falling back to internal clustered locking.");
263*86d7f5d3SJohn Marino 		/* Fall through */
264*86d7f5d3SJohn Marino 
265*86d7f5d3SJohn Marino 	case 3:
266*86d7f5d3SJohn Marino 		log_very_verbose("Cluster locking selected.");
267*86d7f5d3SJohn Marino 		if (!init_cluster_locking(&_locking, cmd))
268*86d7f5d3SJohn Marino 			break;
269*86d7f5d3SJohn Marino 		return 1;
270*86d7f5d3SJohn Marino #endif
271*86d7f5d3SJohn Marino 
272*86d7f5d3SJohn Marino 	case 4:
273*86d7f5d3SJohn Marino 		log_verbose("Read-only locking selected. "
274*86d7f5d3SJohn Marino 			    "Only read operations permitted.");
275*86d7f5d3SJohn Marino 		if (!init_readonly_locking(&_locking, cmd))
276*86d7f5d3SJohn Marino 			break;
277*86d7f5d3SJohn Marino 		return 1;
278*86d7f5d3SJohn Marino 
279*86d7f5d3SJohn Marino 	default:
280*86d7f5d3SJohn Marino 		log_error("Unknown locking type requested.");
281*86d7f5d3SJohn Marino 		return 0;
282*86d7f5d3SJohn Marino 	}
283*86d7f5d3SJohn Marino 
284*86d7f5d3SJohn Marino 	if ((type == 2 || type == 3) &&
285*86d7f5d3SJohn Marino 	    find_config_tree_int(cmd, "locking/fallback_to_local_locking",
286*86d7f5d3SJohn Marino 	    	    find_config_tree_int(cmd, "global/fallback_to_local_locking",
287*86d7f5d3SJohn Marino 					 DEFAULT_FALLBACK_TO_LOCAL_LOCKING))) {
288*86d7f5d3SJohn Marino 		log_warn("WARNING: Falling back to local file-based locking.");
289*86d7f5d3SJohn Marino 		log_warn("Volume Groups with the clustered attribute will "
290*86d7f5d3SJohn Marino 			  "be inaccessible.");
291*86d7f5d3SJohn Marino 		if (init_file_locking(&_locking, cmd))
292*86d7f5d3SJohn Marino 			return 1;
293*86d7f5d3SJohn Marino 	}
294*86d7f5d3SJohn Marino 
295*86d7f5d3SJohn Marino 	if (!ignorelockingfailure())
296*86d7f5d3SJohn Marino 		return 0;
297*86d7f5d3SJohn Marino 
298*86d7f5d3SJohn Marino 	log_verbose("Locking disabled - only read operations permitted.");
299*86d7f5d3SJohn Marino 	init_readonly_locking(&_locking, cmd);
300*86d7f5d3SJohn Marino 
301*86d7f5d3SJohn Marino 	return 1;
302*86d7f5d3SJohn Marino }
303*86d7f5d3SJohn Marino 
fin_locking(void)304*86d7f5d3SJohn Marino void fin_locking(void)
305*86d7f5d3SJohn Marino {
306*86d7f5d3SJohn Marino 	_locking.fin_locking();
307*86d7f5d3SJohn Marino }
308*86d7f5d3SJohn Marino 
309*86d7f5d3SJohn Marino /*
310*86d7f5d3SJohn Marino  * Does the LVM1 driver know of this VG name?
311*86d7f5d3SJohn Marino  */
check_lvm1_vg_inactive(struct cmd_context * cmd,const char * vgname)312*86d7f5d3SJohn Marino int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
313*86d7f5d3SJohn Marino {
314*86d7f5d3SJohn Marino 	struct stat info;
315*86d7f5d3SJohn Marino 	char path[PATH_MAX];
316*86d7f5d3SJohn Marino 
317*86d7f5d3SJohn Marino 	/* We'll allow operations on orphans */
318*86d7f5d3SJohn Marino 	if (is_orphan_vg(vgname))
319*86d7f5d3SJohn Marino 		return 1;
320*86d7f5d3SJohn Marino 
321*86d7f5d3SJohn Marino 	/* LVM1 is only present in 2.4 kernels. */
322*86d7f5d3SJohn Marino 	if (strncmp(cmd->kernel_vsn, "2.4.", 4))
323*86d7f5d3SJohn Marino 		return 1;
324*86d7f5d3SJohn Marino 
325*86d7f5d3SJohn Marino 	if (dm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
326*86d7f5d3SJohn Marino 			 vgname) < 0) {
327*86d7f5d3SJohn Marino 		log_error("LVM1 proc VG pathname too long for %s", vgname);
328*86d7f5d3SJohn Marino 		return 0;
329*86d7f5d3SJohn Marino 	}
330*86d7f5d3SJohn Marino 
331*86d7f5d3SJohn Marino 	if (stat(path, &info) == 0) {
332*86d7f5d3SJohn Marino 		log_error("%s exists: Is the original LVM driver using "
333*86d7f5d3SJohn Marino 			  "this volume group?", path);
334*86d7f5d3SJohn Marino 		return 0;
335*86d7f5d3SJohn Marino 	} else if (errno != ENOENT && errno != ENOTDIR) {
336*86d7f5d3SJohn Marino 		log_sys_error("stat", path);
337*86d7f5d3SJohn Marino 		return 0;
338*86d7f5d3SJohn Marino 	}
339*86d7f5d3SJohn Marino 
340*86d7f5d3SJohn Marino 	return 1;
341*86d7f5d3SJohn Marino }
342*86d7f5d3SJohn Marino 
343*86d7f5d3SJohn Marino /*
344*86d7f5d3SJohn Marino  * VG locking is by VG name.
345*86d7f5d3SJohn Marino  * FIXME This should become VG uuid.
346*86d7f5d3SJohn Marino  */
_lock_vol(struct cmd_context * cmd,const char * resource,uint32_t flags,lv_operation_t lv_op)347*86d7f5d3SJohn Marino static int _lock_vol(struct cmd_context *cmd, const char *resource,
348*86d7f5d3SJohn Marino 		     uint32_t flags, lv_operation_t lv_op)
349*86d7f5d3SJohn Marino {
350*86d7f5d3SJohn Marino 	int ret = 0;
351*86d7f5d3SJohn Marino 
352*86d7f5d3SJohn Marino 	_block_signals(flags);
353*86d7f5d3SJohn Marino 	_lock_memory(lv_op);
354*86d7f5d3SJohn Marino 
355*86d7f5d3SJohn Marino 	assert(resource);
356*86d7f5d3SJohn Marino 
357*86d7f5d3SJohn Marino 	if (!*resource) {
358*86d7f5d3SJohn Marino 		log_error("Internal error: Use of P_orphans is deprecated.");
359*86d7f5d3SJohn Marino 		return 0;
360*86d7f5d3SJohn Marino 	}
361*86d7f5d3SJohn Marino 
362*86d7f5d3SJohn Marino 	if (*resource == '#' && (flags & LCK_CACHE)) {
363*86d7f5d3SJohn Marino 		log_error("Internal error: P_%s referenced", resource);
364*86d7f5d3SJohn Marino 		return 0;
365*86d7f5d3SJohn Marino 	}
366*86d7f5d3SJohn Marino 
367*86d7f5d3SJohn Marino 	if ((ret = _locking.lock_resource(cmd, resource, flags))) {
368*86d7f5d3SJohn Marino 		if ((flags & LCK_SCOPE_MASK) == LCK_VG &&
369*86d7f5d3SJohn Marino 		    !(flags & LCK_CACHE)) {
370*86d7f5d3SJohn Marino 			if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
371*86d7f5d3SJohn Marino 				lvmcache_unlock_vgname(resource);
372*86d7f5d3SJohn Marino 			else
373*86d7f5d3SJohn Marino 				lvmcache_lock_vgname(resource, (flags & LCK_TYPE_MASK)
374*86d7f5d3SJohn Marino 								== LCK_READ);
375*86d7f5d3SJohn Marino 		}
376*86d7f5d3SJohn Marino 
377*86d7f5d3SJohn Marino 		_update_vg_lock_count(resource, flags);
378*86d7f5d3SJohn Marino 	}
379*86d7f5d3SJohn Marino 
380*86d7f5d3SJohn Marino 	_unlock_memory(lv_op);
381*86d7f5d3SJohn Marino 	_unblock_signals();
382*86d7f5d3SJohn Marino 
383*86d7f5d3SJohn Marino 	return ret;
384*86d7f5d3SJohn Marino }
385*86d7f5d3SJohn Marino 
lock_vol(struct cmd_context * cmd,const char * vol,uint32_t flags)386*86d7f5d3SJohn Marino int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
387*86d7f5d3SJohn Marino {
388*86d7f5d3SJohn Marino 	char resource[258] __attribute((aligned(8)));
389*86d7f5d3SJohn Marino 	lv_operation_t lv_op;
390*86d7f5d3SJohn Marino 
391*86d7f5d3SJohn Marino 	switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) {
392*86d7f5d3SJohn Marino 		case LCK_LV_SUSPEND:
393*86d7f5d3SJohn Marino 				lv_op = LV_SUSPEND;
394*86d7f5d3SJohn Marino 				break;
395*86d7f5d3SJohn Marino 		case LCK_LV_RESUME:
396*86d7f5d3SJohn Marino 				lv_op = LV_RESUME;
397*86d7f5d3SJohn Marino 				break;
398*86d7f5d3SJohn Marino 		default:	lv_op = LV_NOOP;
399*86d7f5d3SJohn Marino 	}
400*86d7f5d3SJohn Marino 
401*86d7f5d3SJohn Marino 
402*86d7f5d3SJohn Marino 	if (flags == LCK_NONE) {
403*86d7f5d3SJohn Marino 		log_debug("Internal error: %s: LCK_NONE lock requested", vol);
404*86d7f5d3SJohn Marino 		return 1;
405*86d7f5d3SJohn Marino 	}
406*86d7f5d3SJohn Marino 
407*86d7f5d3SJohn Marino 	switch (flags & LCK_SCOPE_MASK) {
408*86d7f5d3SJohn Marino 	case LCK_VG:
409*86d7f5d3SJohn Marino 		/*
410*86d7f5d3SJohn Marino 		 * Automatically set LCK_NONBLOCK if one or more VGs locked.
411*86d7f5d3SJohn Marino 		 * This will enforce correctness and prevent deadlocks rather
412*86d7f5d3SJohn Marino 		 * than relying on the caller to set the flag properly.
413*86d7f5d3SJohn Marino 		 */
414*86d7f5d3SJohn Marino 		if (!_blocking_supported || vgs_locked())
415*86d7f5d3SJohn Marino 			flags |= LCK_NONBLOCK;
416*86d7f5d3SJohn Marino 
417*86d7f5d3SJohn Marino 		if (vol[0] != '#' &&
418*86d7f5d3SJohn Marino 		    ((flags & LCK_TYPE_MASK) != LCK_UNLOCK) &&
419*86d7f5d3SJohn Marino 		    (!(flags & LCK_CACHE)) &&
420*86d7f5d3SJohn Marino 		    !lvmcache_verify_lock_order(vol))
421*86d7f5d3SJohn Marino 			return 0;
422*86d7f5d3SJohn Marino 
423*86d7f5d3SJohn Marino 		/* Lock VG to change on-disk metadata. */
424*86d7f5d3SJohn Marino 		/* If LVM1 driver knows about the VG, it can't be accessed. */
425*86d7f5d3SJohn Marino 		if (!check_lvm1_vg_inactive(cmd, vol))
426*86d7f5d3SJohn Marino 			return 0;
427*86d7f5d3SJohn Marino 		break;
428*86d7f5d3SJohn Marino 	case LCK_LV:
429*86d7f5d3SJohn Marino 		/* All LV locks are non-blocking. */
430*86d7f5d3SJohn Marino 		flags |= LCK_NONBLOCK;
431*86d7f5d3SJohn Marino 		break;
432*86d7f5d3SJohn Marino 	default:
433*86d7f5d3SJohn Marino 		log_error("Unrecognised lock scope: %d",
434*86d7f5d3SJohn Marino 			  flags & LCK_SCOPE_MASK);
435*86d7f5d3SJohn Marino 		return 0;
436*86d7f5d3SJohn Marino 	}
437*86d7f5d3SJohn Marino 
438*86d7f5d3SJohn Marino 	strncpy(resource, vol, sizeof(resource));
439*86d7f5d3SJohn Marino 
440*86d7f5d3SJohn Marino 	if (!_lock_vol(cmd, resource, flags, lv_op))
441*86d7f5d3SJohn Marino 		return 0;
442*86d7f5d3SJohn Marino 
443*86d7f5d3SJohn Marino 	/*
444*86d7f5d3SJohn Marino 	 * If a real lock was acquired (i.e. not LCK_CACHE),
445*86d7f5d3SJohn Marino 	 * perform an immediate unlock unless LCK_HOLD was requested.
446*86d7f5d3SJohn Marino 	 */
447*86d7f5d3SJohn Marino 	if (!(flags & LCK_CACHE) && !(flags & LCK_HOLD) &&
448*86d7f5d3SJohn Marino 	    ((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
449*86d7f5d3SJohn Marino 		if (!_lock_vol(cmd, resource,
450*86d7f5d3SJohn Marino 			       (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op))
451*86d7f5d3SJohn Marino 			return 0;
452*86d7f5d3SJohn Marino 	}
453*86d7f5d3SJohn Marino 
454*86d7f5d3SJohn Marino 	return 1;
455*86d7f5d3SJohn Marino }
456*86d7f5d3SJohn Marino 
457*86d7f5d3SJohn Marino /* Unlock list of LVs */
resume_lvs(struct cmd_context * cmd,struct dm_list * lvs)458*86d7f5d3SJohn Marino int resume_lvs(struct cmd_context *cmd, struct dm_list *lvs)
459*86d7f5d3SJohn Marino {
460*86d7f5d3SJohn Marino 	struct lv_list *lvl;
461*86d7f5d3SJohn Marino 
462*86d7f5d3SJohn Marino 	dm_list_iterate_items(lvl, lvs)
463*86d7f5d3SJohn Marino 		resume_lv(cmd, lvl->lv);
464*86d7f5d3SJohn Marino 
465*86d7f5d3SJohn Marino 	return 1;
466*86d7f5d3SJohn Marino }
467*86d7f5d3SJohn Marino 
468*86d7f5d3SJohn Marino /* Lock a list of LVs */
suspend_lvs(struct cmd_context * cmd,struct dm_list * lvs)469*86d7f5d3SJohn Marino int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs)
470*86d7f5d3SJohn Marino {
471*86d7f5d3SJohn Marino 	struct dm_list *lvh;
472*86d7f5d3SJohn Marino 	struct lv_list *lvl;
473*86d7f5d3SJohn Marino 
474*86d7f5d3SJohn Marino 	dm_list_iterate_items(lvl, lvs) {
475*86d7f5d3SJohn Marino 		if (!suspend_lv(cmd, lvl->lv)) {
476*86d7f5d3SJohn Marino 			log_error("Failed to suspend %s", lvl->lv->name);
477*86d7f5d3SJohn Marino 			dm_list_uniterate(lvh, lvs, &lvl->list) {
478*86d7f5d3SJohn Marino 				lvl = dm_list_item(lvh, struct lv_list);
479*86d7f5d3SJohn Marino 				resume_lv(cmd, lvl->lv);
480*86d7f5d3SJohn Marino 			}
481*86d7f5d3SJohn Marino 
482*86d7f5d3SJohn Marino 			return 0;
483*86d7f5d3SJohn Marino 		}
484*86d7f5d3SJohn Marino 	}
485*86d7f5d3SJohn Marino 
486*86d7f5d3SJohn Marino 	return 1;
487*86d7f5d3SJohn Marino }
488*86d7f5d3SJohn Marino 
489*86d7f5d3SJohn Marino /* Lock a list of LVs */
activate_lvs(struct cmd_context * cmd,struct dm_list * lvs,unsigned exclusive)490*86d7f5d3SJohn Marino int activate_lvs(struct cmd_context *cmd, struct dm_list *lvs, unsigned exclusive)
491*86d7f5d3SJohn Marino {
492*86d7f5d3SJohn Marino 	struct dm_list *lvh;
493*86d7f5d3SJohn Marino 	struct lv_list *lvl;
494*86d7f5d3SJohn Marino 
495*86d7f5d3SJohn Marino 	dm_list_iterate_items(lvl, lvs) {
496*86d7f5d3SJohn Marino 		if (!exclusive) {
497*86d7f5d3SJohn Marino 			if (!activate_lv(cmd, lvl->lv)) {
498*86d7f5d3SJohn Marino 				log_error("Failed to activate %s", lvl->lv->name);
499*86d7f5d3SJohn Marino 				return 0;
500*86d7f5d3SJohn Marino 			}
501*86d7f5d3SJohn Marino 		} else if (!activate_lv_excl(cmd, lvl->lv)) {
502*86d7f5d3SJohn Marino 			log_error("Failed to activate %s", lvl->lv->name);
503*86d7f5d3SJohn Marino 			dm_list_uniterate(lvh, lvs, &lvl->list) {
504*86d7f5d3SJohn Marino 				lvl = dm_list_item(lvh, struct lv_list);
505*86d7f5d3SJohn Marino 				activate_lv(cmd, lvl->lv);
506*86d7f5d3SJohn Marino 			}
507*86d7f5d3SJohn Marino 			return 0;
508*86d7f5d3SJohn Marino 		}
509*86d7f5d3SJohn Marino 	}
510*86d7f5d3SJohn Marino 
511*86d7f5d3SJohn Marino 	return 1;
512*86d7f5d3SJohn Marino }
513*86d7f5d3SJohn Marino 
vg_write_lock_held(void)514*86d7f5d3SJohn Marino int vg_write_lock_held(void)
515*86d7f5d3SJohn Marino {
516*86d7f5d3SJohn Marino 	return _vg_write_lock_held;
517*86d7f5d3SJohn Marino }
518*86d7f5d3SJohn Marino 
locking_is_clustered(void)519*86d7f5d3SJohn Marino int locking_is_clustered(void)
520*86d7f5d3SJohn Marino {
521*86d7f5d3SJohn Marino 	return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
522*86d7f5d3SJohn Marino }
523*86d7f5d3SJohn Marino 
remote_lock_held(const char * vol)524*86d7f5d3SJohn Marino int remote_lock_held(const char *vol)
525*86d7f5d3SJohn Marino {
526*86d7f5d3SJohn Marino 	int mode = LCK_NULL;
527*86d7f5d3SJohn Marino 
528*86d7f5d3SJohn Marino 	if (!locking_is_clustered())
529*86d7f5d3SJohn Marino 		return 0;
530*86d7f5d3SJohn Marino 
531*86d7f5d3SJohn Marino 	if (!_locking.query_resource)
532*86d7f5d3SJohn Marino 		return -1;
533*86d7f5d3SJohn Marino 
534*86d7f5d3SJohn Marino 	/*
535*86d7f5d3SJohn Marino 	 * If an error occured, expect that volume is active
536*86d7f5d3SJohn Marino 	 */
537*86d7f5d3SJohn Marino 	if (!_locking.query_resource(vol, &mode)) {
538*86d7f5d3SJohn Marino 		stack;
539*86d7f5d3SJohn Marino 		return 1;
540*86d7f5d3SJohn Marino 	}
541*86d7f5d3SJohn Marino 
542*86d7f5d3SJohn Marino 	return mode == LCK_NULL ? 0 : 1;
543*86d7f5d3SJohn Marino }
544