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