summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Caulfield <pcaulfie@redhat.com>2001-12-03 11:06:13 +0000
committerPatrick Caulfield <pcaulfie@redhat.com>2001-12-03 11:06:13 +0000
commit2ddd6ebf79291611a1f72040f54c3bdd9f2d640a (patch)
tree77479e999cb31af1c656e498d5f6000c4b0407ea
parent4da649182fd36393760165d0a35b6aad963bc75b (diff)
downloadlvm2-2ddd6ebf79291611a1f72040f54c3bdd9f2d640a.tar.gz
Add local lockfile-based locking
-rw-r--r--lib/cmgr/cmgr.c164
-rw-r--r--lib/cmgr/cmgr.h9
2 files changed, 160 insertions, 13 deletions
diff --git a/lib/cmgr/cmgr.c b/lib/cmgr/cmgr.c
index 9f5145e39..ec9cae92f 100644
--- a/lib/cmgr/cmgr.c
+++ b/lib/cmgr/cmgr.c
@@ -39,8 +39,9 @@
/* This gets stuck at the start of memory we allocate so we
can sanity-check it at deallocation time */
#define LVM_SIGNATURE 0x434C564D
-
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
+#define LVM_GLOBAL_LOCK "LVM_GLOBAL"
+#define LOCKFILE_DIR "/var/lock/lvm"
/* NOTE: the LVMD uses the socket FD as the client ID, this means
that any client that calls fork() will inherit the context of
@@ -313,10 +314,136 @@ int cluster_free_request(lvm_response_t *response)
}
+
+static pid_t locked_by(char *lockfile_name)
+{
+ /* Check lock is not stale - the file should contain
+ the owners PID */
+ FILE *f = fopen(lockfile_name, "r");
+ pid_t pid = 0;
+
+ if (f)
+ {
+ char proc_pid[PATH_MAX];
+ struct stat st;
+
+ /* Normal practice to to kill -0 the process at this point
+ but we may not have the privilege */
+ fscanf(f, "%d\n", &pid);
+ fclose(f);
+
+ snprintf(proc_pid, sizeof(proc_pid), "/proc/%d", pid);
+ if (stat(proc_pid, &st) == 0)
+ {
+ /* Process exists - lock is valid. */
+ return pid;
+ }
+ /* Remove stale lock file */
+ unlink(lockfile_name);
+ }
+
+ /* Not locked */
+ return -1;
+}
+
+
+/* LOCK resource using a file */
+static int lock_resource(char *resource, int mode, int flags, int *lockid)
+{
+ struct stat;
+ int fd;
+ char lockfile_name[PATH_MAX];
+ mode_t old_umask;
+ FILE *pidfile;
+ int ret = -1;
+ int ret_errno;
+
+ if (mode != LKM_EXMODE)
+ {
+ ret_errno = EINVAL;
+ goto lock_finish;
+ }
+
+ old_umask = umask(000);
+
+ ret_errno = -EPERM;
+ if (mkdir(LOCKFILE_DIR, 0777) != 0)
+ if (errno != EEXIST)
+ goto lock_finish;
+
+ /* Make the lockfile name */
+ snprintf(lockfile_name, sizeof(lockfile_name), LOCKFILE_DIR "/%s", resource);
+
+ /* Keep trying to lock untill we succeed
+ unless LKM_NONBLOCK was requested */
+ do
+ {
+ fd = open(lockfile_name, O_CREAT|O_EXCL|O_WRONLY, 0666);
+ if (fd == -1)
+ {
+ pid_t owner_pid;
+
+ /* Is the permission on the directory correct ? */
+ if (errno == EPERM)
+ goto lock_finish;
+
+ owner_pid = locked_by(lockfile_name);
+ /* If it's locked and the caller doesn't want to block then return */
+ if (owner_pid > 0 && (flags & O_NONBLOCK))
+ {
+ ret_errno = EAGAIN;
+ goto lock_finish;
+ }
+
+ /* If it's locked, then wait and try again in a second,
+ Ugh, need directrory notification */
+ if (owner_pid > 0)
+ {
+ sleep(1);
+ }
+ }
+ }
+ while (fd < 0);
+
+ /* OK - lock it */
+ pidfile = fdopen(fd, "w");
+ if (pidfile)
+ {
+ fprintf(pidfile, "%d\n", getpid());
+ fclose(pidfile);
+ ret = 0;
+ }
+
+lock_finish:
+ umask(old_umask);
+ errno = ret_errno;
+ return ret;
+}
+
+
+static int unlock_resource(char *resource, int lockid)
+{
+ char lockfile_name[PATH_MAX];
+ pid_t owner_pid;
+
+ snprintf(lockfile_name, sizeof(lockfile_name), LOCKFILE_DIR "/%s", resource);
+
+ owner_pid = locked_by(lockfile_name);
+
+ /* Is it locked by us ? */
+ if (owner_pid != getpid())
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ unlink(lockfile_name);
+ return 0;
+}
+
+
/* These are a "higher-level" API providing black-box lock/unlock
functions for cluster LVM...maybe */
-
/* Set by lock(), used by unlock() */
static int num_responses;
static lvm_response_t *response;
@@ -493,6 +620,7 @@ int unlock_for_cluster(char scope, char *name, int namelen, int suspend)
/* Keep track of the current request state */
static int clustered = 0;
static int suspended = 0;
+static int lockid;
/* Lock the whole system */
int lock_lvm(int suspend)
@@ -508,8 +636,11 @@ int lock_lvm(int suspend)
if (errno == ENOENT)
{
clustered = 0;
- /* TODO: Local Lock
- suspend everything */
+ status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
+ if (!status)
+ return status;
+
+ /* TODO: suspend? */
return 0;
}
clustered = 1;
@@ -524,9 +655,8 @@ int unlock_lvm()
{
if (!clustered)
{
- /* TODO: Local unlock
- resume all */
- return 0;
+ /* TODO: resume? */
+ return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
@@ -549,7 +679,12 @@ int lock_vg(struct volume_group *vg, int suspend)
if (errno == ENOENT)
{
clustered = 0;
- /* TODO: Local Lock */
+
+ /* Get LVM lock */
+ status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
+ if (!status)
+ return status;
+
if (suspend) suspend_lvs_in_vg(vg, 1);
return 0;
}
@@ -566,8 +701,7 @@ int unlock_vg(struct volume_group *vg)
if (!clustered)
{
activate_lvs_in_vg(vg);
- /* TODO Local Unlock */
- return 0;
+ return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
@@ -588,8 +722,13 @@ int lock_lv(struct logical_volume *lv, int suspend)
/* TODO: May need some way of forcing this to fail in the future */
if (errno == ENOENT)
{
- /* TODO: Local lock */
clustered = 0;
+
+ /* Get LVM lock */
+ status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
+ if (!status)
+ return status;
+
if (suspend) lv_suspend(lv, 1);
return 0;
}
@@ -606,8 +745,7 @@ int unlock_lv(struct logical_volume *lv)
if (!clustered)
{
lv_reactivate(lv);
- /* TODO Local Unlock */
- return 0;
+ return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
diff --git a/lib/cmgr/cmgr.h b/lib/cmgr/cmgr.h
index 405981993..e08f0e9e2 100644
--- a/lib/cmgr/cmgr.h
+++ b/lib/cmgr/cmgr.h
@@ -41,3 +41,12 @@ extern int unlock_vg(struct volume_group *vg);
using these */
extern int get_lv_open_count(struct logical_volume *lv, int *open_count);
extern int get_vg_active_count(struct volume_group *vg, int *active_count);
+
+/* Lock modes: these are taken from the IBM DLM,
+ but we only support EX! */
+#define LKM_NLMODE 0 /* null lock */
+#define LKM_CRMODE 1 /* concurrent read */
+#define LKM_CWMODE 2 /* concurrent write */
+#define LKM_PRMODE 3 /* protected read */
+#define LKM_PWMODE 4 /* protected write */
+#define LKM_EXMODE 5 /* exclusive */