locking.c revision 1.1.1.3 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