4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
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.
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
20 #include "locking_types.h"
25 #include "lvm-string.h"
41 static struct dm_list _lock_list
;
42 static char _lock_dir
[NAME_LEN
];
43 static int _prioritise_write_locks
;
45 static sig_t _oldhandler
;
46 static sigset_t _fullsigset
, _intsigset
;
47 static volatile sig_atomic_t _handler_installed
;
49 static void _undo_flock(const char *file
, int fd
)
51 struct stat buf1
, buf2
;
53 log_debug("_undo_flock %s", file
);
54 if (!flock(fd
, LOCK_NB
| LOCK_EX
) &&
57 is_same_inode(buf1
, buf2
))
59 log_sys_error("unlink", file
);
62 log_sys_error("close", file
);
65 static int _release_lock(const char *file
, int unlock
)
68 struct dm_list
*llh
, *llt
;
70 dm_list_iterate_safe(llh
, llt
, &_lock_list
) {
71 ll
= dm_list_item(llh
, struct lock_list
);
73 if (!file
|| !strcmp(ll
->res
, file
)) {
76 log_very_verbose("Unlocking %s", ll
->res
);
77 if (flock(ll
->lf
, LOCK_NB
| LOCK_UN
))
78 log_sys_error("flock", ll
->res
);
81 _undo_flock(ll
->res
, ll
->lf
);
94 static void _fin_file_locking(void)
96 _release_lock(NULL
, 1);
99 static void _reset_file_locking(void)
101 _release_lock(NULL
, 0);
104 static void _remove_ctrl_c_handler(void)
106 siginterrupt(SIGINT
, 0);
107 if (!_handler_installed
)
110 _handler_installed
= 0;
112 sigprocmask(SIG_SETMASK
, &_fullsigset
, NULL
);
113 if (signal(SIGINT
, _oldhandler
) == SIG_ERR
)
114 log_sys_error("signal", "_remove_ctrl_c_handler");
117 static void _trap_ctrl_c(int sig
__attribute((unused
)))
119 _remove_ctrl_c_handler();
120 log_error("CTRL-c detected: giving up waiting for lock");
123 static void _install_ctrl_c_handler()
125 _handler_installed
= 1;
127 if ((_oldhandler
= signal(SIGINT
, _trap_ctrl_c
)) == SIG_ERR
) {
128 _handler_installed
= 0;
132 sigprocmask(SIG_SETMASK
, &_intsigset
, NULL
);
133 siginterrupt(SIGINT
, 1);
136 static int _do_flock(const char *file
, int *fd
, int operation
, uint32_t nonblock
)
140 struct stat buf1
, buf2
;
142 log_debug("_do_flock %s %c%c",
143 file
, operation
== LOCK_EX
? 'W' : 'R', nonblock
? ' ' : 'B');
145 if ((*fd
> -1) && close(*fd
))
146 log_sys_error("close", file
);
148 if ((*fd
= open(file
, O_CREAT
| O_APPEND
| O_RDWR
, 0777)) < 0) {
149 log_sys_error("open", file
);
154 operation
|= LOCK_NB
;
156 _install_ctrl_c_handler();
158 r
= flock(*fd
, operation
);
161 _remove_ctrl_c_handler();
165 log_sys_error("flock", file
);
170 if (!stat(file
, &buf1
) && !fstat(*fd
, &buf2
) &&
171 is_same_inode(buf1
, buf2
))
178 #define AUX_LOCK_SUFFIX ":aux"
180 static int _do_write_priority_flock(const char *file
, int *fd
, int operation
, uint32_t nonblock
)
183 char *file_aux
= alloca(strlen(file
) + sizeof(AUX_LOCK_SUFFIX
));
185 strcpy(file_aux
, file
);
186 strcat(file_aux
, AUX_LOCK_SUFFIX
);
188 if ((r
= _do_flock(file_aux
, &fd_aux
, LOCK_EX
, 0))) {
189 if (operation
== LOCK_EX
) {
190 r
= _do_flock(file
, fd
, operation
, nonblock
);
191 _undo_flock(file_aux
, fd_aux
);
193 _undo_flock(file_aux
, fd_aux
);
194 r
= _do_flock(file
, fd
, operation
, nonblock
);
201 static int _lock_file(const char *file
, uint32_t flags
)
204 uint32_t nonblock
= flags
& LCK_NONBLOCK
;
207 struct lock_list
*ll
;
210 switch (flags
& LCK_TYPE_MASK
) {
220 return _release_lock(file
, 1);
222 log_error("Unrecognised lock type: %d", flags
& LCK_TYPE_MASK
);
226 if (!(ll
= dm_malloc(sizeof(struct lock_list
))))
229 if (!(ll
->res
= dm_strdup(file
))) {
236 log_very_verbose("Locking %s %c%c", ll
->res
, state
,
237 nonblock
? ' ' : 'B');
239 if (_prioritise_write_locks
)
240 r
= _do_write_priority_flock(file
, &ll
->lf
, operation
, nonblock
);
242 r
= _do_flock(file
, &ll
->lf
, operation
, nonblock
);
245 dm_list_add(&_lock_list
, &ll
->list
);
255 static int _file_lock_resource(struct cmd_context
*cmd
, const char *resource
,
258 char lockfile
[PATH_MAX
];
260 switch (flags
& LCK_SCOPE_MASK
) {
262 /* Skip cache refresh for VG_GLOBAL - the caller handles it */
263 if (strcmp(resource
, VG_GLOBAL
))
264 lvmcache_drop_metadata(resource
);
266 /* LCK_CACHE does not require a real lock */
267 if (flags
& LCK_CACHE
)
270 if (*resource
== '#')
271 dm_snprintf(lockfile
, sizeof(lockfile
),
272 "%s/P_%s", _lock_dir
, resource
+ 1);
274 dm_snprintf(lockfile
, sizeof(lockfile
),
275 "%s/V_%s", _lock_dir
, resource
);
277 if (!_lock_file(lockfile
, flags
))
281 switch (flags
& LCK_TYPE_MASK
) {
283 log_very_verbose("Unlocking LV %s", resource
);
284 if (!lv_resume_if_active(cmd
, resource
))
288 log_very_verbose("Locking LV %s (NL)", resource
);
289 if (!lv_deactivate(cmd
, resource
))
293 log_very_verbose("Locking LV %s (R)", resource
);
294 if (!lv_activate_with_filter(cmd
, resource
, 0))
298 log_very_verbose("Locking LV %s (PR) - ignored", resource
);
301 log_very_verbose("Locking LV %s (W)", resource
);
302 if (!lv_suspend_if_active(cmd
, resource
))
306 log_very_verbose("Locking LV %s (EX)", resource
);
307 if (!lv_activate_with_filter(cmd
, resource
, 1))
315 log_error("Unrecognised lock scope: %d",
316 flags
& LCK_SCOPE_MASK
);
323 int init_file_locking(struct locking_type
*locking
, struct cmd_context
*cmd
)
325 locking
->lock_resource
= _file_lock_resource
;
326 locking
->reset_locking
= _reset_file_locking
;
327 locking
->fin_locking
= _fin_file_locking
;
330 /* Get lockfile directory from config file */
331 strncpy(_lock_dir
, find_config_tree_str(cmd
, "global/locking_dir",
335 _prioritise_write_locks
=
336 find_config_tree_bool(cmd
, "global/prioritise_write_locks",
337 DEFAULT_PRIORITISE_WRITE_LOCKS
);
339 if (!dm_create_dir(_lock_dir
))
342 /* Trap a read-only file system */
343 if ((access(_lock_dir
, R_OK
| W_OK
| X_OK
) == -1) && (errno
== EROFS
))
346 dm_list_init(&_lock_list
);
348 if (sigfillset(&_intsigset
) || sigfillset(&_fullsigset
)) {
349 log_sys_error("sigfillset", "init_file_locking");
353 if (sigdelset(&_intsigset
, SIGINT
)) {
354 log_sys_error("sigdelset", "init_file_locking");