1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/lib/locking/file_locking.c
Alasdair Kergon 7d0e6e800e o Support locking with local lock files
o Disable control-c during updates (except if blocked waiting for a lock)
2002-02-11 15:42:34 +00:00

194 lines
3.5 KiB
C

/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "log.h"
#include "locking.h"
#include "locking_types.h"
#include "activate.h"
#include "config.h"
#include "defaults.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <signal.h>
struct lock_list {
struct list list;
int lf;
char *res;
};
static struct list _lock_list;
static char _lock_dir[NAME_LEN];
static int _release_lock(const char *file)
{
struct lock_list *ll;
struct list *llh, *llt;
list_iterate_safe(llh, llt, &_lock_list) {
ll = list_item(llh, struct lock_list);
if (!file || !strcmp(ll->res, file)) {
list_del(llh);
log_very_verbose("Unlocking %s", ll->res);
/*
* If this is the last pid using the file, remove it
*/
if (!flock(ll->lf, LOCK_NB | LOCK_EX))
if (unlink(ll->res))
log_sys_error("unlink", ll->res);
if (close(ll->lf) < 0)
log_sys_error("close", ll->res);
dbg_free(ll->res);
dbg_free(llh);
if (file)
return 1;
}
}
return 0;
}
void fin_file_locking(void)
{
_release_lock(NULL);
}
void _trap_ctrl_c(int signal)
{
log_error("CTRL-c detected: giving up waiting for lock");
return;
}
static void _install_ctrl_c_handler()
{
siginterrupt(SIGINT, 1);
signal(SIGINT, _trap_ctrl_c);
}
static void _remove_ctrl_c_handler()
{
signal(SIGINT, SIG_IGN);
siginterrupt(SIGINT, 0);
}
static int _lock_file(const char *file, int flags)
{
int operation;
int r = 1;
struct lock_list *ll;
switch (flags & LCK_TYPE_MASK) {
case LCK_READ:
operation = LOCK_SH;
break;
case LCK_WRITE:
operation = LOCK_EX;
break;
case LCK_NONE:
return _release_lock(file);
default:
log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
return 0;
}
if (!(ll = dbg_malloc(sizeof(struct lock_list))))
return 0;
if (!(ll->res = dbg_strdup(file))) {
dbg_free(ll);
return 0;
}
log_very_verbose("Locking %s", ll->res);
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
log_sys_error("open", file);
dbg_free(ll->res);
dbg_free(ll);
return 0;
}
if ((flags & LCK_NONBLOCK))
operation |= LOCK_NB;
else
_install_ctrl_c_handler();
if (flock(ll->lf, operation)) {
log_sys_error("flock", ll->res);
dbg_free(ll->res);
dbg_free(ll);
r = 0;
} else
list_add(&_lock_list, &ll->list);
if (!(flags & LCK_NONBLOCK))
_remove_ctrl_c_handler();
return r;
}
int lock_resource(const char *resource, int flags)
{
char lockfile[PATH_MAX];
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG:
if (!resource || !*resource)
lvm_snprintf(lockfile, sizeof(lockfile),
"%s/P_orphans", _lock_dir);
else
lvm_snprintf(lockfile, sizeof(lockfile),
"%s/V_%s", _lock_dir, resource);
break;
case LCK_LV:
/* No-op for now */
return 1;
default:
log_error("Unrecognised lock scope: %d",
flags & LCK_SCOPE_MASK);
return 0;
}
if (!_lock_file(lockfile, flags))
return 0;
return 1;
}
int init_file_locking(struct locking_type *locking, struct config_file *cf)
{
locking->lock_resource = lock_resource;
locking->fin_locking = fin_file_locking;
/* Get lockfile directory from config file */
strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir",
'/', DEFAULT_LOCK_DIR),
sizeof(_lock_dir));
if (!create_dir(_lock_dir))
return 0;
list_init(&_lock_list);
return 1;
}