summaryrefslogtreecommitdiffstats
path: root/lib/locking/file_locking.c
diff options
context:
space:
mode:
authorPetr Rockai <prockai@redhat.com>2009-08-13 13:23:51 +0000
committerPetr Rockai <prockai@redhat.com>2009-08-13 13:23:51 +0000
commit5d5e2bf8f64ff468c80f27af548094ee12f9e6fc (patch)
tree38bc2b2283d9605f616b028ca720e8795a244fd7 /lib/locking/file_locking.c
parent004c103c205c19229ac657da7961c0f89d6e8fca (diff)
downloadlvm2-5d5e2bf8f64ff468c80f27af548094ee12f9e6fc.tar.gz
lvm2-5d5e2bf8f64ff468c80f27af548094ee12f9e6fc.tar.xz
lvm2-5d5e2bf8f64ff468c80f27af548094ee12f9e6fc.zip
Refactor file locking, lifting the flock wrapper code into separate
functions. Also fixes a bug, where a nonblocking lock could, in certain race situations, succeed without actually obtaining the lock.
Diffstat (limited to 'lib/locking/file_locking.c')
-rw-r--r--lib/locking/file_locking.c124
1 files changed, 70 insertions, 54 deletions
diff --git a/lib/locking/file_locking.c b/lib/locking/file_locking.c
index e2055779..0e1e8124 100644
--- a/lib/locking/file_locking.c
+++ b/lib/locking/file_locking.c
@@ -43,13 +43,26 @@ static sig_t _oldhandler;
static sigset_t _fullsigset, _intsigset;
static volatile sig_atomic_t _handler_installed;
+static void _undo_flock(const char *file, int fd)
+{
+ struct stat buf1, buf2;
+
+ if (!flock(fd, LOCK_NB | LOCK_EX) &&
+ !stat(file, &buf1) &&
+ !fstat(fd, &buf2) &&
+ is_same_inode(buf1, buf2))
+ if (unlink(file))
+ log_sys_error("unlink", file);
+
+ if (close(fd) < 0)
+ log_sys_error("close", file);
+}
+
static int _release_lock(const char *file, int unlock)
{
struct lock_list *ll;
struct dm_list *llh, *llt;
- struct stat buf1, buf2;
-
dm_list_iterate_safe(llh, llt, &_lock_list) {
ll = dm_list_item(llh, struct lock_list);
@@ -61,15 +74,7 @@ static int _release_lock(const char *file, int unlock)
log_sys_error("flock", ll->res);
}
- if (!flock(ll->lf, LOCK_NB | LOCK_EX) &&
- !stat(ll->res, &buf1) &&
- !fstat(ll->lf, &buf2) &&
- is_same_inode(buf1, buf2))
- if (unlink(ll->res))
- log_sys_error("unlink", ll->res);
-
- if (close(ll->lf) < 0)
- log_sys_error("close", ll->res);
+ _undo_flock(ll->res, ll->lf);
dm_free(ll->res);
dm_free(llh);
@@ -124,14 +129,53 @@ static void _install_ctrl_c_handler()
siginterrupt(SIGINT, 1);
}
-static int _lock_file(const char *file, uint32_t flags)
+static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
{
- int operation;
int r = 1;
int old_errno;
+ struct stat buf1, buf2;
+
+ do {
+ if ((*fd > -1) && close(*fd))
+ log_sys_error("close", file);
+
+ if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
+ log_sys_error("open", file);
+ return 0;
+ }
+
+ if (nonblock)
+ operation |= LOCK_NB;
+ else
+ _install_ctrl_c_handler();
+
+ r = flock(*fd, operation);
+ old_errno = errno;
+ if (!nonblock)
+ _remove_ctrl_c_handler();
+
+ if (r) {
+ errno = old_errno;
+ log_sys_error("flock", file);
+ close(*fd);
+ return 0;
+ }
+
+ if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
+ is_same_inode(buf1, buf2))
+ return 1;
+ } while (!nonblock);
+
+ return_0;
+}
+
+static int _lock_file(const char *file, uint32_t flags)
+{
+ int operation;
+ uint32_t nonblock = flags & LCK_NONBLOCK;
+ int r;
struct lock_list *ll;
- struct stat buf1, buf2;
char state;
switch (flags & LCK_TYPE_MASK) {
@@ -151,56 +195,28 @@ static int _lock_file(const char *file, uint32_t flags)
}
if (!(ll = dm_malloc(sizeof(struct lock_list))))
- return 0;
+ return_0;
if (!(ll->res = dm_strdup(file))) {
dm_free(ll);
- return 0;
+ return_0;
}
ll->lf = -1;
log_very_verbose("Locking %s %c%c", ll->res, state,
- flags & LCK_NONBLOCK ? ' ' : 'B');
- do {
- if ((ll->lf > -1) && close(ll->lf))
- log_sys_error("close", file);
-
- if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
- < 0) {
- log_sys_error("open", file);
- goto err;
- }
+ nonblock ? ' ' : 'B');
- if ((flags & LCK_NONBLOCK))
- operation |= LOCK_NB;
- else
- _install_ctrl_c_handler();
-
- r = flock(ll->lf, operation);
- old_errno = errno;
- if (!(flags & LCK_NONBLOCK))
- _remove_ctrl_c_handler();
-
- if (r) {
- errno = old_errno;
- log_sys_error("flock", ll->res);
- close(ll->lf);
- goto err;
- }
-
- if (!stat(ll->res, &buf1) && !fstat(ll->lf, &buf2) &&
- is_same_inode(buf1, buf2))
- break;
- } while (!(flags & LCK_NONBLOCK));
-
- dm_list_add(&_lock_list, &ll->list);
- return 1;
+ r = _do_flock(file, &ll->lf, operation, nonblock);
+ if (r)
+ dm_list_add(&_lock_list, &ll->list);
+ else {
+ dm_free(ll->res);
+ dm_free(ll);
+ stack;
+ }
- err:
- dm_free(ll->res);
- dm_free(ll);
- return 0;
+ return r;
}
static int _file_lock_resource(struct cmd_context *cmd, const char *resource,