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