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