2
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3
* Copyright (C) 2004-2014 Red Hat, Inc. All rights reserved.
5
* This file is part of LVM2.
7
* This copyrighted material is made available to anyone wishing to use,
8
* modify, copy, or redistribute it subject to the terms and conditions
9
* of the GNU Lesser General Public License v.2.1.
11
* You should have received a copy of the GNU Lesser General Public License
12
* along with this program; if not, write to the Free Software Foundation,
13
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
#include "lvm-flock.h"
20
#include "lvm-signal.h"
32
static struct dm_list _lock_list;
33
static int _prioritise_write_locks;
35
/* Drop lock known to be shared with another file descriptor. */
36
static void _drop_shared_flock(const char *file, int fd)
38
log_debug_locking("_drop_shared_flock %s.", file);
41
log_sys_debug("close", file);
44
static void _undo_flock(const char *file, int fd)
46
struct stat buf1, buf2;
48
log_debug_locking("_undo_flock %s", file);
49
if (!flock(fd, LOCK_NB | LOCK_EX) &&
52
is_same_inode(buf1, buf2))
54
log_sys_debug("unlink", file);
57
log_sys_debug("close", file);
60
static int _release_lock(const char *file, int unlock)
63
struct dm_list *llh, *llt;
65
dm_list_iterate_safe(llh, llt, &_lock_list) {
66
ll = dm_list_item(llh, struct lock_list);
68
if (!file || !strcmp(ll->res, file)) {
71
log_very_verbose("Unlocking %s", ll->res);
72
if (flock(ll->lf, LOCK_NB | LOCK_UN))
73
log_sys_debug("flock", ll->res);
74
_undo_flock(ll->res, ll->lf);
76
_drop_shared_flock(ll->res, ll->lf);
89
void release_flocks(int unlock)
91
_release_lock(NULL, unlock);
94
static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
98
struct stat buf1, buf2;
100
log_debug_locking("_do_flock %s %c%c", file,
101
operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B');
103
if ((*fd > -1) && close(*fd))
104
log_sys_debug("close", file);
106
if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
107
log_sys_error("open", file);
112
operation |= LOCK_NB;
116
r = flock(*fd, operation);
121
log_error("Giving up waiting for lock.");
126
log_sys_error("flock", file);
128
log_sys_debug("close", file);
133
if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
134
is_same_inode(buf1, buf2))
141
#define AUX_LOCK_SUFFIX ":aux"
143
static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
146
char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX));
148
strcpy(file_aux, file);
149
strcat(file_aux, AUX_LOCK_SUFFIX);
151
if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
152
if (operation == LOCK_EX) {
153
r = _do_flock(file, fd, operation, nonblock);
154
_undo_flock(file_aux, fd_aux);
156
_undo_flock(file_aux, fd_aux);
157
r = _do_flock(file, fd, operation, nonblock);
164
int lock_file(const char *file, uint32_t flags)
167
uint32_t nonblock = flags & LCK_NONBLOCK;
170
struct lock_list *ll;
173
switch (flags & LCK_TYPE_MASK) {
183
return _release_lock(file, 1);
185
log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
189
if (!(ll = dm_malloc(sizeof(struct lock_list))))
192
if (!(ll->res = dm_strdup(file))) {
199
log_very_verbose("Locking %s %c%c", ll->res, state,
200
nonblock ? ' ' : 'B');
202
(void) dm_prepare_selinux_context(file, S_IFREG);
203
if (_prioritise_write_locks)
204
r = _do_write_priority_flock(file, &ll->lf, operation, nonblock);
206
r = _do_flock(file, &ll->lf, operation, nonblock);
207
(void) dm_prepare_selinux_context(NULL, 0);
210
dm_list_add(&_lock_list, &ll->list);
220
void init_flock(struct cmd_context *cmd)
222
dm_list_init(&_lock_list);
224
_prioritise_write_locks =
225
find_config_tree_bool(cmd, global_prioritise_write_locks_CFG, NULL);