Home | History | Annotate | Line # | Download | only in locking
      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 
     53 static void _catch_sigint(int unused __attribute__((unused)))
     54 {
     55 	_sigint_caught = 1;
     56 }
     57 
     58 int sigint_caught(void) {
     59 	return _sigint_caught;
     60 }
     61 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    304 void fin_locking(void)
    305 {
    306 	_locking.fin_locking();
    307 }
    308 
    309 /*
    310  * Does the LVM1 driver know of this VG name?
    311  */
    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  */
    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 
    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 */
    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 */
    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 */
    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 
    514 int vg_write_lock_held(void)
    515 {
    516 	return _vg_write_lock_held;
    517 }
    518 
    519 int locking_is_clustered(void)
    520 {
    521 	return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
    522 }
    523 
    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