diff options
author | Patrick Caulfield <pcaulfie@redhat.com> | 2001-12-03 11:06:13 +0000 |
---|---|---|
committer | Patrick Caulfield <pcaulfie@redhat.com> | 2001-12-03 11:06:13 +0000 |
commit | 2ddd6ebf79291611a1f72040f54c3bdd9f2d640a (patch) | |
tree | 77479e999cb31af1c656e498d5f6000c4b0407ea | |
parent | 4da649182fd36393760165d0a35b6aad963bc75b (diff) | |
download | lvm2-2ddd6ebf79291611a1f72040f54c3bdd9f2d640a.tar.gz |
Add local lockfile-based locking
-rw-r--r-- | lib/cmgr/cmgr.c | 164 | ||||
-rw-r--r-- | lib/cmgr/cmgr.h | 9 |
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 */ |