Gitweb:
http://git.fedorahosted.org/git/dlm.git?p=dlm.git;a=commitdiff;h=b440452a...
Commit: b440452a8a553e1b3df2a92144077ba4459688fc
Parent: 8d03f2e225d3a2109def78ddf9c7bed13575ea2e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Sep 30 16:48:57 2011 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Sep 30 16:54:07 2011 -0500
libdlm: move files
and new Makefile
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
dlm/libdlm/51-dlm.rules | 5 -
dlm/libdlm/libdlm.c | 1487 ------------------------------------
dlm/libdlm/libdlm.h | 275 -------
dlm/libdlm/libdlm_internal.h | 9 -
dlm/man/dlm_cleanup.3 | 1 -
dlm/man/dlm_close_lockspace.3 | 1 -
dlm/man/dlm_create_lockspace.3 | 94 ---
dlm/man/dlm_dispatch.3 | 1 -
dlm/man/dlm_get_fd.3 | 1 -
dlm/man/dlm_lock.3 | 239 ------
dlm/man/dlm_lock_wait.3 | 1 -
dlm/man/dlm_ls_lock.3 | 1 -
dlm/man/dlm_ls_lock_wait.3 | 1 -
dlm/man/dlm_ls_lockx.3 | 1 -
dlm/man/dlm_ls_pthread_init.3 | 1 -
dlm/man/dlm_ls_unlock.3 | 1 -
dlm/man/dlm_ls_unlock_wait.3 | 1 -
dlm/man/dlm_new_lockspace.3 | 1 -
dlm/man/dlm_open_lockspace.3 | 1 -
dlm/man/dlm_pthread_init.3 | 1 -
dlm/man/dlm_release_lockspace.3 | 1 -
dlm/man/dlm_unlock.3 | 94 ---
dlm/man/dlm_unlock_wait.3 | 1 -
dlm/man/libdlm.3 | 105 ---
libdlm/51-dlm.rules | 5 +
libdlm/Makefile | 117 +++
libdlm/libdlm.c | 1485 +++++++++++++++++++++++++++++++++++
libdlm/libdlm.h | 275 +++++++
libdlm/libdlm_internal.h | 9 +
libdlm/man/dlm_cleanup.3 | 1 +
libdlm/man/dlm_close_lockspace.3 | 1 +
libdlm/man/dlm_create_lockspace.3 | 94 +++
libdlm/man/dlm_dispatch.3 | 1 +
libdlm/man/dlm_get_fd.3 | 1 +
libdlm/man/dlm_lock.3 | 239 ++++++
libdlm/man/dlm_lock_wait.3 | 1 +
libdlm/man/dlm_ls_lock.3 | 1 +
libdlm/man/dlm_ls_lock_wait.3 | 1 +
libdlm/man/dlm_ls_lockx.3 | 1 +
libdlm/man/dlm_ls_pthread_init.3 | 1 +
libdlm/man/dlm_ls_unlock.3 | 1 +
libdlm/man/dlm_ls_unlock_wait.3 | 1 +
libdlm/man/dlm_new_lockspace.3 | 1 +
libdlm/man/dlm_open_lockspace.3 | 1 +
libdlm/man/dlm_pthread_init.3 | 1 +
libdlm/man/dlm_release_lockspace.3 | 1 +
libdlm/man/dlm_unlock.3 | 94 +++
libdlm/man/dlm_unlock_wait.3 | 1 +
libdlm/man/libdlm.3 | 105 +++
49 files changed, 2439 insertions(+), 2324 deletions(-)
diff --git a/dlm/libdlm/51-dlm.rules b/dlm/libdlm/51-dlm.rules
deleted file mode 100644
index f71e79d..0000000
--- a/dlm/libdlm/51-dlm.rules
+++ /dev/null
@@ -1,5 +0,0 @@
-KERNEL=="dlm-control", NAME="misc/dlm-control",
MODE="0666"
-KERNEL=="dlm-monitor", NAME="misc/dlm-monitor",
MODE="0666"
-KERNEL=="dlm_default", NAME="misc/dlm_default",
MODE="0666"
-KERNEL=="dlm_*", NAME="misc/%k", MODE="0660"
-
diff --git a/dlm/libdlm/libdlm.c b/dlm/libdlm/libdlm.c
deleted file mode 100644
index 823bb84..0000000
--- a/dlm/libdlm/libdlm.c
+++ /dev/null
@@ -1,1487 +0,0 @@
-#include "clusterautoconfig.h"
-
-#ifdef _REENTRANT
-#include <pthread.h>
-#endif
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <linux/major.h>
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-#include <linux/types.h>
-#include <linux/dlm.h>
-#define BUILDING_LIBDLM
-#include "libdlm.h"
-#include <linux/dlm_device.h>
-
-#define MISC_PREFIX "/dev/misc/"
-#define DLM_PREFIX "dlm_"
-#define DLM_MISC_PREFIX MISC_PREFIX DLM_PREFIX
-#define DLM_CONTROL_NAME "dlm-control"
-#define DLM_CONTROL_PATH MISC_PREFIX DLM_CONTROL_NAME
-#define DEFAULT_LOCKSPACE "default"
-
-/*
- * V5 of the dlm_device.h kernel/user interface structs
- */
-
-struct dlm_lock_params_v5 {
- __u8 mode;
- __u8 namelen;
- __u16 flags;
- __u32 lkid;
- __u32 parent;
- void *castparam;
- void *castaddr;
- void *bastparam;
- void *bastaddr;
- struct dlm_lksb *lksb;
- char lvb[DLM_USER_LVB_LEN];
- char name[0];
-};
-
-struct dlm_write_request_v5 {
- __u32 version[3];
- __u8 cmd;
- __u8 is64bit;
- __u8 unused[2];
-
- union {
- struct dlm_lock_params_v5 lock;
- struct dlm_lspace_params lspace;
- } i;
-};
-
-struct dlm_lock_result_v5 {
- __u32 length;
- void *user_astaddr;
- void *user_astparam;
- struct dlm_lksb *user_lksb;
- struct dlm_lksb lksb;
- __u8 bast_mode;
- __u8 unused[3];
- /* Offsets may be zero if no data is present */
- __u32 lvb_offset;
-};
-
-
-/*
- * One of these per lockspace in use by the application
- */
-
-struct dlm_ls_info {
- int fd;
-#ifdef _REENTRANT
- pthread_t tid;
-#else
- int tid;
-#endif
-};
-
-/*
- * The default lockspace.
- * I've resisted putting locking around this as the user should be
- * "sensible" and only do lockspace operations either in the
- * main thread or ... carefully...
- */
-
-static struct dlm_ls_info *default_ls = NULL;
-static int control_fd = -1;
-static struct dlm_device_version kernel_version;
-static int kernel_version_detected = 0;
-
-
-static int release_lockspace(uint32_t minor, uint32_t flags);
-
-
-static void ls_dev_name(const char *lsname, char *devname, int devlen)
-{
- snprintf(devname, devlen, DLM_MISC_PREFIX "%s", lsname);
-}
-
-static void dummy_ast_routine(void *arg)
-{
-}
-
-#ifdef _REENTRANT
-/* Used for the synchronous and "simplified, synchronous" API routines */
-struct lock_wait
-{
- pthread_cond_t cond;
- pthread_mutex_t mutex;
- struct dlm_lksb lksb;
-};
-
-static void sync_ast_routine(void *arg)
-{
- struct lock_wait *lwait = arg;
-
- pthread_mutex_lock(&lwait->mutex);
- pthread_cond_signal(&lwait->cond);
- pthread_mutex_unlock(&lwait->mutex);
-}
-
-/* lock_resource & unlock_resource
- * are the simplified, synchronous API.
- * Aways uses the default lockspace.
- */
-int lock_resource(const char *resource, int mode, int flags, int *lockid)
-{
- int status;
- struct lock_wait lwait;
-
- if (default_ls == NULL)
- {
- if (dlm_pthread_init())
- {
- return -1;
- }
- }
-
- if (!lockid)
- {
- errno = EINVAL;
- return -1;
- }
-
- /* Conversions need the lockid in the LKSB */
- if (flags & LKF_CONVERT)
- lwait.lksb.sb_lkid = *lockid;
-
- pthread_cond_init(&lwait.cond, NULL);
- pthread_mutex_init(&lwait.mutex, NULL);
- pthread_mutex_lock(&lwait.mutex);
-
- status = dlm_lock(mode,
- &lwait.lksb,
- flags,
- resource,
- strlen(resource),
- 0,
- sync_ast_routine,
- &lwait,
- NULL,
- NULL);
- if (status)
- return status;
-
- /* Wait for it to complete */
- pthread_cond_wait(&lwait.cond, &lwait.mutex);
- pthread_mutex_unlock(&lwait.mutex);
-
- *lockid = lwait.lksb.sb_lkid;
-
- errno = lwait.lksb.sb_status;
- if (lwait.lksb.sb_status)
- return -1;
- else
- return 0;
-}
-
-
-int unlock_resource(int lockid)
-{
- int status;
- struct lock_wait lwait;
-
- if (default_ls == NULL)
- {
- errno = -ENOTCONN;
- return -1;
- }
-
- pthread_cond_init(&lwait.cond, NULL);
- pthread_mutex_init(&lwait.mutex, NULL);
- pthread_mutex_lock(&lwait.mutex);
-
- status = dlm_unlock(lockid, 0, &lwait.lksb, &lwait);
-
- if (status)
- return status;
-
- /* Wait for it to complete */
- pthread_cond_wait(&lwait.cond, &lwait.mutex);
- pthread_mutex_unlock(&lwait.mutex);
-
- errno = lwait.lksb.sb_status;
- if (lwait.lksb.sb_status != DLM_EUNLOCK)
- return -1;
- else
- return 0;
-}
-
-/* Tidy up threads after a lockspace is closed */
-static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
-{
- int status = 0;
- int fd;
-
- /* Must close the fd after the thread has finished */
- fd = lsinfo->fd;
- if (lsinfo->tid)
- {
- status = pthread_cancel(lsinfo->tid);
- if (!status)
- pthread_join(lsinfo->tid, NULL);
- }
- if (!status)
- {
- free(lsinfo);
- close(fd);
- }
-
- return status;
-}
-
-/* Cleanup default lockspace */
-int dlm_pthread_cleanup(void)
-{
- struct dlm_ls_info *lsinfo = default_ls;
-
- /* Protect users from their own stupidity */
- if (!lsinfo)
- return 0;
-
- default_ls = NULL;
-
- return ls_pthread_cleanup(lsinfo);
-}
-#else
-
-/* Non-pthread version of cleanup */
-static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
-{
- close(lsinfo->fd);
- free(lsinfo);
- return 0;
-}
-#endif
-
-
-static void set_version_v5(struct dlm_write_request_v5 *req)
-{
- req->version[0] = kernel_version.version[0];
- req->version[1] = kernel_version.version[1];
- req->version[2] = kernel_version.version[2];
- if (sizeof(long) == sizeof(long long))
- req->is64bit = 1;
- else
- req->is64bit = 0;
-}
-
-static void set_version_v6(struct dlm_write_request *req)
-{
- req->version[0] = kernel_version.version[0];
- req->version[1] = kernel_version.version[1];
- req->version[2] = kernel_version.version[2];
- if (sizeof(long) == sizeof(long long))
- req->is64bit = 1;
- else
- req->is64bit = 0;
-}
-
-static int open_default_lockspace(void)
-{
- if (!default_ls) {
- dlm_lshandle_t ls;
-
- /* This isn't the race it looks, create_lockspace will
- * do the right thing if the lockspace has already been
- * created.
- */
-
- ls = dlm_open_lockspace(DEFAULT_LOCKSPACE);
- if (!ls)
- ls = dlm_create_lockspace(DEFAULT_LOCKSPACE, 0600);
- if (!ls)
- return -1;
-
- default_ls = (struct dlm_ls_info *)ls;
- }
- return 0;
-}
-
-static void detect_kernel_version(void)
-{
- struct dlm_device_version v;
- int rv;
-
- rv = read(control_fd, &v, sizeof(struct dlm_device_version));
- if (rv < 0) {
- kernel_version.version[0] = 5;
- kernel_version.version[1] = 0;
- kernel_version.version[2] = 0;
- } else {
- kernel_version.version[0] = v.version[0];
- kernel_version.version[1] = v.version[1];
- kernel_version.version[2] = v.version[2];
- }
-
- kernel_version_detected = 1;
-}
-
-static int find_control_minor(int *minor)
-{
- FILE *f;
- char name[256];
- int found = 0, m = 0;
-
- f = fopen("/proc/misc", "r");
- if (!f)
- return -1;
-
- while (!feof(f)) {
- if (fscanf(f, "%d %s", &m, name) != 2)
- continue;
- if (strcmp(name, DLM_CONTROL_NAME))
- continue;
- found = 1;
- break;
- }
- fclose(f);
-
- if (found) {
- *minor = m;
- return 0;
- }
- return -1;
-}
-
-static int open_control_device(void)
-{
- struct stat st;
- int i, rv, minor, found = 0;
-
- if (control_fd > -1)
- goto out;
-
- rv = find_control_minor(&minor);
- if (rv < 0)
- return -1;
-
- /* wait for udev to create the device */
-
- for (i = 0; i < 10; i++) {
- if (stat(DLM_CONTROL_PATH, &st) == 0 &&
- minor(st.st_rdev) == minor) {
- found = 1;
- break;
- }
- sleep(1);
- continue;
- }
-
- if (!found)
- return -1;
-
- control_fd = open(DLM_CONTROL_PATH, O_RDWR);
- if (control_fd == -1)
- return -1;
-
- out:
- fcntl(control_fd, F_SETFD, 1);
-
- if (!kernel_version_detected)
- detect_kernel_version();
- return 0;
-}
-
-/* the max number of characters in a sysfs device name, not including \0 */
-#define MAX_SYSFS_NAME 19
-
-static int find_udev_device(const char *lockspace, int minor, char *udev_path)
-{
- char basename[PATH_MAX];
- char tmp_path[PATH_MAX];
- DIR *d;
- struct dirent *de;
- struct stat st;
- size_t basename_len;
- int i;
-
- ls_dev_name(lockspace, udev_path, PATH_MAX);
- snprintf(basename, PATH_MAX, DLM_PREFIX "%s", lockspace);
- basename_len = strlen(basename);
-
- for (i = 0; i < 10; i++) {
-
- /* look for a device with the full name */
-
- if (stat(udev_path, &st) == 0 && minor(st.st_rdev) == minor)
- return 0;
-
- if (basename_len < MAX_SYSFS_NAME) {
- sleep(1);
- continue;
- }
-
- /* look for a device with a truncated name */
-
- d = opendir(MISC_PREFIX);
- while ((de = readdir(d))) {
- if (de->d_name[0] == '.')
- continue;
- if (strlen(de->d_name) < MAX_SYSFS_NAME)
- continue;
- if (strncmp(de->d_name, basename, MAX_SYSFS_NAME))
- continue;
- snprintf(tmp_path, PATH_MAX, MISC_PREFIX "%s",
- de->d_name);
- if (stat(tmp_path, &st))
- continue;
- if (minor(st.st_rdev) != minor)
- continue;
-
- /* truncated name */
- strncpy(udev_path, tmp_path, PATH_MAX);
- closedir(d);
- return 0;
- }
- closedir(d);
- sleep(1);
- }
-
- return -1;
-}
-
-/*
- * do_dlm_dispatch()
- * Read an ast from the kernel.
- */
-
-static int do_dlm_dispatch_v5(int fd)
-{
- char resultbuf[sizeof(struct dlm_lock_result_v5) + DLM_USER_LVB_LEN];
- struct dlm_lock_result_v5 *result = (struct dlm_lock_result_v5 *)resultbuf;
- char *fullresult = NULL;
- int status;
- void (*astaddr)(void *astarg);
-
- status = read(fd, result, sizeof(resultbuf));
- if (status <= 0)
- return -1;
-
- /* This shouldn't happen any more, can probably be removed */
-
- if (result->length != status) {
- int newstat;
-
- fullresult = malloc(result->length);
- if (!fullresult)
- return -1;
-
- newstat = read(fd, (struct dlm_lock_result_v5 *)fullresult,
- result->length);
-
- /* If it read OK then use the new data. otherwise we can
- still deliver the AST, it just might not have all the
- info in it...hmmm */
-
- if (newstat == result->length)
- result = (struct dlm_lock_result_v5 *)fullresult;
- } else {
- fullresult = resultbuf;
- }
-
-
- /* Copy lksb to user's buffer - except the LVB ptr */
- memcpy(result->user_lksb, &result->lksb,
- sizeof(struct dlm_lksb) - sizeof(char*));
-
- /* Flip the status. Kernel space likes negative return codes,
- userspace positive ones */
- result->user_lksb->sb_status = -result->user_lksb->sb_status;
-
- /* Copy optional items */
- if (result->lvb_offset)
- memcpy(result->user_lksb->sb_lvbptr,
- fullresult + result->lvb_offset, DLM_LVB_LEN);
-
- /* Call AST */
- if (result->user_astaddr) {
- astaddr = result->user_astaddr;
- astaddr(result->user_astparam);
- }
-
- if (fullresult != resultbuf)
- free(fullresult);
-
- return 0;
-}
-
-static int do_dlm_dispatch_v6(int fd)
-{
- char resultbuf[sizeof(struct dlm_lock_result) + DLM_USER_LVB_LEN];
- struct dlm_lock_result *result = (struct dlm_lock_result *)resultbuf;
- int status;
- void (*astaddr)(void *astarg);
-
- status = read(fd, result, sizeof(resultbuf));
- if (status <= 0)
- return -1;
-
- /* Copy lksb to user's buffer - except the LVB ptr */
- memcpy(result->user_lksb, &result->lksb,
- sizeof(struct dlm_lksb) - sizeof(char*));
-
- /* Copy lvb to user's buffer */
- if (result->lvb_offset)
- memcpy(result->user_lksb->sb_lvbptr,
- (char *)result + result->lvb_offset, DLM_LVB_LEN);
-
- result->user_lksb->sb_status = -result->user_lksb->sb_status;
-
- if (result->user_astaddr) {
- astaddr = result->user_astaddr;
- astaddr(result->user_astparam);
- }
-
- return 0;
-}
-
-static int do_dlm_dispatch(int fd)
-{
- if (kernel_version.version[0] == 5)
- return do_dlm_dispatch_v5(fd);
- else
- return do_dlm_dispatch_v6(fd);
-}
-
-
-/*
- * sync_write()
- * Helper routine which supports the synchronous DLM calls. This
- * writes a parameter block down to the DLM and waits for the
- * operation to complete. This hides the different completion mechanism
- * used when called from the main thread or the DLM 'AST' thread.
- */
-
-#ifdef _REENTRANT
-
-static int sync_write_v5(struct dlm_ls_info *lsinfo,
- struct dlm_write_request_v5 *req, int len)
-{
- struct lock_wait lwait;
- int status;
-
- if (pthread_self() == lsinfo->tid) {
- /* This is the DLM worker thread, don't use lwait to sync */
- req->i.lock.castaddr = dummy_ast_routine;
- req->i.lock.castparam = NULL;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- while (req->i.lock.lksb->sb_status == EINPROG) {
- do_dlm_dispatch_v5(lsinfo->fd);
- }
- } else {
- pthread_cond_init(&lwait.cond, NULL);
- pthread_mutex_init(&lwait.mutex, NULL);
- pthread_mutex_lock(&lwait.mutex);
-
- req->i.lock.castaddr = sync_ast_routine;
- req->i.lock.castparam = &lwait;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- pthread_cond_wait(&lwait.cond, &lwait.mutex);
- pthread_mutex_unlock(&lwait.mutex);
- }
-
- return status; /* lock status is in the lksb */
-}
-
-static int sync_write_v6(struct dlm_ls_info *lsinfo,
- struct dlm_write_request *req, int len)
-{
- struct lock_wait lwait;
- int status;
-
- if (pthread_self() == lsinfo->tid) {
- /* This is the DLM worker thread, don't use lwait to sync */
- req->i.lock.castaddr = dummy_ast_routine;
- req->i.lock.castparam = NULL;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- while (req->i.lock.lksb->sb_status == EINPROG) {
- do_dlm_dispatch_v6(lsinfo->fd);
- }
- } else {
- pthread_cond_init(&lwait.cond, NULL);
- pthread_mutex_init(&lwait.mutex, NULL);
- pthread_mutex_lock(&lwait.mutex);
-
- req->i.lock.castaddr = sync_ast_routine;
- req->i.lock.castparam = &lwait;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- pthread_cond_wait(&lwait.cond, &lwait.mutex);
- pthread_mutex_unlock(&lwait.mutex);
- }
-
- return status; /* lock status is in the lksb */
-}
-
-#else /* _REENTRANT */
-
-static int sync_write_v5(struct dlm_ls_info *lsinfo,
- struct dlm_write_request_v5 *req, int len)
-{
- int status;
-
- req->i.lock.castaddr = dummy_ast_routine;
- req->i.lock.castparam = NULL;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- while (req->i.lock.lksb->sb_status == EINPROG) {
- do_dlm_dispatch_v5(lsinfo->fd);
- }
-
- errno = req->i.lock.lksb->sb_status;
- if (errno && errno != EUNLOCK)
- return -1;
- return 0;
-}
-
-static int sync_write_v6(struct dlm_ls_info *lsinfo,
- struct dlm_write_request *req, int len)
-{
- int status;
-
- req->i.lock.castaddr = dummy_ast_routine;
- req->i.lock.castparam = NULL;
-
- status = write(lsinfo->fd, req, len);
- if (status < 0)
- return -1;
-
- while (req->i.lock.lksb->sb_status == EINPROG) {
- do_dlm_dispatch_v6(lsinfo->fd);
- }
-
- errno = req->i.lock.lksb->sb_status;
- if (errno && errno != EUNLOCK)
- return -1;
- return 0;
-}
-
-#endif /* _REENTRANT */
-
-
-/*
- * Lock
- * All the ways to request/convert a lock
- */
-
-static int ls_lock_v5(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg))
-{
- char parambuf[sizeof(struct dlm_write_request_v5) + DLM_RESNAME_MAXLEN];
- struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)parambuf;
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- int status;
- int len;
-
- memset(req, 0, sizeof(*req));
- set_version_v5(req);
-
- req->cmd = DLM_USER_LOCK;
- req->i.lock.mode = mode;
- req->i.lock.flags = (flags & ~LKF_WAIT);
- req->i.lock.lkid = lksb->sb_lkid;
- req->i.lock.parent = parent;
- req->i.lock.lksb = lksb;
- req->i.lock.castaddr = astaddr;
- req->i.lock.bastaddr = bastaddr;
- req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
- req->i.lock.bastparam = astarg;
-
- if (flags & LKF_CONVERT) {
- req->i.lock.namelen = 0;
- } else {
- if (namelen > DLM_RESNAME_MAXLEN) {
- errno = EINVAL;
- return -1;
- }
- req->i.lock.namelen = namelen;
- memcpy(req->i.lock.name, name, namelen);
- }
-
- if (flags & LKF_VALBLK) {
- memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
- }
-
- len = sizeof(struct dlm_write_request_v5) + namelen;
- lksb->sb_status = EINPROG;
-
- if (flags & LKF_WAIT)
- status = sync_write_v5(lsinfo, req, len);
- else
- status = write(lsinfo->fd, req, len);
-
- if (status < 0)
- return -1;
-
- /*
- * the lock id is the return value from the write on the device
- */
-
- if (status > 0)
- lksb->sb_lkid = status;
- return 0;
-}
-
-static int ls_lock_v6(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- uint64_t *xid,
- uint64_t *timeout)
-{
- char parambuf[sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN];
- struct dlm_write_request *req = (struct dlm_write_request *)parambuf;
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- int status;
- int len;
-
- memset(req, 0, sizeof(*req));
- set_version_v6(req);
-
- req->cmd = DLM_USER_LOCK;
- req->i.lock.mode = mode;
- req->i.lock.flags = (flags & ~LKF_WAIT);
- req->i.lock.lkid = lksb->sb_lkid;
- req->i.lock.parent = parent;
- req->i.lock.lksb = lksb;
- req->i.lock.castaddr = astaddr;
- req->i.lock.bastaddr = bastaddr;
- req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
- req->i.lock.bastparam = astarg;
-
- if (xid)
- req->i.lock.xid = *xid;
- if (timeout)
- req->i.lock.timeout = *timeout;
-
- if (flags & LKF_CONVERT) {
- req->i.lock.namelen = 0;
- } else {
- if (namelen > DLM_RESNAME_MAXLEN) {
- errno = EINVAL;
- return -1;
- }
- req->i.lock.namelen = namelen;
- memcpy(req->i.lock.name, name, namelen);
- }
-
- if (flags & LKF_VALBLK) {
- memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
- }
-
- len = sizeof(struct dlm_write_request) + namelen;
- lksb->sb_status = EINPROG;
-
- if (flags & LKF_WAIT)
- status = sync_write_v6(lsinfo, req, len);
- else
- status = write(lsinfo->fd, req, len);
-
- if (status < 0)
- return -1;
-
- /*
- * the lock id is the return value from the write on the device
- */
-
- if (status > 0)
- lksb->sb_lkid = status;
- return 0;
-}
-
-static int ls_lock(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range)
-{
- /* no support for range locks */
- if (range) {
- errno = ENOSYS;
- return -1;
- }
-
- if (flags & LKF_VALBLK && !lksb->sb_lvbptr) {
- errno = EINVAL;
- return -1;
- }
-
- if (kernel_version.version[0] == 5)
- return ls_lock_v5(ls, mode, lksb, flags, name, namelen, parent,
- astaddr, astarg, bastaddr);
- else
- return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
- astaddr, astarg, bastaddr, NULL, NULL);
-}
-
-/*
- * Extended async locking in own lockspace
- */
-int dlm_ls_lockx(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- uint64_t *xid,
- uint64_t *timeout)
-{
- if (kernel_version.version[0] < 6) {
- errno = ENOSYS;
- return -1;
- }
-
- return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
- astaddr, astarg, bastaddr, xid, timeout);
-}
-
-/*
- * Async locking in own lockspace
- */
-int dlm_ls_lock(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range)
-{
- return ls_lock(ls, mode, lksb, flags, name, namelen, parent,
- astaddr, astarg, bastaddr, range);
-}
-
-/*
- * Sync locking in own lockspace
- */
-int dlm_ls_lock_wait(dlm_lshandle_t ls,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range)
-{
- return ls_lock(ls, mode, lksb, flags | LKF_WAIT, name, namelen, parent,
- NULL, bastarg, bastaddr, range);
-}
-
-/*
- * Async locking in the default lockspace
- */
-int dlm_lock(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range)
-{
- if (open_default_lockspace())
- return -1;
-
- return ls_lock(default_ls, mode, lksb, flags, name, namelen, parent,
- astaddr, astarg, bastaddr, range);
-}
-
-/*
- * Sync locking in the default lockspace
- */
-int dlm_lock_wait(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent,
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range)
-{
- if (open_default_lockspace())
- return -1;
-
- return ls_lock(default_ls, mode, lksb, flags | LKF_WAIT, name, namelen,
- parent, NULL, bastarg, bastaddr, range);
-}
-
-
-/*
- * Unlock
- * All the ways to unlock/cancel a lock
- */
-
-static int ls_unlock_v5(struct dlm_ls_info *lsinfo, uint32_t lkid,
- uint32_t flags, struct dlm_lksb *lksb, void *astarg)
-{
- struct dlm_write_request_v5 req;
-
- set_version_v5(&req);
- req.cmd = DLM_USER_UNLOCK;
- req.i.lock.lkid = lkid;
- req.i.lock.flags = (flags & ~LKF_WAIT);
- req.i.lock.lksb = lksb;
- req.i.lock.castparam = astarg;
- /* DLM_USER_UNLOCK will default to existing completion AST */
- req.i.lock.castaddr = 0;
- lksb->sb_status = EINPROG;
-
- if (flags & LKF_WAIT)
- return sync_write_v5(lsinfo, &req, sizeof(req));
- else
- return write(lsinfo->fd, &req, sizeof(req));
-}
-
-static int ls_unlock_v6(struct dlm_ls_info *lsinfo, uint32_t lkid,
- uint32_t flags, struct dlm_lksb *lksb, void *astarg)
-{
- struct dlm_write_request req;
-
- set_version_v6(&req);
- req.cmd = DLM_USER_UNLOCK;
- req.i.lock.lkid = lkid;
- req.i.lock.flags = (flags & ~LKF_WAIT);
- req.i.lock.lksb = lksb;
- req.i.lock.namelen = 0;
- req.i.lock.castparam = astarg;
- /* DLM_USER_UNLOCK will default to existing completion AST */
- req.i.lock.castaddr = 0;
- lksb->sb_status = EINPROG;
-
- if (flags & LKF_WAIT)
- return sync_write_v6(lsinfo, &req, sizeof(req));
- else
- return write(lsinfo->fd, &req, sizeof(req));
-}
-
-int dlm_ls_unlock(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
- struct dlm_lksb *lksb, void *astarg)
-{
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- int status;
-
- if (ls == NULL) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!lkid) {
- errno = EINVAL;
- return -1;
- }
-
- if (kernel_version.version[0] == 5)
- status = ls_unlock_v5(lsinfo, lkid, flags, lksb, astarg);
- else
- status = ls_unlock_v6(lsinfo, lkid, flags, lksb, astarg);
-
- if (status < 0)
- return -1;
- return 0;
-}
-
-int dlm_ls_unlock_wait(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
- struct dlm_lksb *lksb)
-{
- return dlm_ls_unlock(ls, lkid, flags | LKF_WAIT, lksb, NULL);
-}
-
-int dlm_unlock_wait(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb)
-{
- return dlm_ls_unlock_wait(default_ls, lkid, flags | LKF_WAIT, lksb);
-}
-
-int dlm_unlock(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb,
- void *astarg)
-{
- return dlm_ls_unlock(default_ls, lkid, flags, lksb, astarg);
-}
-
-int dlm_ls_deadlock_cancel(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags)
-{
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- struct dlm_write_request req;
-
- if (kernel_version.version[0] < 6) {
- errno = ENOSYS;
- return -1;
- }
-
- if (ls == NULL) {
- errno = ENOTCONN;
- return -1;
- }
-
- if (!lkid) {
- errno = EINVAL;
- return -1;
- }
-
- set_version_v6(&req);
- req.cmd = DLM_USER_DEADLOCK;
- req.i.lock.lkid = lkid;
- req.i.lock.flags = flags;
-
- return write(lsinfo->fd, &req, sizeof(req));
-}
-
-
-/*
- * Purge
- * Clear away orphan locks
- */
-
-int dlm_ls_purge(dlm_lshandle_t ls, int nodeid, int pid)
-{
- struct dlm_write_request req;
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- int status;
-
- if (kernel_version.version[0] < 6) {
- errno = ENOSYS;
- return -1;
- }
-
- if (ls == NULL) {
- errno = ENOTCONN;
- return -1;
- }
-
- set_version_v6(&req);
- req.cmd = DLM_USER_PURGE;
- req.i.purge.nodeid = nodeid;
- req.i.purge.pid = pid;
-
- status = write(lsinfo->fd, &req, sizeof(req));
-
- if (status < 0)
- return -1;
- return 0;
-}
-
-
-/* These two routines for for users that want to
- * do their own fd handling.
- * This allows a non-threaded app to use the DLM.
- */
-int dlm_get_fd(void)
-{
- if (default_ls)
- {
- return default_ls->fd;
- }
- else
- {
- if (open_default_lockspace())
- return -1;
- else
- return default_ls->fd;
- }
-}
-
-int dlm_dispatch(int fd)
-{
- int status;
- int fdflags;
-
- fdflags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, fdflags | O_NONBLOCK);
- do
- {
- status = do_dlm_dispatch(fd);
- } while (status == 0);
-
- /* EAGAIN is not an error */
- if (status < 0 && errno == EAGAIN)
- status = 0;
-
- fcntl(fd, F_SETFL, fdflags);
- return status;
-}
-
-/* Converts a lockspace handle into a file descriptor */
-int dlm_ls_get_fd(dlm_lshandle_t lockspace)
-{
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)lockspace;
-
- return lsinfo->fd;
-}
-
-#ifdef _REENTRANT
-static void *dlm_recv_thread(void *lsinfo)
-{
- struct dlm_ls_info *lsi = lsinfo;
-
- for (;;)
- do_dlm_dispatch(lsi->fd);
-
- return NULL;
-}
-
-/* Multi-threaded callers normally use this */
-int dlm_pthread_init(void)
-{
- if (open_default_lockspace())
- return -1;
-
- if (default_ls->tid)
- {
- errno = EEXIST;
- return -1;
- }
-
- if (pthread_create(&default_ls->tid, NULL, dlm_recv_thread, default_ls))
- {
- int saved_errno = errno;
- close(default_ls->fd);
- free(default_ls);
- default_ls = NULL;
- errno = saved_errno;
- return -1;
- }
- return 0;
-}
-
-/* And same, for those with their own lockspace */
-int dlm_ls_pthread_init(dlm_lshandle_t ls)
-{
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
-
- if (lsinfo->tid)
- {
- errno = EEXIST;
- return -1;
- }
-
- return pthread_create(&lsinfo->tid, NULL, dlm_recv_thread, (void *)ls);
-}
-#endif
-
-/*
- * Lockspace manipulation functions
- * Privileged users (checked by the kernel) can create/release lockspaces
- */
-
-static int create_lockspace_v5(const char *name, uint32_t flags)
-{
- char reqbuf[sizeof(struct dlm_write_request_v5) + DLM_LOCKSPACE_LEN];
- struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)reqbuf;
- int namelen = strlen(name);
- int minor;
-
- memset(reqbuf, 0, sizeof(reqbuf));
- set_version_v5(req);
-
- req->cmd = DLM_USER_CREATE_LOCKSPACE;
- req->i.lspace.flags = flags;
-
- if (namelen > DLM_LOCKSPACE_LEN) {
- errno = EINVAL;
- return -1;
- }
- memcpy(req->i.lspace.name, name, namelen);
-
- minor = write(control_fd, req, sizeof(*req) + namelen);
-
- return minor;
-}
-
-static int create_lockspace_v6(const char *name, uint32_t flags)
-{
- char reqbuf[sizeof(struct dlm_write_request) + DLM_LOCKSPACE_LEN];
- struct dlm_write_request *req = (struct dlm_write_request *)reqbuf;
- int namelen = strlen(name);
- int minor;
-
- memset(reqbuf, 0, sizeof(reqbuf));
- set_version_v6(req);
-
- req->cmd = DLM_USER_CREATE_LOCKSPACE;
- req->i.lspace.flags = flags;
-
- if (namelen > DLM_LOCKSPACE_LEN) {
- errno = EINVAL;
- return -1;
- }
- memcpy(req->i.lspace.name, name, namelen);
-
- minor = write(control_fd, req, sizeof(*req) + namelen);
-
- return minor;
-}
-
-static dlm_lshandle_t create_lockspace(const char *name, mode_t mode,
- uint32_t flags)
-{
- char dev_path[PATH_MAX];
- char udev_path[PATH_MAX];
- struct dlm_ls_info *newls;
- int error, saved_errno, minor;
-
- /* We use the control device for creating lockspaces. */
- if (open_control_device())
- return NULL;
-
- newls = malloc(sizeof(struct dlm_ls_info));
- if (!newls)
- return NULL;
-
- ls_dev_name(name, dev_path, sizeof(dev_path));
-
- if (kernel_version.version[0] == 5)
- minor = create_lockspace_v5(name, flags);
- else
- minor = create_lockspace_v6(name, flags);
-
- if (minor < 0)
- goto fail;
-
- /* Wait for udev to create the device; the device it creates may
- have a truncated name due to the sysfs device name limit. */
-
- error = find_udev_device(name, minor, udev_path);
- if (error)
- goto fail;
-
- /* If the symlink already exists, find_udev_device() will return
- it and we'll skip this. */
-
- if (strcmp(dev_path, udev_path)) {
- error = symlink(udev_path, dev_path);
- if (error)
- goto fail;
- }
-
- /* Open it and return the struct as a handle */
-
- newls->fd = open(dev_path, O_RDWR);
- if (newls->fd == -1)
- goto fail;
- if (mode)
- fchmod(newls->fd, mode);
- newls->tid = 0;
- fcntl(newls->fd, F_SETFD, 1);
- return (dlm_lshandle_t)newls;
-
- fail:
- saved_errno = errno;
- free(newls);
- errno = saved_errno;
- return NULL;
-}
-
-dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags)
-{
- return create_lockspace(name, mode, flags);
-}
-
-dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode)
-{
- return create_lockspace(name, mode, 0);
-}
-
-static int release_lockspace_v5(uint32_t minor, uint32_t flags)
-{
- struct dlm_write_request_v5 req;
-
- set_version_v5(&req);
- req.cmd = DLM_USER_REMOVE_LOCKSPACE;
- req.i.lspace.minor = minor;
- req.i.lspace.flags = flags;
-
- return write(control_fd, &req, sizeof(req));
-}
-
-static int release_lockspace_v6(uint32_t minor, uint32_t flags)
-{
- struct dlm_write_request req;
-
- set_version_v6(&req);
- req.cmd = DLM_USER_REMOVE_LOCKSPACE;
- req.i.lspace.minor = minor;
- req.i.lspace.flags = flags;
-
- return write(control_fd, &req, sizeof(req));
-}
-
-static int release_lockspace(uint32_t minor, uint32_t flags)
-{
- if (kernel_version.version[0] == 5)
- return release_lockspace_v5(minor, flags);
- else
- return release_lockspace_v6(minor, flags);
-}
-
-int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force)
-{
- char dev_path[PATH_MAX];
- struct stat st;
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
- uint32_t flags = 0;
- int fd, is_symlink = 0;
-
- ls_dev_name(name, dev_path, sizeof(dev_path));
- if (!lstat(dev_path, &st) && S_ISLNK(st.st_mode))
- is_symlink = 1;
-
- /* We need the minor number */
- if (fstat(lsinfo->fd, &st))
- return -1;
-
- /* Close the lockspace first if it's in use */
- ls_pthread_cleanup(lsinfo);
-
- if (open_control_device())
- return -1;
-
- if (force)
- flags = DLM_USER_LSFLG_FORCEFREE;
-
- release_lockspace(minor(st.st_rdev), flags);
-
- if (!is_symlink)
- return 0;
-
- /* The following open is used to detect if our release was the last.
- It will fail if our release was the last, because either:
- . udev has already removed the truncated sysfs device name (ENOENT)
- . the misc device has been deregistered in the kernel (ENODEV)
- (the deregister completes before release returns)
-
- So, if the open fails, we know that our release was the last,
- udev will be removing the device with the truncated name (if it
- hasn't already), and we should remove the symlink. */
-
- fd = open(dev_path, O_RDWR);
- if (fd < 0)
- unlink(dev_path);
- else
- close(fd); /* our release was not the last */
-
- return 0;
-}
-
-/*
- * Normal users just open/close lockspaces
- */
-
-dlm_lshandle_t dlm_open_lockspace(const char *name)
-{
- char dev_name[PATH_MAX];
- struct dlm_ls_info *newls;
- int saved_errno;
-
- /* Need to detect kernel version */
- if (open_control_device())
- return NULL;
-
- newls = malloc(sizeof(struct dlm_ls_info));
- if (!newls)
- return NULL;
-
- newls->tid = 0;
- ls_dev_name(name, dev_name, sizeof(dev_name));
-
- newls->fd = open(dev_name, O_RDWR);
- saved_errno = errno;
-
- if (newls->fd == -1) {
- free(newls);
- errno = saved_errno;
- return NULL;
- }
- fcntl(newls->fd, F_SETFD, 1);
- return (dlm_lshandle_t)newls;
-}
-
-int dlm_close_lockspace(dlm_lshandle_t ls)
-{
- struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
-
- ls_pthread_cleanup(lsinfo);
- return 0;
-}
-
-int dlm_kernel_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
-{
- if (open_control_device())
- return -1;
- *major = kernel_version.version[0];
- *minor = kernel_version.version[1];
- *patch = kernel_version.version[2];
- return 0;
-}
-
-void dlm_library_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
-{
- *major = DLM_DEVICE_VERSION_MAJOR;
- *minor = DLM_DEVICE_VERSION_MINOR;
- *patch = DLM_DEVICE_VERSION_PATCH;
-}
-
diff --git a/dlm/libdlm/libdlm.h b/dlm/libdlm/libdlm.h
deleted file mode 100644
index 17a552c..0000000
--- a/dlm/libdlm/libdlm.h
+++ /dev/null
@@ -1,275 +0,0 @@
-#ifndef __LIBDLM_H
-#define __LIBDLM_H
-
-/*
- * Typedefs for things that are compatible with the kernel but replicated here
- * so that users only need the libdlm include file. libdlm itself needs the
- * full kernel file so shouldn't use these.
- */
-
-#define DLM_LVB_LEN 32
-
-#ifndef BUILDING_LIBDLM
-
-/*
- * These two lengths are copied from linux/dlmconstants.h
- * They are the max length of a lockspace name and the max length of a
- * resource name.
- */
-
-#define DLM_LOCKSPACE_LEN 64
-#define DLM_RESNAME_MAXLEN 64
-
-struct dlm_lksb {
- int sb_status;
- uint32_t sb_lkid;
- char sb_flags;
- char *sb_lvbptr;
-};
-
-/* lksb flags */
-#define DLM_SBF_DEMOTED 0x01
-#define DLM_SBF_VALNOTVALID 0x02
-#define DLM_SBF_ALTMODE 0x04
-
-/* dlm_new_lockspace flags */
-#define DLM_LSFL_NODIR 0x00000001
-#define DLM_LSFL_TIMEWARN 0x00000002
-#define DLM_LSFL_FS 0x00000004
-#define DLM_LSFL_NEWEXCL 0x00000008
-
-#endif
-
-
-#if 0
-/* Dummy definition to keep linkages */
-struct dlm_queryinfo;
-#endif
-
-extern int dlm_kernel_version(uint32_t *maj, uint32_t *min, uint32_t *patch);
-extern void dlm_library_version(uint32_t *maj, uint32_t *min, uint32_t *patch);
-
-
-/*
- * Using the default lockspace
- *
- * lock_resource() - simple sync request or convert (requires pthreads)
- * unlock_resource() - simple sync unlock (requires pthreads)
- * dlm_lock() - async request or convert
- * dlm_unlock() - async unlock or cancel
- * dlm_lock_wait() - sync request or convert
- * dlm_unlock_wait() - sync unlock or cancel
- */
-
-#ifdef _REENTRANT
-extern int lock_resource(const char *resource, int mode, int flags, int *lockid);
-extern int unlock_resource(int lockid);
-#endif
-
-extern int dlm_lock(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unusued */
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range); /* unused */
-
-extern int dlm_unlock(uint32_t lkid,
- uint32_t flags,
- struct dlm_lksb *lksb,
- void *astarg);
-
-extern int dlm_lock_wait(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range); /* unused */
-
-extern int dlm_unlock_wait(uint32_t lkid,
- uint32_t flags,
- struct dlm_lksb *lksb);
-
-
-/*
- * These two are for users that want to do their own FD handling
- *
- * dlm_get_fd() - returns fd for the default lockspace for polling and dispatch
- * dlm_dispatch() - dispatches pending asts and basts
- */
-
-extern int dlm_get_fd(void);
-extern int dlm_dispatch(int fd);
-
-
-/*
- * Creating your own lockspace
- *
- * dlm_create_lockspace() - create and open a lockspace and return a handle
- * to it. Privileges are required to create/release.
- * dlm_new_lockspace() - same as create but allows flags
- * dlm_open_lockspace() - simply returns a handle for an existing lockspace and
- * may be called by ordinary users.
- * dlm_release_lockspace()
- * dlm_close_lockspace()
- * dlm_ls_get_fd()
- *
- * NOTE: that if you dlm_create_lockspace() then dlm_open_lockspace() you will
- * have two open files on the same device. Hardly a major problem but I thought
- * it worth pointing out.
- */
-
-typedef void *dlm_lshandle_t;
-
-extern dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
-extern int dlm_release_lockspace(const char *name, dlm_lshandle_t ls,
- int force);
-extern dlm_lshandle_t dlm_open_lockspace(const char *name);
-extern int dlm_close_lockspace(dlm_lshandle_t ls);
-extern int dlm_ls_get_fd(dlm_lshandle_t ls);
-extern dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode,
- uint32_t flags);
-
-
-/*
- * Using your own lockspace
- *
- * dlm_ls_lock()
- * dlm_ls_lockx()
- * dlm_ls_unlock()
- * dlm_ls_lock_wait()
- * dlm_ls_unlock_wait()
- * dlm_ls_deadlock_cancel()
- * dlm_ls_purge()
- */
-
-extern int dlm_ls_lock(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range); /* unused */
-
-extern int dlm_ls_lockx(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- uint64_t *xid,
- uint64_t *timeout);
-
-extern int dlm_ls_unlock(dlm_lshandle_t lockspace,
- uint32_t lkid,
- uint32_t flags,
- struct dlm_lksb *lksb,
- void *astarg);
-
-extern int dlm_ls_lock_wait(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range); /* unused */
-
-extern int dlm_ls_unlock_wait(dlm_lshandle_t lockspace,
- uint32_t lkid,
- uint32_t flags,
- struct dlm_lksb *lksb);
-
-extern int dlm_ls_deadlock_cancel(dlm_lshandle_t ls,
- uint32_t lkid,
- uint32_t flags);
-
-extern int dlm_ls_purge(dlm_lshandle_t lockspace,
- int nodeid,
- int pid);
-
-
-/*
- * For threaded applications
- *
- * dlm_pthread_init()
- * dlm_ls_pthread_init() - call this before any locking operations and the ASTs
- * will be delivered in their own thread.
- * dlm_pthread_cleanup() - call the cleanup routine at application exit
- * (optional) or, if the locking functions are in a
- * shared library that is to be unloaded.
- *
- * dlm_close/release_lockspace() will tidy the threads for a non-default
- * lockspace
- */
-
-#ifdef _REENTRANT
-extern int dlm_pthread_init(void);
-extern int dlm_ls_pthread_init(dlm_lshandle_t lockspace);
-extern int dlm_pthread_cleanup(void);
-#endif
-
-
-/*
- * Lock modes
- */
-
-#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 */
-
-
-/*
- * Locking flags - these match the ones in dlm.h
- */
-
-#define LKF_NOQUEUE 0x00000001
-#define LKF_CANCEL 0x00000002
-#define LKF_CONVERT 0x00000004
-#define LKF_VALBLK 0x00000008
-#define LKF_QUECVT 0x00000010
-#define LKF_IVVALBLK 0x00000020
-#define LKF_CONVDEADLK 0x00000040
-#define LKF_PERSISTENT 0x00000080
-#define LKF_NODLCKWT 0x00000100
-#define LKF_NODLCKBLK 0x00000200
-#define LKF_EXPEDITE 0x00000400
-#define LKF_NOQUEUEBAST 0x00000800
-#define LKF_HEADQUE 0x00001000
-#define LKF_NOORDER 0x00002000
-#define LKF_ORPHAN 0x00004000
-#define LKF_ALTPR 0x00008000
-#define LKF_ALTCW 0x00010000
-#define LKF_FORCEUNLOCK 0x00020000
-#define LKF_TIMEOUT 0x00040000
-#define LKF_WAIT 0x80000000 /* Userspace only, for sync API calls */
-
-/*
- * Extra return codes used by the DLM
- */
-
-#define ECANCEL 0x10001
-#define EUNLOCK 0x10002
-#define EINPROG 0x10003 /* lock operation is in progress */
-
-#endif
-
diff --git a/dlm/libdlm/libdlm_internal.h b/dlm/libdlm/libdlm_internal.h
deleted file mode 100644
index c8b270e..0000000
--- a/dlm/libdlm/libdlm_internal.h
+++ /dev/null
@@ -1,9 +0,0 @@
-
-/* Needed before we include the kernel libdlm header */
-#define __user
-typedef uint8_t __u8;
-typedef uint16_t __u16;
-typedef uint32_t __u32;
-#define BUILDING_LIBDLM
-
-
diff --git a/dlm/man/dlm_cleanup.3 b/dlm/man/dlm_cleanup.3
deleted file mode 100644
index db4a9cf..0000000
--- a/dlm/man/dlm_cleanup.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libdlm.3
diff --git a/dlm/man/dlm_close_lockspace.3 b/dlm/man/dlm_close_lockspace.3
deleted file mode 100644
index e5db408..0000000
--- a/dlm/man/dlm_close_lockspace.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_create_lockspace.3
diff --git a/dlm/man/dlm_create_lockspace.3 b/dlm/man/dlm_create_lockspace.3
deleted file mode 100644
index 3879e85..0000000
--- a/dlm/man/dlm_create_lockspace.3
+++ /dev/null
@@ -1,94 +0,0 @@
-.TH DLM_CREATE_LOCKSPACE 3 "July 5, 2007" "libdlm functions"
-.SH NAME
-dlm_create_lockspace, dlm_open_lockspace, dlm_close_lockspace, dlm_release_lockspace \-
manipulate DLM lockspaces
-.SH SYNOPSIS
-.nf
- #include <libdlm.h>
-
-dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
-dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode,
- uint32_t flags);
-dlm_lshandle_t dlm_open_lockspace(const char *name);
-int dlm_close_lockspace(dlm_lshandle_t ls);
-int dlm_release_lockspace(const char *name, dlm_lshandle_t ls,
- int force);
-
-.fi
-.SH DESCRIPTION
-The DLM allows locks to be partitioned into "lockspaces", and these can be
manipulated by userspace calls. It is possible (though not recommended) for an application
to have multiple lockspaces open at one time.
-
-Many of the DLM calls work on the "default" lockspace, which should be fine for
most users. The calls with _ls_ in them allow you to isolate your application from all
others running in the cluster. Remember, lockspaces are a cluster-wide resource, so if you
create a lockspace called "myls" it will share locks with a lockspace called
"myls" on all nodes. These calls allow users to create & remove lockspaces,
and users to connect to existing lockspace to store their locks there.
-.PP
-.SS
-dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
-.br
-This creates a lockspace called <name> and the mode of the file user to access it
will be <mode> (subject to umask as usual). The lockspace must not already exist on
this node, if it does -1 will be returned and errno will be set to EEXIST. If you really
want to use this lockspace you can then use dlm_open_lockspace() below. The name is the
name of a misc device that will be created in /dev/misc.
-.br
-On success a handle to the lockspace is returned, which can be used to pass into
subsequent dlm_ls_lock/unlock calls. Make no assumptions as to the content of this handle
as it's content may change in future.
-.br
-The caller must have CAP_SYSADMIN privileges to do this operation.
-.PP
-Return codes:
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
-.nf
-EINVAL An invalid parameter was passed to the call
-ENOMEM A (kernel) memory allocation failed
-EEXIST The lockspace already exists
-EPERM Process does not have capability to create lockspaces
-ENOSYS A fatal error occurred initializing the DLM
-Any error returned by the open() system call
-.fi
-.SS
-int dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags)
-.PP
-Performs the same function as
-.B dlm_create_lockspace()
-above, but passes some creation flags to the call that affect the lockspace being
created. Currently supported flags are:
-.nf
-DLM_LSFL_NODIR the lockspace should not use a resource directory
-DLM_LSFL_TIMEWARN the dlm should emit warnings over netlink when locks
- have been waiting too long; required for deadlock
- detection
-.fi
-.SS
-int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force)
-.PP
-Deletes a lockspace. If the lockspace still has active locks then -1 will be returned and
errno set to EBUSY. Both the lockspace handle /and/ the name must be specified. This call
also closes the lockspace and stops the thread associated with the lockspace, if any.
-.br
-Note that other nodes in the cluster may still have locks open on this lockspace. This
call only removes the lockspace from the current node. If the force flag is set then the
lockspace will be removed even if another user on this node has active locks in it.
Existing users will NOT be notified if you do this, so be careful.
-.br
-The caller must have CAP_SYSADMIN privileges to do this operation.
-.PP
-Return codes:
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
-.nf
-EINVAL An invalid parameter was passed to the call
-EPERM Process does not have capability to release lockspaces
-EBUSY The lockspace could not be freed because it still
- contains locks and force was not set.
-.fi
-
-.SS
-dlm_lshandle_t dlm_open_lockspace(const char *name)
-.PP
-Opens an already existing lockspace and returns a handle to it.
-.PP
-Return codes:
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to an error returned by the open() system call
-.SS
-int dlm_close_lockspace(dlm_lshandle_t ls)
-.br
-Close the lockspace. Any locks held by this process will be freed. If a thread is
associated with this lockspace then it will be stopped.
-.PP
-Return codes:
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
-.nf
-EINVAL lockspace was not a valid lockspace handle
-.fi
-
-
-.SH SEE ALSO
-
-.BR libdlm (3),
-.BR dlm_unlock (3),
-.BR dlm_lock (3),
diff --git a/dlm/man/dlm_dispatch.3 b/dlm/man/dlm_dispatch.3
deleted file mode 100644
index db4a9cf..0000000
--- a/dlm/man/dlm_dispatch.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libdlm.3
diff --git a/dlm/man/dlm_get_fd.3 b/dlm/man/dlm_get_fd.3
deleted file mode 100644
index db4a9cf..0000000
--- a/dlm/man/dlm_get_fd.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libdlm.3
diff --git a/dlm/man/dlm_lock.3 b/dlm/man/dlm_lock.3
deleted file mode 100644
index 3c5f8b5..0000000
--- a/dlm/man/dlm_lock.3
+++ /dev/null
@@ -1,239 +0,0 @@
-.TH DLM_LOCK 3 "July 5, 2007" "libdlm functions"
-.SH NAME
-dlm_lock \- acquire or convert a DLM lock
-.SH SYNOPSIS
-.nf
- #include <libdlm.h>
-
-int dlm_lock(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range); /* unused */
-
-int dlm_lock_wait(uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range); /* unused */
-
-int dlm_ls_lock(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- void (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- void *range); /* unused */
-
-int dlm_ls_lock_wait(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unusued */
- void *bastarg,
- void (*bastaddr) (void *bastarg),
- void *range); /* unused */
-
-int dlm_ls_lockx(dlm_lshandle_t lockspace,
- uint32_t mode,
- struct dlm_lksb *lksb,
- uint32_t flags,
- const void *name,
- unsigned int namelen,
- uint32_t parent, /* unused */
- (*astaddr) (void *astarg),
- void *astarg,
- void (*bastaddr) (void *astarg),
- uint64_t *xid,
- uint64_t *timeout);
-
-
-
-.fi
-.SH DESCRIPTION
-dlm_lock and its variants acquire and convert locks in the DLM.
-.PP
-dlm_lock() operations are asynchronous. If the call to dlm_lock returns an error then the
operation has failed and the AST routine will not be called. If dlm_lock returns 0 it is
still possible that the lock operation will fail. The AST routine will be called when the
locking is complete or has failed and the status is returned in the lksb.
-.B dlm_lock_wait()
-will wait until the lock operation has completed and returns the final completion
status.
-.B dlm_ls_lock()
-is the same as
-.B dlm_lock()
-but takes a lockspace argument. This lockspace must have been previously opened by
-.B dlm_lockspace_open() or
-.B dlm_lockspace_create().
-.PP
-For conversion operations the name and namelen are ignored and the lock ID in the LKSB is
used to identify the lock to be converted.
-.PP
-If a lock value block is specified then in general, a grant or a conversion to an
equal-level or higher-level lock mode reads the lock value from the resource into the
caller's lock value block. When a lock conversion from EX or PW to an equal-level or
lower-level lock mode occurs, the contents of the caller's lock value block are
written into the resource. If the LVB is invalidated the lksb.sb_flags member will be set
to DLM_SBF_VALNOTVALID. Lock values blocks are always 32 bytes long.
-.PP
-If the AST routines or parameter are passed to a conversion operation then they will
overwrite those values that were passed to a previous dlm_lock call.
-.PP
-.B mode
-Lock mode to acquire or convert to.
-.nf
- LKM_NLMODE NULL Lock
- LKM_CRMODE Concurrent read
- LKM_CWMODE Concurrent write
- LKM_PRMODE Protected read
- LKM_PWMODE Protected write
- LKM_EXMODE Exclusive
-.fi
-.PP
-.B flags
-Affect the operation of the lock call:
-.nf
- LKF_NOQUEUE Don't queue the lock. If it cannot be granted return
- -EAGAIN
- LKF_CONVERT Convert an existing lock
- LKF_VALBLK Lock has a value block
- LKF_QUECVT Put conversion to the back of the queue
- LKF_EXPEDITE Grant a NL lock immediately regardless of other locks
- on the conversion queue
- LKF_PERSISTENT Specifies a lock that will not be unlocked when the
- process exits; it will become an orphan lock.
- LKF_CONVDEADLK Enable internal conversion deadlock resolution where
- the lock's granted mode may be set to NL and
- DLM_SBF_DEMOTED is returned in lksb.sb_flags.
- LKF_NODLCKWT Do not consider this lock when trying to detect
- deadlock conditions.
- LKF_NODLCKBLK Not implemented
- LKF_NOQUEUEBAST Send blocking ASTs even for NOQUEUE operations
- LKF_HEADQUE Add locks to the head of the convert or waiting queue
- LKF_NOORDER Avoid the VMS rules on grant order
- LKF_ALTPR If the requested mode can't be granted (generally CW),
- try to grant in PR and return DLM_SBF_ALTMODE.
- LKF_ALTCW If the requested mode can't be granted (generally PR),
- try to grant in CW and return DLM_SBF_ALTMODE.
- LKF_TIMEOUT The lock will time out per the timeout arg.
-
-.fi
-.PP
-.B lksb
-Lock Status block
-.br
-This structure contains the returned lock ID, the actual
-status of the lock operation (all lock ops are asynchronous)
-and the value block if LKF_VALBLK is set.
-.PP
-.B name
-.br
-Name of the lock. Can be binary, max 64 bytes. Ignored for lock
-conversions. (Should be a string to work with debugging tools.)
-.PP
-.B namelen
-.br
-Length of the above name. Ignored for lock conversions.
-.PP
-.B parent
-.br
-ID of parent lock or NULL if this is a top-level lock. This is currently unused.
-.PP
-.B ast
-.br
-Address of AST routine to be called when the lock operation
-completes. The final completion status of the lock will be
-in the lksb. the AST routine must not be NULL.
-.PP
-.B astargs
-.br
-Argument to pass to the AST routine (most people pass the lksb
-in here but it can be anything you like.)
-.PP
-.B bast
-.br
-Blocking AST routine. address of a function to call if this
-lock is blocking another. The function will be called with
-astargs.
-.PP
-.B range
-.br
-This is unused.
-.PP
-.B xid
-.br
-Optional transaction ID for deadlock detection.
-.PP
-.B timeout
-.br
-Timeout in centiseconds. If it takes longer than this to acquire the lock
-(usually because it is already blocked by another lock), then the AST
-will trigger with ETIMEDOUT as the status. If the lock operation is a conversion
-then the lock will remain at its current status. If this is a new lock then
-the lock will not exist and any LKB in the lksb will be invalid. This is
-ignored without the LKF_TIMEOUT flag.
-.PP
-.SS Return values
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
-.PP
-.nf
-EINVAL An invalid parameter was passed to the call (eg bad lock
- mode or flag)
-ENOMEM A (kernel) memory allocation failed
-EAGAIN LKF_NOQUEUE was requested and the lock could not be
- granted
-EBUSY The lock is currently being locked or converted
-EFAULT The userland buffer could not be read/written by the
- kernel (this indicates a library problem)
-EDEADLOCK The lock operation is causing a deadlock and has been
- cancelled. If this was a conversion then the lock is
- reverted to its previously granted state. If it was a
- new lock then it has not been granted. (NB Only
- conversion deadlocks are currently detected)
-.PP
-If an error is returned in the AST, then lksb.sb_status is set to the one of the above
values instead of zero.
-.SS Structures
-.nf
-struct dlm_lksb {
- int sb_status; /* Final status of lock operation */
- uint32_t sb_lkid; /* ID of lock. Returned from dlm_lock()
- on first use. Used as input to
- dlm_lock() for a conversion operation */
- char sb_flags; /* Completion flags, see above */
- char sb_lvbptr; /* Optional pointer to lock value block */
-};
-
-.fi
-.SH EXAMPLE
-.nf
-int status;
-struct dlm_lksb lksb;
-
-status = dlm_lock_wait(LKM_EXMODE,
- &lksb,
- LKF_NOQUEUE,
- "MyLock",
- strlen("MyLock"),
- 0, // Parent,
- NULL, // bast arg
- NULL, // bast routine,
- NULL); // Range
-
-if (status == 0)
- dlm_unlock_wait(lksb.sb_lkid, 0, &lksb);
-
-.fi
-
-.SH SEE ALSO
-
-.BR libdlm (3),
-.BR dlm_unlock (3),
-.BR dlm_open_lockspace (3),
-.BR dlm_create_lockspace (3),
-.BR dlm_close_lockspace (3),
-.BR dlm_release_lockspace (3)
diff --git a/dlm/man/dlm_lock_wait.3 b/dlm/man/dlm_lock_wait.3
deleted file mode 100644
index a99225c..0000000
--- a/dlm/man/dlm_lock_wait.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_lock.3
diff --git a/dlm/man/dlm_ls_lock.3 b/dlm/man/dlm_ls_lock.3
deleted file mode 100644
index a99225c..0000000
--- a/dlm/man/dlm_ls_lock.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_lock.3
diff --git a/dlm/man/dlm_ls_lock_wait.3 b/dlm/man/dlm_ls_lock_wait.3
deleted file mode 100644
index a99225c..0000000
--- a/dlm/man/dlm_ls_lock_wait.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_lock.3
diff --git a/dlm/man/dlm_ls_lockx.3 b/dlm/man/dlm_ls_lockx.3
deleted file mode 100644
index a99225c..0000000
--- a/dlm/man/dlm_ls_lockx.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_lock.3
diff --git a/dlm/man/dlm_ls_pthread_init.3 b/dlm/man/dlm_ls_pthread_init.3
deleted file mode 100644
index db4a9cf..0000000
--- a/dlm/man/dlm_ls_pthread_init.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libdlm.3
diff --git a/dlm/man/dlm_ls_unlock.3 b/dlm/man/dlm_ls_unlock.3
deleted file mode 100644
index 91babd2..0000000
--- a/dlm/man/dlm_ls_unlock.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_unlock.3
diff --git a/dlm/man/dlm_ls_unlock_wait.3 b/dlm/man/dlm_ls_unlock_wait.3
deleted file mode 100644
index 91babd2..0000000
--- a/dlm/man/dlm_ls_unlock_wait.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_unlock.3
diff --git a/dlm/man/dlm_new_lockspace.3 b/dlm/man/dlm_new_lockspace.3
deleted file mode 100644
index e5db408..0000000
--- a/dlm/man/dlm_new_lockspace.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_create_lockspace.3
diff --git a/dlm/man/dlm_open_lockspace.3 b/dlm/man/dlm_open_lockspace.3
deleted file mode 100644
index e5db408..0000000
--- a/dlm/man/dlm_open_lockspace.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_create_lockspace.3
diff --git a/dlm/man/dlm_pthread_init.3 b/dlm/man/dlm_pthread_init.3
deleted file mode 100644
index db4a9cf..0000000
--- a/dlm/man/dlm_pthread_init.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/libdlm.3
diff --git a/dlm/man/dlm_release_lockspace.3 b/dlm/man/dlm_release_lockspace.3
deleted file mode 100644
index e5db408..0000000
--- a/dlm/man/dlm_release_lockspace.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_create_lockspace.3
diff --git a/dlm/man/dlm_unlock.3 b/dlm/man/dlm_unlock.3
deleted file mode 100644
index 9023139..0000000
--- a/dlm/man/dlm_unlock.3
+++ /dev/null
@@ -1,94 +0,0 @@
-.TH DLM_UNLOCK 3 "July 5, 2007" "libdlm functions"
-.SH NAME
-dlm_unlock \- unlock a DLM lock
-.SH SYNOPSIS
-.nf
-#include <libdlm.h>
-
-int dlm_unlock(uint32_t lkid,
- uint32_t flags, struct dlm_lksb *lksb, void *astarg);
-
-int dlm_unlock_wait(uint32_t lkid,
- uint32_t flags, struct dlm_lksb *lksb);
-
-.fi
-.SH DESCRIPTION
-.B dlm_unlock()
-unlocks a lock previously acquired by dlm_lock and its variants.
-.PP
-Unless
-.B dlm_unlock_wait()
-is used unlocks are also asynchronous. The AST routine is called when the resource is
successfully unlocked (see below).
-.PP
-.B lkid
-Lock ID as returned in the lksb
-.PP
-.B flags
-flags affecting the unlock operation:
-.nf
- LKF_CANCEL Cancel a pending lock or conversion.
- This returns the lock to it's previously
- granted mode (in case of a conversion) or
- unlocks it (in case of a waiting lock).
- LKF_IVVALBLK Invalidate value block
- LKF_FORCEUNLOCK Unlock the lock even if it's waiting.
-.fi
-.PP
-.B lksb
-LKSB to return status and value block information.
-.PP
-.B astarg
-New parameter to be passed to the completion AST.
-The completion AST routine is the
-last completion AST routine specified in a dlm_lock call.
-If dlm_lock_wait() was the last routine to issue a lock,
-dlm_unlock_wait() must be used to release the lock. If dlm_lock()
-was the last routine to issue a lock then either dlm_unlock()
-or dlm_unlock_wait() may be called.
-.PP
-
-.SS Return values
-0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
-.PP
-.nf
-EINVAL An invalid parameter was passed to the call (eg bad
- lock mode or flag)
-EINPROGRESS The lock is already being unlocked
-EBUSY The lock is currently being locked or converted
-ENOTEMPTY An attempt to made to unlock a parent lock that still has
- child locks.
-ECANCEL A lock conversion was successfully cancelled
-EUNLOCK An unlock operation completed successfully
- (sb_status only)
-EFAULT The userland buffer could not be read/written by the
- kernel
-.fi
-If an error is returned in the AST, then lksb.sb_status is set to the one of the above
numbers instead of zero.
-.SH EXAMPLE
-.nf
-int status;
-struct dlm_lksb lksb;
-
-status = dlm_lock_wait(LKM_EXMODE,
- &lksb,
- LKF_NOQUEUE,
- "MyLock",
- strlen("MyLock"),
- 0, // Parent,
- NULL, // bast arg
- NULL, // bast routine,
- NULL); // Range
-
-if (status == 0)
- dlm_unlock_wait(lksb.sb_lkid, 0, &lksb);
-
-.fi
-
-.SH SEE ALSO
-
-.BR libdlm (3),
-.BR dlm_lock (3),
-.BR dlm_open_lockspace (3),
-.BR dlm_create_lockspace (3),
-.BR dlm_close_lockspace (3),
-.BR dlm_release_lockspace (3)
diff --git a/dlm/man/dlm_unlock_wait.3 b/dlm/man/dlm_unlock_wait.3
deleted file mode 100644
index 91babd2..0000000
--- a/dlm/man/dlm_unlock_wait.3
+++ /dev/null
@@ -1 +0,0 @@
-.so man3/dlm_unlock.3
diff --git a/dlm/man/libdlm.3 b/dlm/man/libdlm.3
deleted file mode 100644
index a020560..0000000
--- a/dlm/man/libdlm.3
+++ /dev/null
@@ -1,105 +0,0 @@
-.TH LIBDLM 3 "July 5, 2007" "libdlm functions"
-.SH NAME
-libdlm \- dlm_get_fd, dlm_dispatch, dlm_pthread_init, dlm_ls_pthread_init, dlm_cleanup
-.SH SYNOPSIS
-.nf
-#include <libdlm.h>
-.nf
-int dlm_pthread_init();
-int dlm_ls_pthread_init(dlm_lshandle_t lockspace);
-int dlm_pthread_cleanup();
-int dlm_get_fd(void);
-int dlm_dispatch(int fd);
-
-link with -ldlm
-.fi
-.SH DESCRIPTION
-libdlm provides the programmatic userspace interface to the Distributed Lock manager. It
provides all the calls you need to manipulate locks & lockspaces
-.br
-libdlm can be used in pthread or non-pthread applications. For pthread applications
simply call the following function before doing any lock operations. If you're using
pthreads, remember to define _REENTRANT at the top of the program or using -D_REENTRANT on
the compile line.
-.br
-pthreads is the normal way of using the DLM. This way you simply initialize the DLM's
thread and all the AST routines will be delivered in that thread. You just call the
dlm_lock() etc routines in the main line of your program.
-.br
-If you don't want to use pthreads or you want to handle the dlm callback ASTs
yourself then you can get an FD handle to the DLM device and call
-.B dlm_dispatch()
-on it whenever it becomes active. That was ASTs will be delivered in the context of the
thread/process that called
-.B dlm_dispatch().
-
-
-.SS int dlm_pthread_init()
-.br
-Creates a thread to receive all lock ASTs. The AST callback function for lock operations
will be called in the context of this thread. If there is a potential for local resource
access conflicts you must provide your own pthread-based locking in the AST routine.
-.PP
-.SS int dlm_ls_pthread_init(dlm_lshandle_t lockspace)
-.br
-As dlm_pthread_init but initializes a thread for the specified lockspace.
-.PP
-.SS int dlm_pthread_cleanup()
-.br
-Cleans up the default lockspace threads after use. Normally you don't need to call
this, but if the locking code is in a dynamically loadable shared library this will
probably be necessary.
-.br
-For non-pthread based applications the DLM provides a file descriptor that the program
can feed into poll/select. If activity is detected on that FD then a dispatch function
should be called:
-.PP
-.SS int dlm_get_fd()
-Returns a file-descriptor for the DLM suitable for passing in to poll() or select().
-.PP
-.SS int dlm_dispatch(int fd)
-.br
-Reads from the DLM and calls any AST routines that may be needed. This routine runs in
the context of the caller so no extra locking is needed to protect local resources.
-.PP
-
-
-.SH libdlm_lt
-There also exists a "light" version of the libdlm library called libdlm_lt.
This is provided for those applications that do not want to use pthread functions. If you
use this library it is important that your application is NOT compiled with -D_REENTRANT
or linked with libpthread.
-
-.SH EXAMPLES
-
-Create a lockspace and start a thread to deliver its callbacks:
-.nf
-dlm_lshandle_t ls;
-
-ls = dlm_create_lockspace("myLS", 0660);
-dlm_ls_pthread_init(ls);
-
- ...
-
-status = dlm_ls_lock(ls,
- ... );
-
-
-.fi
-.PP
- Using poll(2) to wait for and dispatch ASTs
-.nf
-
-
-static int poll_for_ast(dlm_lshandle_t ls)
-{
- struct pollfd pfd;
-
- pfd.fd = dlm_ls_get_fd(ls);
- pfd.events = POLLIN;
- while (!ast_called)
- {
- if (poll(&pfd, 1, 0) < 0)
- {
- perror("poll");
- return -1;
- }
- dlm_dispatch(dlm_ls_get_fd(ls));
- }
- ast_called = 0;
- return 0;
-}
-.fi
-
-
-.SH SEE ALSO
-
-.BR libdlm (3),
-.BR dlm_lock (3),
-.BR dlm_unlock (3),
-.BR dlm_open_lockspace (3),
-.BR dlm_create_lockspace (3),
-.BR dlm_close_lockspace (3),
-.BR dlm_release_lockspace (3)
diff --git a/libdlm/51-dlm.rules b/libdlm/51-dlm.rules
new file mode 100644
index 0000000..f71e79d
--- /dev/null
+++ b/libdlm/51-dlm.rules
@@ -0,0 +1,5 @@
+KERNEL=="dlm-control", NAME="misc/dlm-control",
MODE="0666"
+KERNEL=="dlm-monitor", NAME="misc/dlm-monitor",
MODE="0666"
+KERNEL=="dlm_default", NAME="misc/dlm_default",
MODE="0666"
+KERNEL=="dlm_*", NAME="misc/%k", MODE="0660"
+
diff --git a/libdlm/Makefile b/libdlm/Makefile
new file mode 100644
index 0000000..2b8b6d3
--- /dev/null
+++ b/libdlm/Makefile
@@ -0,0 +1,117 @@
+LIB_NAME = libdlm
+LIB_MAJOR = 3
+LIB_MINOR = 0
+LIB_O = $(LIB_NAME).o
+LIB_SO = $(LIB_NAME).so
+LIB_SMAJOR = $(LIB_SO).$(LIB_MAJOR)
+LIB_TARGET = $(LIB_SO).$(LIB_MAJOR).$(LIB_MINOR)
+
+LLT_NAME = libdlm_lt
+LLT_MAJOR = 3
+LLT_MINOR = 0
+LLT_O = $(LLT_NAME).o
+LLT_SO = $(LLT_NAME).so
+LLT_SMAJOR = $(LLT_SO).$(LLT_MAJOR)
+LLT_TARGET = $(LLT_SO).$(LLT_MAJOR).$(LLT_MINOR)
+
+HDR_TARGET = libdlm.h
+
+MAN_TARGET = \
+ man/dlm_cleanup.3 \
+ man/dlm_close_lockspace.3 \
+ man/dlm_create_lockspace.3 \
+ man/dlm_dispatch.3 \
+ man/dlm_get_fd.3 \
+ man/dlm_lock.3 \
+ man/dlm_lock_wait.3 \
+ man/dlm_ls_lock.3 \
+ man/dlm_ls_lock_wait.3 \
+ man/dlm_ls_lockx.3 \
+ man/dlm_ls_pthread_init.3 \
+ man/dlm_ls_unlock.3 \
+ man/dlm_ls_unlock_wait.3 \
+ man/dlm_new_lockspace.3 \
+ man/dlm_open_lockspace.3 \
+ man/dlm_pthread_init.3 \
+ man/dlm_release_lockspace.3 \
+ man/dlm_unlock.3 \
+ man/dlm_unlock_wait.3 \
+ man/libdlm.3
+
+UDEV_TARGET = 51-dlm.rules
+
+SOURCE = libdlm.c
+
+CFLAGS += -D_GNU_SOURCE -g \
+ -Wall \
+ -Wformat \
+ -Wformat-security \
+ -Wmissing-prototypes \
+ -Wnested-externs \
+ -Wpointer-arith \
+ -Wextra -Wshadow \
+ -Wcast-align \
+ -Wwrite-strings \
+ -Waggregate-return \
+ -Wstrict-prototypes \
+ -Winline \
+ -Wredundant-decls \
+ -Wno-sign-compare \
+ -Wno-unused-parameter \
+ -Wp,-D_FORTIFY_SOURCE=2 \
+ -fexceptions \
+ -fasynchronous-unwind-tables \
+ -fdiagnostics-show-option \
+ -fPIC \
+
+LIB_CFLAGS += $(CFLAGS) -D_REENTRANT
+LLT_CFLAGS += $(CFLAGS)
+
+LDFLAGS += -Wl
+
+LIB_LDFLAGS += $(LDFLAGS) -lpthread
+LLT_LDFLAGS += $(LDFLAGS)
+
+all: $(LIB_TARGET) $(LLT_TARGET)
+
+$(LIB_O): $(SOURCE)
+ $(CC) $(LIB_CFLAGS) -c -o $@ $<
+
+$(LLT_O): $(SOURCE)
+ $(CC) $(LLT_CFLAGS) -c -o $@ $<
+
+$(LIB_TARGET): $(LIB_O)
+ $(CC) $(LIB_LDFLAGS) -shared -o $@ -Wl,-soname=$(LIB_SMAJOR) $^
+ ln -sf $(LIB_TARGET) $(LIB_SO)
+ ln -sf $(LIB_TARGET) $(LIB_SMAJOR)
+
+$(LLT_TARGET): $(LLT_O)
+ $(CC) $(LLT_LDFLAGS) -shared -o $@ -Wl,-soname=$(LLT_SMAJOR) $^
+ ln -sf $(LLT_TARGET) $(LLT_SO)
+ ln -sf $(LLT_TARGET) $(LLT_SMAJOR)
+
+clean:
+ rm -f *.o *.so *.so.* *.a
+
+INSTALL=$(shell which install)
+
+DESTDIR=
+LIBDIR=/usr/lib64
+HDRDIR=/usr/include
+MANDIR=/usr/share/man
+UDEVDIR=/etc/udev/rules.d
+
+.PHONY: install
+install: all
+ $(INSTALL) -d $(DESTDIR)/$(LIBDIR)
+ $(INSTALL) -d $(DESTDIR)/$(HDRDIR)
+ $(INSTALL) -d $(DESTDIR)/$(MANDIR)/man3
+ $(INSTALL) -d $(DESTDIR)/$(UDEVDIR)
+ $(INSTALL) -c -m 755 $(LIB_TARGET) $(DESTDIR)/$(LIBDIR)
+ $(INSTALL) -c -m 755 $(LLT_TARGET) $(DESTDIR)/$(LIBDIR)
+ cp -a $(LIB_SO) $(DESTDIR)/$(LIBDIR)
+ cp -a $(LLT_SO) $(DESTDIR)/$(LIBDIR)
+ $(INSTALL) -c -m 644 $(HDR_TARGET) $(DESTDIR)/$(HDRDIR)
+ $(INSTALL) -m 644 $(MAN_TARGET) $(DESTDIR)/$(MANDIR)/man3/
+ $(INSTALL) -m 644 $(UDEV_TARGET) $(DESTDIR)/$(UDEVDIR)
+
diff --git a/libdlm/libdlm.c b/libdlm/libdlm.c
new file mode 100644
index 0000000..a5157e2
--- /dev/null
+++ b/libdlm/libdlm.c
@@ -0,0 +1,1485 @@
+#ifdef _REENTRANT
+#include <pthread.h>
+#endif
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <linux/major.h>
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+#include <linux/types.h>
+#include <linux/dlm.h>
+#define BUILDING_LIBDLM
+#include "libdlm.h"
+#include <linux/dlm_device.h>
+
+#define MISC_PREFIX "/dev/misc/"
+#define DLM_PREFIX "dlm_"
+#define DLM_MISC_PREFIX MISC_PREFIX DLM_PREFIX
+#define DLM_CONTROL_NAME "dlm-control"
+#define DLM_CONTROL_PATH MISC_PREFIX DLM_CONTROL_NAME
+#define DEFAULT_LOCKSPACE "default"
+
+/*
+ * V5 of the dlm_device.h kernel/user interface structs
+ */
+
+struct dlm_lock_params_v5 {
+ __u8 mode;
+ __u8 namelen;
+ __u16 flags;
+ __u32 lkid;
+ __u32 parent;
+ void *castparam;
+ void *castaddr;
+ void *bastparam;
+ void *bastaddr;
+ struct dlm_lksb *lksb;
+ char lvb[DLM_USER_LVB_LEN];
+ char name[0];
+};
+
+struct dlm_write_request_v5 {
+ __u32 version[3];
+ __u8 cmd;
+ __u8 is64bit;
+ __u8 unused[2];
+
+ union {
+ struct dlm_lock_params_v5 lock;
+ struct dlm_lspace_params lspace;
+ } i;
+};
+
+struct dlm_lock_result_v5 {
+ __u32 length;
+ void *user_astaddr;
+ void *user_astparam;
+ struct dlm_lksb *user_lksb;
+ struct dlm_lksb lksb;
+ __u8 bast_mode;
+ __u8 unused[3];
+ /* Offsets may be zero if no data is present */
+ __u32 lvb_offset;
+};
+
+
+/*
+ * One of these per lockspace in use by the application
+ */
+
+struct dlm_ls_info {
+ int fd;
+#ifdef _REENTRANT
+ pthread_t tid;
+#else
+ int tid;
+#endif
+};
+
+/*
+ * The default lockspace.
+ * I've resisted putting locking around this as the user should be
+ * "sensible" and only do lockspace operations either in the
+ * main thread or ... carefully...
+ */
+
+static struct dlm_ls_info *default_ls = NULL;
+static int control_fd = -1;
+static struct dlm_device_version kernel_version;
+static int kernel_version_detected = 0;
+
+
+static int release_lockspace(uint32_t minor, uint32_t flags);
+
+
+static void ls_dev_name(const char *lsname, char *devname, int devlen)
+{
+ snprintf(devname, devlen, DLM_MISC_PREFIX "%s", lsname);
+}
+
+static void dummy_ast_routine(void *arg)
+{
+}
+
+#ifdef _REENTRANT
+/* Used for the synchronous and "simplified, synchronous" API routines */
+struct lock_wait
+{
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ struct dlm_lksb lksb;
+};
+
+static void sync_ast_routine(void *arg)
+{
+ struct lock_wait *lwait = arg;
+
+ pthread_mutex_lock(&lwait->mutex);
+ pthread_cond_signal(&lwait->cond);
+ pthread_mutex_unlock(&lwait->mutex);
+}
+
+/* lock_resource & unlock_resource
+ * are the simplified, synchronous API.
+ * Aways uses the default lockspace.
+ */
+int lock_resource(const char *resource, int mode, int flags, int *lockid)
+{
+ int status;
+ struct lock_wait lwait;
+
+ if (default_ls == NULL)
+ {
+ if (dlm_pthread_init())
+ {
+ return -1;
+ }
+ }
+
+ if (!lockid)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Conversions need the lockid in the LKSB */
+ if (flags & LKF_CONVERT)
+ lwait.lksb.sb_lkid = *lockid;
+
+ pthread_cond_init(&lwait.cond, NULL);
+ pthread_mutex_init(&lwait.mutex, NULL);
+ pthread_mutex_lock(&lwait.mutex);
+
+ status = dlm_lock(mode,
+ &lwait.lksb,
+ flags,
+ resource,
+ strlen(resource),
+ 0,
+ sync_ast_routine,
+ &lwait,
+ NULL,
+ NULL);
+ if (status)
+ return status;
+
+ /* Wait for it to complete */
+ pthread_cond_wait(&lwait.cond, &lwait.mutex);
+ pthread_mutex_unlock(&lwait.mutex);
+
+ *lockid = lwait.lksb.sb_lkid;
+
+ errno = lwait.lksb.sb_status;
+ if (lwait.lksb.sb_status)
+ return -1;
+ else
+ return 0;
+}
+
+
+int unlock_resource(int lockid)
+{
+ int status;
+ struct lock_wait lwait;
+
+ if (default_ls == NULL)
+ {
+ errno = -ENOTCONN;
+ return -1;
+ }
+
+ pthread_cond_init(&lwait.cond, NULL);
+ pthread_mutex_init(&lwait.mutex, NULL);
+ pthread_mutex_lock(&lwait.mutex);
+
+ status = dlm_unlock(lockid, 0, &lwait.lksb, &lwait);
+
+ if (status)
+ return status;
+
+ /* Wait for it to complete */
+ pthread_cond_wait(&lwait.cond, &lwait.mutex);
+ pthread_mutex_unlock(&lwait.mutex);
+
+ errno = lwait.lksb.sb_status;
+ if (lwait.lksb.sb_status != DLM_EUNLOCK)
+ return -1;
+ else
+ return 0;
+}
+
+/* Tidy up threads after a lockspace is closed */
+static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
+{
+ int status = 0;
+ int fd;
+
+ /* Must close the fd after the thread has finished */
+ fd = lsinfo->fd;
+ if (lsinfo->tid)
+ {
+ status = pthread_cancel(lsinfo->tid);
+ if (!status)
+ pthread_join(lsinfo->tid, NULL);
+ }
+ if (!status)
+ {
+ free(lsinfo);
+ close(fd);
+ }
+
+ return status;
+}
+
+/* Cleanup default lockspace */
+int dlm_pthread_cleanup(void)
+{
+ struct dlm_ls_info *lsinfo = default_ls;
+
+ /* Protect users from their own stupidity */
+ if (!lsinfo)
+ return 0;
+
+ default_ls = NULL;
+
+ return ls_pthread_cleanup(lsinfo);
+}
+#else
+
+/* Non-pthread version of cleanup */
+static int ls_pthread_cleanup(struct dlm_ls_info *lsinfo)
+{
+ close(lsinfo->fd);
+ free(lsinfo);
+ return 0;
+}
+#endif
+
+
+static void set_version_v5(struct dlm_write_request_v5 *req)
+{
+ req->version[0] = kernel_version.version[0];
+ req->version[1] = kernel_version.version[1];
+ req->version[2] = kernel_version.version[2];
+ if (sizeof(long) == sizeof(long long))
+ req->is64bit = 1;
+ else
+ req->is64bit = 0;
+}
+
+static void set_version_v6(struct dlm_write_request *req)
+{
+ req->version[0] = kernel_version.version[0];
+ req->version[1] = kernel_version.version[1];
+ req->version[2] = kernel_version.version[2];
+ if (sizeof(long) == sizeof(long long))
+ req->is64bit = 1;
+ else
+ req->is64bit = 0;
+}
+
+static int open_default_lockspace(void)
+{
+ if (!default_ls) {
+ dlm_lshandle_t ls;
+
+ /* This isn't the race it looks, create_lockspace will
+ * do the right thing if the lockspace has already been
+ * created.
+ */
+
+ ls = dlm_open_lockspace(DEFAULT_LOCKSPACE);
+ if (!ls)
+ ls = dlm_create_lockspace(DEFAULT_LOCKSPACE, 0600);
+ if (!ls)
+ return -1;
+
+ default_ls = (struct dlm_ls_info *)ls;
+ }
+ return 0;
+}
+
+static void detect_kernel_version(void)
+{
+ struct dlm_device_version v;
+ int rv;
+
+ rv = read(control_fd, &v, sizeof(struct dlm_device_version));
+ if (rv < 0) {
+ kernel_version.version[0] = 5;
+ kernel_version.version[1] = 0;
+ kernel_version.version[2] = 0;
+ } else {
+ kernel_version.version[0] = v.version[0];
+ kernel_version.version[1] = v.version[1];
+ kernel_version.version[2] = v.version[2];
+ }
+
+ kernel_version_detected = 1;
+}
+
+static int find_control_minor(int *minor)
+{
+ FILE *f;
+ char name[256];
+ int found = 0, m = 0;
+
+ f = fopen("/proc/misc", "r");
+ if (!f)
+ return -1;
+
+ while (!feof(f)) {
+ if (fscanf(f, "%d %s", &m, name) != 2)
+ continue;
+ if (strcmp(name, DLM_CONTROL_NAME))
+ continue;
+ found = 1;
+ break;
+ }
+ fclose(f);
+
+ if (found) {
+ *minor = m;
+ return 0;
+ }
+ return -1;
+}
+
+static int open_control_device(void)
+{
+ struct stat st;
+ int i, rv, minor, found = 0;
+
+ if (control_fd > -1)
+ goto out;
+
+ rv = find_control_minor(&minor);
+ if (rv < 0)
+ return -1;
+
+ /* wait for udev to create the device */
+
+ for (i = 0; i < 10; i++) {
+ if (stat(DLM_CONTROL_PATH, &st) == 0 &&
+ minor(st.st_rdev) == minor) {
+ found = 1;
+ break;
+ }
+ sleep(1);
+ continue;
+ }
+
+ if (!found)
+ return -1;
+
+ control_fd = open(DLM_CONTROL_PATH, O_RDWR);
+ if (control_fd == -1)
+ return -1;
+
+ out:
+ fcntl(control_fd, F_SETFD, 1);
+
+ if (!kernel_version_detected)
+ detect_kernel_version();
+ return 0;
+}
+
+/* the max number of characters in a sysfs device name, not including \0 */
+#define MAX_SYSFS_NAME 19
+
+static int find_udev_device(const char *lockspace, int minor, char *udev_path)
+{
+ char bname[PATH_MAX];
+ char tmp_path[PATH_MAX];
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+ size_t basename_len;
+ int i;
+
+ ls_dev_name(lockspace, udev_path, PATH_MAX);
+ snprintf(bname, PATH_MAX, DLM_PREFIX "%s", lockspace);
+ basename_len = strlen(bname);
+
+ for (i = 0; i < 10; i++) {
+
+ /* look for a device with the full name */
+
+ if (stat(udev_path, &st) == 0 && minor(st.st_rdev) == minor)
+ return 0;
+
+ if (basename_len < MAX_SYSFS_NAME) {
+ sleep(1);
+ continue;
+ }
+
+ /* look for a device with a truncated name */
+
+ d = opendir(MISC_PREFIX);
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (strlen(de->d_name) < MAX_SYSFS_NAME)
+ continue;
+ if (strncmp(de->d_name, bname, MAX_SYSFS_NAME))
+ continue;
+ snprintf(tmp_path, PATH_MAX, MISC_PREFIX "%s",
+ de->d_name);
+ if (stat(tmp_path, &st))
+ continue;
+ if (minor(st.st_rdev) != minor)
+ continue;
+
+ /* truncated name */
+ strncpy(udev_path, tmp_path, PATH_MAX);
+ closedir(d);
+ return 0;
+ }
+ closedir(d);
+ sleep(1);
+ }
+
+ return -1;
+}
+
+/*
+ * do_dlm_dispatch()
+ * Read an ast from the kernel.
+ */
+
+static int do_dlm_dispatch_v5(int fd)
+{
+ char resultbuf[sizeof(struct dlm_lock_result_v5) + DLM_USER_LVB_LEN];
+ struct dlm_lock_result_v5 *result = (struct dlm_lock_result_v5 *)resultbuf;
+ char *fullresult = NULL;
+ int status;
+ void (*astaddr)(void *astarg);
+
+ status = read(fd, result, sizeof(resultbuf));
+ if (status <= 0)
+ return -1;
+
+ /* This shouldn't happen any more, can probably be removed */
+
+ if (result->length != status) {
+ int newstat;
+
+ fullresult = malloc(result->length);
+ if (!fullresult)
+ return -1;
+
+ newstat = read(fd, (struct dlm_lock_result_v5 *)fullresult,
+ result->length);
+
+ /* If it read OK then use the new data. otherwise we can
+ still deliver the AST, it just might not have all the
+ info in it...hmmm */
+
+ if (newstat == result->length)
+ result = (struct dlm_lock_result_v5 *)fullresult;
+ } else {
+ fullresult = resultbuf;
+ }
+
+
+ /* Copy lksb to user's buffer - except the LVB ptr */
+ memcpy(result->user_lksb, &result->lksb,
+ sizeof(struct dlm_lksb) - sizeof(char*));
+
+ /* Flip the status. Kernel space likes negative return codes,
+ userspace positive ones */
+ result->user_lksb->sb_status = -result->user_lksb->sb_status;
+
+ /* Copy optional items */
+ if (result->lvb_offset)
+ memcpy(result->user_lksb->sb_lvbptr,
+ fullresult + result->lvb_offset, DLM_LVB_LEN);
+
+ /* Call AST */
+ if (result->user_astaddr) {
+ astaddr = result->user_astaddr;
+ astaddr(result->user_astparam);
+ }
+
+ if (fullresult != resultbuf)
+ free(fullresult);
+
+ return 0;
+}
+
+static int do_dlm_dispatch_v6(int fd)
+{
+ char resultbuf[sizeof(struct dlm_lock_result) + DLM_USER_LVB_LEN];
+ struct dlm_lock_result *result = (struct dlm_lock_result *)resultbuf;
+ int status;
+ void (*astaddr)(void *astarg);
+
+ status = read(fd, result, sizeof(resultbuf));
+ if (status <= 0)
+ return -1;
+
+ /* Copy lksb to user's buffer - except the LVB ptr */
+ memcpy(result->user_lksb, &result->lksb,
+ sizeof(struct dlm_lksb) - sizeof(char*));
+
+ /* Copy lvb to user's buffer */
+ if (result->lvb_offset)
+ memcpy(result->user_lksb->sb_lvbptr,
+ (char *)result + result->lvb_offset, DLM_LVB_LEN);
+
+ result->user_lksb->sb_status = -result->user_lksb->sb_status;
+
+ if (result->user_astaddr) {
+ astaddr = result->user_astaddr;
+ astaddr(result->user_astparam);
+ }
+
+ return 0;
+}
+
+static int do_dlm_dispatch(int fd)
+{
+ if (kernel_version.version[0] == 5)
+ return do_dlm_dispatch_v5(fd);
+ else
+ return do_dlm_dispatch_v6(fd);
+}
+
+
+/*
+ * sync_write()
+ * Helper routine which supports the synchronous DLM calls. This
+ * writes a parameter block down to the DLM and waits for the
+ * operation to complete. This hides the different completion mechanism
+ * used when called from the main thread or the DLM 'AST' thread.
+ */
+
+#ifdef _REENTRANT
+
+static int sync_write_v5(struct dlm_ls_info *lsinfo,
+ struct dlm_write_request_v5 *req, int len)
+{
+ struct lock_wait lwait;
+ int status;
+
+ if (pthread_self() == lsinfo->tid) {
+ /* This is the DLM worker thread, don't use lwait to sync */
+ req->i.lock.castaddr = dummy_ast_routine;
+ req->i.lock.castparam = NULL;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ while (req->i.lock.lksb->sb_status == EINPROG) {
+ do_dlm_dispatch_v5(lsinfo->fd);
+ }
+ } else {
+ pthread_cond_init(&lwait.cond, NULL);
+ pthread_mutex_init(&lwait.mutex, NULL);
+ pthread_mutex_lock(&lwait.mutex);
+
+ req->i.lock.castaddr = sync_ast_routine;
+ req->i.lock.castparam = &lwait;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ pthread_cond_wait(&lwait.cond, &lwait.mutex);
+ pthread_mutex_unlock(&lwait.mutex);
+ }
+
+ return status; /* lock status is in the lksb */
+}
+
+static int sync_write_v6(struct dlm_ls_info *lsinfo,
+ struct dlm_write_request *req, int len)
+{
+ struct lock_wait lwait;
+ int status;
+
+ if (pthread_self() == lsinfo->tid) {
+ /* This is the DLM worker thread, don't use lwait to sync */
+ req->i.lock.castaddr = dummy_ast_routine;
+ req->i.lock.castparam = NULL;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ while (req->i.lock.lksb->sb_status == EINPROG) {
+ do_dlm_dispatch_v6(lsinfo->fd);
+ }
+ } else {
+ pthread_cond_init(&lwait.cond, NULL);
+ pthread_mutex_init(&lwait.mutex, NULL);
+ pthread_mutex_lock(&lwait.mutex);
+
+ req->i.lock.castaddr = sync_ast_routine;
+ req->i.lock.castparam = &lwait;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ pthread_cond_wait(&lwait.cond, &lwait.mutex);
+ pthread_mutex_unlock(&lwait.mutex);
+ }
+
+ return status; /* lock status is in the lksb */
+}
+
+#else /* _REENTRANT */
+
+static int sync_write_v5(struct dlm_ls_info *lsinfo,
+ struct dlm_write_request_v5 *req, int len)
+{
+ int status;
+
+ req->i.lock.castaddr = dummy_ast_routine;
+ req->i.lock.castparam = NULL;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ while (req->i.lock.lksb->sb_status == EINPROG) {
+ do_dlm_dispatch_v5(lsinfo->fd);
+ }
+
+ errno = req->i.lock.lksb->sb_status;
+ if (errno && errno != EUNLOCK)
+ return -1;
+ return 0;
+}
+
+static int sync_write_v6(struct dlm_ls_info *lsinfo,
+ struct dlm_write_request *req, int len)
+{
+ int status;
+
+ req->i.lock.castaddr = dummy_ast_routine;
+ req->i.lock.castparam = NULL;
+
+ status = write(lsinfo->fd, req, len);
+ if (status < 0)
+ return -1;
+
+ while (req->i.lock.lksb->sb_status == EINPROG) {
+ do_dlm_dispatch_v6(lsinfo->fd);
+ }
+
+ errno = req->i.lock.lksb->sb_status;
+ if (errno && errno != EUNLOCK)
+ return -1;
+ return 0;
+}
+
+#endif /* _REENTRANT */
+
+
+/*
+ * Lock
+ * All the ways to request/convert a lock
+ */
+
+static int ls_lock_v5(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg))
+{
+ char parambuf[sizeof(struct dlm_write_request_v5) + DLM_RESNAME_MAXLEN];
+ struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)parambuf;
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ int status;
+ int len;
+
+ memset(req, 0, sizeof(*req));
+ set_version_v5(req);
+
+ req->cmd = DLM_USER_LOCK;
+ req->i.lock.mode = mode;
+ req->i.lock.flags = (flags & ~LKF_WAIT);
+ req->i.lock.lkid = lksb->sb_lkid;
+ req->i.lock.parent = parent;
+ req->i.lock.lksb = lksb;
+ req->i.lock.castaddr = astaddr;
+ req->i.lock.bastaddr = bastaddr;
+ req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
+ req->i.lock.bastparam = astarg;
+
+ if (flags & LKF_CONVERT) {
+ req->i.lock.namelen = 0;
+ } else {
+ if (namelen > DLM_RESNAME_MAXLEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ req->i.lock.namelen = namelen;
+ memcpy(req->i.lock.name, name, namelen);
+ }
+
+ if (flags & LKF_VALBLK) {
+ memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
+ }
+
+ len = sizeof(struct dlm_write_request_v5) + namelen;
+ lksb->sb_status = EINPROG;
+
+ if (flags & LKF_WAIT)
+ status = sync_write_v5(lsinfo, req, len);
+ else
+ status = write(lsinfo->fd, req, len);
+
+ if (status < 0)
+ return -1;
+
+ /*
+ * the lock id is the return value from the write on the device
+ */
+
+ if (status > 0)
+ lksb->sb_lkid = status;
+ return 0;
+}
+
+static int ls_lock_v6(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ uint64_t *xid,
+ uint64_t *timeout)
+{
+ char parambuf[sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN];
+ struct dlm_write_request *req = (struct dlm_write_request *)parambuf;
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ int status;
+ int len;
+
+ memset(req, 0, sizeof(*req));
+ set_version_v6(req);
+
+ req->cmd = DLM_USER_LOCK;
+ req->i.lock.mode = mode;
+ req->i.lock.flags = (flags & ~LKF_WAIT);
+ req->i.lock.lkid = lksb->sb_lkid;
+ req->i.lock.parent = parent;
+ req->i.lock.lksb = lksb;
+ req->i.lock.castaddr = astaddr;
+ req->i.lock.bastaddr = bastaddr;
+ req->i.lock.castparam = astarg; /* same comp and blocking ast arg */
+ req->i.lock.bastparam = astarg;
+
+ if (xid)
+ req->i.lock.xid = *xid;
+ if (timeout)
+ req->i.lock.timeout = *timeout;
+
+ if (flags & LKF_CONVERT) {
+ req->i.lock.namelen = 0;
+ } else {
+ if (namelen > DLM_RESNAME_MAXLEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ req->i.lock.namelen = namelen;
+ memcpy(req->i.lock.name, name, namelen);
+ }
+
+ if (flags & LKF_VALBLK) {
+ memcpy(req->i.lock.lvb, lksb->sb_lvbptr, DLM_LVB_LEN);
+ }
+
+ len = sizeof(struct dlm_write_request) + namelen;
+ lksb->sb_status = EINPROG;
+
+ if (flags & LKF_WAIT)
+ status = sync_write_v6(lsinfo, req, len);
+ else
+ status = write(lsinfo->fd, req, len);
+
+ if (status < 0)
+ return -1;
+
+ /*
+ * the lock id is the return value from the write on the device
+ */
+
+ if (status > 0)
+ lksb->sb_lkid = status;
+ return 0;
+}
+
+static int ls_lock(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range)
+{
+ /* no support for range locks */
+ if (range) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (flags & LKF_VALBLK && !lksb->sb_lvbptr) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (kernel_version.version[0] == 5)
+ return ls_lock_v5(ls, mode, lksb, flags, name, namelen, parent,
+ astaddr, astarg, bastaddr);
+ else
+ return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
+ astaddr, astarg, bastaddr, NULL, NULL);
+}
+
+/*
+ * Extended async locking in own lockspace
+ */
+int dlm_ls_lockx(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ uint64_t *xid,
+ uint64_t *timeout)
+{
+ if (kernel_version.version[0] < 6) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ return ls_lock_v6(ls, mode, lksb, flags, name, namelen, parent,
+ astaddr, astarg, bastaddr, xid, timeout);
+}
+
+/*
+ * Async locking in own lockspace
+ */
+int dlm_ls_lock(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range)
+{
+ return ls_lock(ls, mode, lksb, flags, name, namelen, parent,
+ astaddr, astarg, bastaddr, range);
+}
+
+/*
+ * Sync locking in own lockspace
+ */
+int dlm_ls_lock_wait(dlm_lshandle_t ls,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range)
+{
+ return ls_lock(ls, mode, lksb, flags | LKF_WAIT, name, namelen, parent,
+ NULL, bastarg, bastaddr, range);
+}
+
+/*
+ * Async locking in the default lockspace
+ */
+int dlm_lock(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range)
+{
+ if (open_default_lockspace())
+ return -1;
+
+ return ls_lock(default_ls, mode, lksb, flags, name, namelen, parent,
+ astaddr, astarg, bastaddr, range);
+}
+
+/*
+ * Sync locking in the default lockspace
+ */
+int dlm_lock_wait(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent,
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range)
+{
+ if (open_default_lockspace())
+ return -1;
+
+ return ls_lock(default_ls, mode, lksb, flags | LKF_WAIT, name, namelen,
+ parent, NULL, bastarg, bastaddr, range);
+}
+
+
+/*
+ * Unlock
+ * All the ways to unlock/cancel a lock
+ */
+
+static int ls_unlock_v5(struct dlm_ls_info *lsinfo, uint32_t lkid,
+ uint32_t flags, struct dlm_lksb *lksb, void *astarg)
+{
+ struct dlm_write_request_v5 req;
+
+ set_version_v5(&req);
+ req.cmd = DLM_USER_UNLOCK;
+ req.i.lock.lkid = lkid;
+ req.i.lock.flags = (flags & ~LKF_WAIT);
+ req.i.lock.lksb = lksb;
+ req.i.lock.castparam = astarg;
+ /* DLM_USER_UNLOCK will default to existing completion AST */
+ req.i.lock.castaddr = 0;
+ lksb->sb_status = EINPROG;
+
+ if (flags & LKF_WAIT)
+ return sync_write_v5(lsinfo, &req, sizeof(req));
+ else
+ return write(lsinfo->fd, &req, sizeof(req));
+}
+
+static int ls_unlock_v6(struct dlm_ls_info *lsinfo, uint32_t lkid,
+ uint32_t flags, struct dlm_lksb *lksb, void *astarg)
+{
+ struct dlm_write_request req;
+
+ set_version_v6(&req);
+ req.cmd = DLM_USER_UNLOCK;
+ req.i.lock.lkid = lkid;
+ req.i.lock.flags = (flags & ~LKF_WAIT);
+ req.i.lock.lksb = lksb;
+ req.i.lock.namelen = 0;
+ req.i.lock.castparam = astarg;
+ /* DLM_USER_UNLOCK will default to existing completion AST */
+ req.i.lock.castaddr = 0;
+ lksb->sb_status = EINPROG;
+
+ if (flags & LKF_WAIT)
+ return sync_write_v6(lsinfo, &req, sizeof(req));
+ else
+ return write(lsinfo->fd, &req, sizeof(req));
+}
+
+int dlm_ls_unlock(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
+ struct dlm_lksb *lksb, void *astarg)
+{
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ int status;
+
+ if (ls == NULL) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ if (!lkid) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (kernel_version.version[0] == 5)
+ status = ls_unlock_v5(lsinfo, lkid, flags, lksb, astarg);
+ else
+ status = ls_unlock_v6(lsinfo, lkid, flags, lksb, astarg);
+
+ if (status < 0)
+ return -1;
+ return 0;
+}
+
+int dlm_ls_unlock_wait(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags,
+ struct dlm_lksb *lksb)
+{
+ return dlm_ls_unlock(ls, lkid, flags | LKF_WAIT, lksb, NULL);
+}
+
+int dlm_unlock_wait(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb)
+{
+ return dlm_ls_unlock_wait(default_ls, lkid, flags | LKF_WAIT, lksb);
+}
+
+int dlm_unlock(uint32_t lkid, uint32_t flags, struct dlm_lksb *lksb,
+ void *astarg)
+{
+ return dlm_ls_unlock(default_ls, lkid, flags, lksb, astarg);
+}
+
+int dlm_ls_deadlock_cancel(dlm_lshandle_t ls, uint32_t lkid, uint32_t flags)
+{
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ struct dlm_write_request req;
+
+ if (kernel_version.version[0] < 6) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (ls == NULL) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ if (!lkid) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ set_version_v6(&req);
+ req.cmd = DLM_USER_DEADLOCK;
+ req.i.lock.lkid = lkid;
+ req.i.lock.flags = flags;
+
+ return write(lsinfo->fd, &req, sizeof(req));
+}
+
+
+/*
+ * Purge
+ * Clear away orphan locks
+ */
+
+int dlm_ls_purge(dlm_lshandle_t ls, int nodeid, int pid)
+{
+ struct dlm_write_request req;
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ int status;
+
+ if (kernel_version.version[0] < 6) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (ls == NULL) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ set_version_v6(&req);
+ req.cmd = DLM_USER_PURGE;
+ req.i.purge.nodeid = nodeid;
+ req.i.purge.pid = pid;
+
+ status = write(lsinfo->fd, &req, sizeof(req));
+
+ if (status < 0)
+ return -1;
+ return 0;
+}
+
+
+/* These two routines for for users that want to
+ * do their own fd handling.
+ * This allows a non-threaded app to use the DLM.
+ */
+int dlm_get_fd(void)
+{
+ if (default_ls)
+ {
+ return default_ls->fd;
+ }
+ else
+ {
+ if (open_default_lockspace())
+ return -1;
+ else
+ return default_ls->fd;
+ }
+}
+
+int dlm_dispatch(int fd)
+{
+ int status;
+ int fdflags;
+
+ fdflags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, fdflags | O_NONBLOCK);
+ do
+ {
+ status = do_dlm_dispatch(fd);
+ } while (status == 0);
+
+ /* EAGAIN is not an error */
+ if (status < 0 && errno == EAGAIN)
+ status = 0;
+
+ fcntl(fd, F_SETFL, fdflags);
+ return status;
+}
+
+/* Converts a lockspace handle into a file descriptor */
+int dlm_ls_get_fd(dlm_lshandle_t lockspace)
+{
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)lockspace;
+
+ return lsinfo->fd;
+}
+
+#ifdef _REENTRANT
+static void *dlm_recv_thread(void *lsinfo)
+{
+ struct dlm_ls_info *lsi = lsinfo;
+
+ for (;;)
+ do_dlm_dispatch(lsi->fd);
+
+ return NULL;
+}
+
+/* Multi-threaded callers normally use this */
+int dlm_pthread_init(void)
+{
+ if (open_default_lockspace())
+ return -1;
+
+ if (default_ls->tid)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ if (pthread_create(&default_ls->tid, NULL, dlm_recv_thread, default_ls))
+ {
+ int saved_errno = errno;
+ close(default_ls->fd);
+ free(default_ls);
+ default_ls = NULL;
+ errno = saved_errno;
+ return -1;
+ }
+ return 0;
+}
+
+/* And same, for those with their own lockspace */
+int dlm_ls_pthread_init(dlm_lshandle_t ls)
+{
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+
+ if (lsinfo->tid)
+ {
+ errno = EEXIST;
+ return -1;
+ }
+
+ return pthread_create(&lsinfo->tid, NULL, dlm_recv_thread, (void *)ls);
+}
+#endif
+
+/*
+ * Lockspace manipulation functions
+ * Privileged users (checked by the kernel) can create/release lockspaces
+ */
+
+static int create_lockspace_v5(const char *name, uint32_t flags)
+{
+ char reqbuf[sizeof(struct dlm_write_request_v5) + DLM_LOCKSPACE_LEN];
+ struct dlm_write_request_v5 *req = (struct dlm_write_request_v5 *)reqbuf;
+ int namelen = strlen(name);
+ int minor;
+
+ memset(reqbuf, 0, sizeof(reqbuf));
+ set_version_v5(req);
+
+ req->cmd = DLM_USER_CREATE_LOCKSPACE;
+ req->i.lspace.flags = flags;
+
+ if (namelen > DLM_LOCKSPACE_LEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(req->i.lspace.name, name, namelen);
+
+ minor = write(control_fd, req, sizeof(*req) + namelen);
+
+ return minor;
+}
+
+static int create_lockspace_v6(const char *name, uint32_t flags)
+{
+ char reqbuf[sizeof(struct dlm_write_request) + DLM_LOCKSPACE_LEN];
+ struct dlm_write_request *req = (struct dlm_write_request *)reqbuf;
+ int namelen = strlen(name);
+ int minor;
+
+ memset(reqbuf, 0, sizeof(reqbuf));
+ set_version_v6(req);
+
+ req->cmd = DLM_USER_CREATE_LOCKSPACE;
+ req->i.lspace.flags = flags;
+
+ if (namelen > DLM_LOCKSPACE_LEN) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(req->i.lspace.name, name, namelen);
+
+ minor = write(control_fd, req, sizeof(*req) + namelen);
+
+ return minor;
+}
+
+static dlm_lshandle_t create_lockspace(const char *name, mode_t mode,
+ uint32_t flags)
+{
+ char dev_path[PATH_MAX];
+ char udev_path[PATH_MAX];
+ struct dlm_ls_info *newls;
+ int error, saved_errno, minor;
+
+ /* We use the control device for creating lockspaces. */
+ if (open_control_device())
+ return NULL;
+
+ newls = malloc(sizeof(struct dlm_ls_info));
+ if (!newls)
+ return NULL;
+
+ ls_dev_name(name, dev_path, sizeof(dev_path));
+
+ if (kernel_version.version[0] == 5)
+ minor = create_lockspace_v5(name, flags);
+ else
+ minor = create_lockspace_v6(name, flags);
+
+ if (minor < 0)
+ goto fail;
+
+ /* Wait for udev to create the device; the device it creates may
+ have a truncated name due to the sysfs device name limit. */
+
+ error = find_udev_device(name, minor, udev_path);
+ if (error)
+ goto fail;
+
+ /* If the symlink already exists, find_udev_device() will return
+ it and we'll skip this. */
+
+ if (strcmp(dev_path, udev_path)) {
+ error = symlink(udev_path, dev_path);
+ if (error)
+ goto fail;
+ }
+
+ /* Open it and return the struct as a handle */
+
+ newls->fd = open(dev_path, O_RDWR);
+ if (newls->fd == -1)
+ goto fail;
+ if (mode)
+ fchmod(newls->fd, mode);
+ newls->tid = 0;
+ fcntl(newls->fd, F_SETFD, 1);
+ return (dlm_lshandle_t)newls;
+
+ fail:
+ saved_errno = errno;
+ free(newls);
+ errno = saved_errno;
+ return NULL;
+}
+
+dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags)
+{
+ return create_lockspace(name, mode, flags);
+}
+
+dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode)
+{
+ return create_lockspace(name, mode, 0);
+}
+
+static int release_lockspace_v5(uint32_t minor, uint32_t flags)
+{
+ struct dlm_write_request_v5 req;
+
+ set_version_v5(&req);
+ req.cmd = DLM_USER_REMOVE_LOCKSPACE;
+ req.i.lspace.minor = minor;
+ req.i.lspace.flags = flags;
+
+ return write(control_fd, &req, sizeof(req));
+}
+
+static int release_lockspace_v6(uint32_t minor, uint32_t flags)
+{
+ struct dlm_write_request req;
+
+ set_version_v6(&req);
+ req.cmd = DLM_USER_REMOVE_LOCKSPACE;
+ req.i.lspace.minor = minor;
+ req.i.lspace.flags = flags;
+
+ return write(control_fd, &req, sizeof(req));
+}
+
+static int release_lockspace(uint32_t minor, uint32_t flags)
+{
+ if (kernel_version.version[0] == 5)
+ return release_lockspace_v5(minor, flags);
+ else
+ return release_lockspace_v6(minor, flags);
+}
+
+int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force)
+{
+ char dev_path[PATH_MAX];
+ struct stat st;
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+ uint32_t flags = 0;
+ int fd, is_symlink = 0;
+
+ ls_dev_name(name, dev_path, sizeof(dev_path));
+ if (!lstat(dev_path, &st) && S_ISLNK(st.st_mode))
+ is_symlink = 1;
+
+ /* We need the minor number */
+ if (fstat(lsinfo->fd, &st))
+ return -1;
+
+ /* Close the lockspace first if it's in use */
+ ls_pthread_cleanup(lsinfo);
+
+ if (open_control_device())
+ return -1;
+
+ if (force)
+ flags = DLM_USER_LSFLG_FORCEFREE;
+
+ release_lockspace(minor(st.st_rdev), flags);
+
+ if (!is_symlink)
+ return 0;
+
+ /* The following open is used to detect if our release was the last.
+ It will fail if our release was the last, because either:
+ . udev has already removed the truncated sysfs device name (ENOENT)
+ . the misc device has been deregistered in the kernel (ENODEV)
+ (the deregister completes before release returns)
+
+ So, if the open fails, we know that our release was the last,
+ udev will be removing the device with the truncated name (if it
+ hasn't already), and we should remove the symlink. */
+
+ fd = open(dev_path, O_RDWR);
+ if (fd < 0)
+ unlink(dev_path);
+ else
+ close(fd); /* our release was not the last */
+
+ return 0;
+}
+
+/*
+ * Normal users just open/close lockspaces
+ */
+
+dlm_lshandle_t dlm_open_lockspace(const char *name)
+{
+ char dev_name[PATH_MAX];
+ struct dlm_ls_info *newls;
+ int saved_errno;
+
+ /* Need to detect kernel version */
+ if (open_control_device())
+ return NULL;
+
+ newls = malloc(sizeof(struct dlm_ls_info));
+ if (!newls)
+ return NULL;
+
+ newls->tid = 0;
+ ls_dev_name(name, dev_name, sizeof(dev_name));
+
+ newls->fd = open(dev_name, O_RDWR);
+ saved_errno = errno;
+
+ if (newls->fd == -1) {
+ free(newls);
+ errno = saved_errno;
+ return NULL;
+ }
+ fcntl(newls->fd, F_SETFD, 1);
+ return (dlm_lshandle_t)newls;
+}
+
+int dlm_close_lockspace(dlm_lshandle_t ls)
+{
+ struct dlm_ls_info *lsinfo = (struct dlm_ls_info *)ls;
+
+ ls_pthread_cleanup(lsinfo);
+ return 0;
+}
+
+int dlm_kernel_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
+{
+ if (open_control_device())
+ return -1;
+ *major = kernel_version.version[0];
+ *minor = kernel_version.version[1];
+ *patch = kernel_version.version[2];
+ return 0;
+}
+
+void dlm_library_version(uint32_t *major, uint32_t *minor, uint32_t *patch)
+{
+ *major = DLM_DEVICE_VERSION_MAJOR;
+ *minor = DLM_DEVICE_VERSION_MINOR;
+ *patch = DLM_DEVICE_VERSION_PATCH;
+}
+
diff --git a/libdlm/libdlm.h b/libdlm/libdlm.h
new file mode 100644
index 0000000..17a552c
--- /dev/null
+++ b/libdlm/libdlm.h
@@ -0,0 +1,275 @@
+#ifndef __LIBDLM_H
+#define __LIBDLM_H
+
+/*
+ * Typedefs for things that are compatible with the kernel but replicated here
+ * so that users only need the libdlm include file. libdlm itself needs the
+ * full kernel file so shouldn't use these.
+ */
+
+#define DLM_LVB_LEN 32
+
+#ifndef BUILDING_LIBDLM
+
+/*
+ * These two lengths are copied from linux/dlmconstants.h
+ * They are the max length of a lockspace name and the max length of a
+ * resource name.
+ */
+
+#define DLM_LOCKSPACE_LEN 64
+#define DLM_RESNAME_MAXLEN 64
+
+struct dlm_lksb {
+ int sb_status;
+ uint32_t sb_lkid;
+ char sb_flags;
+ char *sb_lvbptr;
+};
+
+/* lksb flags */
+#define DLM_SBF_DEMOTED 0x01
+#define DLM_SBF_VALNOTVALID 0x02
+#define DLM_SBF_ALTMODE 0x04
+
+/* dlm_new_lockspace flags */
+#define DLM_LSFL_NODIR 0x00000001
+#define DLM_LSFL_TIMEWARN 0x00000002
+#define DLM_LSFL_FS 0x00000004
+#define DLM_LSFL_NEWEXCL 0x00000008
+
+#endif
+
+
+#if 0
+/* Dummy definition to keep linkages */
+struct dlm_queryinfo;
+#endif
+
+extern int dlm_kernel_version(uint32_t *maj, uint32_t *min, uint32_t *patch);
+extern void dlm_library_version(uint32_t *maj, uint32_t *min, uint32_t *patch);
+
+
+/*
+ * Using the default lockspace
+ *
+ * lock_resource() - simple sync request or convert (requires pthreads)
+ * unlock_resource() - simple sync unlock (requires pthreads)
+ * dlm_lock() - async request or convert
+ * dlm_unlock() - async unlock or cancel
+ * dlm_lock_wait() - sync request or convert
+ * dlm_unlock_wait() - sync unlock or cancel
+ */
+
+#ifdef _REENTRANT
+extern int lock_resource(const char *resource, int mode, int flags, int *lockid);
+extern int unlock_resource(int lockid);
+#endif
+
+extern int dlm_lock(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unusued */
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range); /* unused */
+
+extern int dlm_unlock(uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb,
+ void *astarg);
+
+extern int dlm_lock_wait(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range); /* unused */
+
+extern int dlm_unlock_wait(uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb);
+
+
+/*
+ * These two are for users that want to do their own FD handling
+ *
+ * dlm_get_fd() - returns fd for the default lockspace for polling and dispatch
+ * dlm_dispatch() - dispatches pending asts and basts
+ */
+
+extern int dlm_get_fd(void);
+extern int dlm_dispatch(int fd);
+
+
+/*
+ * Creating your own lockspace
+ *
+ * dlm_create_lockspace() - create and open a lockspace and return a handle
+ * to it. Privileges are required to create/release.
+ * dlm_new_lockspace() - same as create but allows flags
+ * dlm_open_lockspace() - simply returns a handle for an existing lockspace and
+ * may be called by ordinary users.
+ * dlm_release_lockspace()
+ * dlm_close_lockspace()
+ * dlm_ls_get_fd()
+ *
+ * NOTE: that if you dlm_create_lockspace() then dlm_open_lockspace() you will
+ * have two open files on the same device. Hardly a major problem but I thought
+ * it worth pointing out.
+ */
+
+typedef void *dlm_lshandle_t;
+
+extern dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
+extern int dlm_release_lockspace(const char *name, dlm_lshandle_t ls,
+ int force);
+extern dlm_lshandle_t dlm_open_lockspace(const char *name);
+extern int dlm_close_lockspace(dlm_lshandle_t ls);
+extern int dlm_ls_get_fd(dlm_lshandle_t ls);
+extern dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode,
+ uint32_t flags);
+
+
+/*
+ * Using your own lockspace
+ *
+ * dlm_ls_lock()
+ * dlm_ls_lockx()
+ * dlm_ls_unlock()
+ * dlm_ls_lock_wait()
+ * dlm_ls_unlock_wait()
+ * dlm_ls_deadlock_cancel()
+ * dlm_ls_purge()
+ */
+
+extern int dlm_ls_lock(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range); /* unused */
+
+extern int dlm_ls_lockx(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ uint64_t *xid,
+ uint64_t *timeout);
+
+extern int dlm_ls_unlock(dlm_lshandle_t lockspace,
+ uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb,
+ void *astarg);
+
+extern int dlm_ls_lock_wait(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range); /* unused */
+
+extern int dlm_ls_unlock_wait(dlm_lshandle_t lockspace,
+ uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb);
+
+extern int dlm_ls_deadlock_cancel(dlm_lshandle_t ls,
+ uint32_t lkid,
+ uint32_t flags);
+
+extern int dlm_ls_purge(dlm_lshandle_t lockspace,
+ int nodeid,
+ int pid);
+
+
+/*
+ * For threaded applications
+ *
+ * dlm_pthread_init()
+ * dlm_ls_pthread_init() - call this before any locking operations and the ASTs
+ * will be delivered in their own thread.
+ * dlm_pthread_cleanup() - call the cleanup routine at application exit
+ * (optional) or, if the locking functions are in a
+ * shared library that is to be unloaded.
+ *
+ * dlm_close/release_lockspace() will tidy the threads for a non-default
+ * lockspace
+ */
+
+#ifdef _REENTRANT
+extern int dlm_pthread_init(void);
+extern int dlm_ls_pthread_init(dlm_lshandle_t lockspace);
+extern int dlm_pthread_cleanup(void);
+#endif
+
+
+/*
+ * Lock modes
+ */
+
+#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 */
+
+
+/*
+ * Locking flags - these match the ones in dlm.h
+ */
+
+#define LKF_NOQUEUE 0x00000001
+#define LKF_CANCEL 0x00000002
+#define LKF_CONVERT 0x00000004
+#define LKF_VALBLK 0x00000008
+#define LKF_QUECVT 0x00000010
+#define LKF_IVVALBLK 0x00000020
+#define LKF_CONVDEADLK 0x00000040
+#define LKF_PERSISTENT 0x00000080
+#define LKF_NODLCKWT 0x00000100
+#define LKF_NODLCKBLK 0x00000200
+#define LKF_EXPEDITE 0x00000400
+#define LKF_NOQUEUEBAST 0x00000800
+#define LKF_HEADQUE 0x00001000
+#define LKF_NOORDER 0x00002000
+#define LKF_ORPHAN 0x00004000
+#define LKF_ALTPR 0x00008000
+#define LKF_ALTCW 0x00010000
+#define LKF_FORCEUNLOCK 0x00020000
+#define LKF_TIMEOUT 0x00040000
+#define LKF_WAIT 0x80000000 /* Userspace only, for sync API calls */
+
+/*
+ * Extra return codes used by the DLM
+ */
+
+#define ECANCEL 0x10001
+#define EUNLOCK 0x10002
+#define EINPROG 0x10003 /* lock operation is in progress */
+
+#endif
+
diff --git a/libdlm/libdlm_internal.h b/libdlm/libdlm_internal.h
new file mode 100644
index 0000000..c8b270e
--- /dev/null
+++ b/libdlm/libdlm_internal.h
@@ -0,0 +1,9 @@
+
+/* Needed before we include the kernel libdlm header */
+#define __user
+typedef uint8_t __u8;
+typedef uint16_t __u16;
+typedef uint32_t __u32;
+#define BUILDING_LIBDLM
+
+
diff --git a/libdlm/man/dlm_cleanup.3 b/libdlm/man/dlm_cleanup.3
new file mode 100644
index 0000000..db4a9cf
--- /dev/null
+++ b/libdlm/man/dlm_cleanup.3
@@ -0,0 +1 @@
+.so man3/libdlm.3
diff --git a/libdlm/man/dlm_close_lockspace.3 b/libdlm/man/dlm_close_lockspace.3
new file mode 100644
index 0000000..e5db408
--- /dev/null
+++ b/libdlm/man/dlm_close_lockspace.3
@@ -0,0 +1 @@
+.so man3/dlm_create_lockspace.3
diff --git a/libdlm/man/dlm_create_lockspace.3 b/libdlm/man/dlm_create_lockspace.3
new file mode 100644
index 0000000..3879e85
--- /dev/null
+++ b/libdlm/man/dlm_create_lockspace.3
@@ -0,0 +1,94 @@
+.TH DLM_CREATE_LOCKSPACE 3 "July 5, 2007" "libdlm functions"
+.SH NAME
+dlm_create_lockspace, dlm_open_lockspace, dlm_close_lockspace, dlm_release_lockspace \-
manipulate DLM lockspaces
+.SH SYNOPSIS
+.nf
+ #include <libdlm.h>
+
+dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
+dlm_lshandle_t dlm_new_lockspace(const char *name, mode_t mode,
+ uint32_t flags);
+dlm_lshandle_t dlm_open_lockspace(const char *name);
+int dlm_close_lockspace(dlm_lshandle_t ls);
+int dlm_release_lockspace(const char *name, dlm_lshandle_t ls,
+ int force);
+
+.fi
+.SH DESCRIPTION
+The DLM allows locks to be partitioned into "lockspaces", and these can be
manipulated by userspace calls. It is possible (though not recommended) for an application
to have multiple lockspaces open at one time.
+
+Many of the DLM calls work on the "default" lockspace, which should be fine for
most users. The calls with _ls_ in them allow you to isolate your application from all
others running in the cluster. Remember, lockspaces are a cluster-wide resource, so if you
create a lockspace called "myls" it will share locks with a lockspace called
"myls" on all nodes. These calls allow users to create & remove lockspaces,
and users to connect to existing lockspace to store their locks there.
+.PP
+.SS
+dlm_lshandle_t dlm_create_lockspace(const char *name, mode_t mode);
+.br
+This creates a lockspace called <name> and the mode of the file user to access it
will be <mode> (subject to umask as usual). The lockspace must not already exist on
this node, if it does -1 will be returned and errno will be set to EEXIST. If you really
want to use this lockspace you can then use dlm_open_lockspace() below. The name is the
name of a misc device that will be created in /dev/misc.
+.br
+On success a handle to the lockspace is returned, which can be used to pass into
subsequent dlm_ls_lock/unlock calls. Make no assumptions as to the content of this handle
as it's content may change in future.
+.br
+The caller must have CAP_SYSADMIN privileges to do this operation.
+.PP
+Return codes:
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
+.nf
+EINVAL An invalid parameter was passed to the call
+ENOMEM A (kernel) memory allocation failed
+EEXIST The lockspace already exists
+EPERM Process does not have capability to create lockspaces
+ENOSYS A fatal error occurred initializing the DLM
+Any error returned by the open() system call
+.fi
+.SS
+int dlm_new_lockspace(const char *name, mode_t mode, uint32_t flags)
+.PP
+Performs the same function as
+.B dlm_create_lockspace()
+above, but passes some creation flags to the call that affect the lockspace being
created. Currently supported flags are:
+.nf
+DLM_LSFL_NODIR the lockspace should not use a resource directory
+DLM_LSFL_TIMEWARN the dlm should emit warnings over netlink when locks
+ have been waiting too long; required for deadlock
+ detection
+.fi
+.SS
+int dlm_release_lockspace(const char *name, dlm_lshandle_t ls, int force)
+.PP
+Deletes a lockspace. If the lockspace still has active locks then -1 will be returned and
errno set to EBUSY. Both the lockspace handle /and/ the name must be specified. This call
also closes the lockspace and stops the thread associated with the lockspace, if any.
+.br
+Note that other nodes in the cluster may still have locks open on this lockspace. This
call only removes the lockspace from the current node. If the force flag is set then the
lockspace will be removed even if another user on this node has active locks in it.
Existing users will NOT be notified if you do this, so be careful.
+.br
+The caller must have CAP_SYSADMIN privileges to do this operation.
+.PP
+Return codes:
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
+.nf
+EINVAL An invalid parameter was passed to the call
+EPERM Process does not have capability to release lockspaces
+EBUSY The lockspace could not be freed because it still
+ contains locks and force was not set.
+.fi
+
+.SS
+dlm_lshandle_t dlm_open_lockspace(const char *name)
+.PP
+Opens an already existing lockspace and returns a handle to it.
+.PP
+Return codes:
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to an error returned by the open() system call
+.SS
+int dlm_close_lockspace(dlm_lshandle_t ls)
+.br
+Close the lockspace. Any locks held by this process will be freed. If a thread is
associated with this lockspace then it will be stopped.
+.PP
+Return codes:
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
+.nf
+EINVAL lockspace was not a valid lockspace handle
+.fi
+
+
+.SH SEE ALSO
+
+.BR libdlm (3),
+.BR dlm_unlock (3),
+.BR dlm_lock (3),
diff --git a/libdlm/man/dlm_dispatch.3 b/libdlm/man/dlm_dispatch.3
new file mode 100644
index 0000000..db4a9cf
--- /dev/null
+++ b/libdlm/man/dlm_dispatch.3
@@ -0,0 +1 @@
+.so man3/libdlm.3
diff --git a/libdlm/man/dlm_get_fd.3 b/libdlm/man/dlm_get_fd.3
new file mode 100644
index 0000000..db4a9cf
--- /dev/null
+++ b/libdlm/man/dlm_get_fd.3
@@ -0,0 +1 @@
+.so man3/libdlm.3
diff --git a/libdlm/man/dlm_lock.3 b/libdlm/man/dlm_lock.3
new file mode 100644
index 0000000..3c5f8b5
--- /dev/null
+++ b/libdlm/man/dlm_lock.3
@@ -0,0 +1,239 @@
+.TH DLM_LOCK 3 "July 5, 2007" "libdlm functions"
+.SH NAME
+dlm_lock \- acquire or convert a DLM lock
+.SH SYNOPSIS
+.nf
+ #include <libdlm.h>
+
+int dlm_lock(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range); /* unused */
+
+int dlm_lock_wait(uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range); /* unused */
+
+int dlm_ls_lock(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ void (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ void *range); /* unused */
+
+int dlm_ls_lock_wait(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unusued */
+ void *bastarg,
+ void (*bastaddr) (void *bastarg),
+ void *range); /* unused */
+
+int dlm_ls_lockx(dlm_lshandle_t lockspace,
+ uint32_t mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ const void *name,
+ unsigned int namelen,
+ uint32_t parent, /* unused */
+ (*astaddr) (void *astarg),
+ void *astarg,
+ void (*bastaddr) (void *astarg),
+ uint64_t *xid,
+ uint64_t *timeout);
+
+
+
+.fi
+.SH DESCRIPTION
+dlm_lock and its variants acquire and convert locks in the DLM.
+.PP
+dlm_lock() operations are asynchronous. If the call to dlm_lock returns an error then the
operation has failed and the AST routine will not be called. If dlm_lock returns 0 it is
still possible that the lock operation will fail. The AST routine will be called when the
locking is complete or has failed and the status is returned in the lksb.
+.B dlm_lock_wait()
+will wait until the lock operation has completed and returns the final completion
status.
+.B dlm_ls_lock()
+is the same as
+.B dlm_lock()
+but takes a lockspace argument. This lockspace must have been previously opened by
+.B dlm_lockspace_open() or
+.B dlm_lockspace_create().
+.PP
+For conversion operations the name and namelen are ignored and the lock ID in the LKSB is
used to identify the lock to be converted.
+.PP
+If a lock value block is specified then in general, a grant or a conversion to an
equal-level or higher-level lock mode reads the lock value from the resource into the
caller's lock value block. When a lock conversion from EX or PW to an equal-level or
lower-level lock mode occurs, the contents of the caller's lock value block are
written into the resource. If the LVB is invalidated the lksb.sb_flags member will be set
to DLM_SBF_VALNOTVALID. Lock values blocks are always 32 bytes long.
+.PP
+If the AST routines or parameter are passed to a conversion operation then they will
overwrite those values that were passed to a previous dlm_lock call.
+.PP
+.B mode
+Lock mode to acquire or convert to.
+.nf
+ LKM_NLMODE NULL Lock
+ LKM_CRMODE Concurrent read
+ LKM_CWMODE Concurrent write
+ LKM_PRMODE Protected read
+ LKM_PWMODE Protected write
+ LKM_EXMODE Exclusive
+.fi
+.PP
+.B flags
+Affect the operation of the lock call:
+.nf
+ LKF_NOQUEUE Don't queue the lock. If it cannot be granted return
+ -EAGAIN
+ LKF_CONVERT Convert an existing lock
+ LKF_VALBLK Lock has a value block
+ LKF_QUECVT Put conversion to the back of the queue
+ LKF_EXPEDITE Grant a NL lock immediately regardless of other locks
+ on the conversion queue
+ LKF_PERSISTENT Specifies a lock that will not be unlocked when the
+ process exits; it will become an orphan lock.
+ LKF_CONVDEADLK Enable internal conversion deadlock resolution where
+ the lock's granted mode may be set to NL and
+ DLM_SBF_DEMOTED is returned in lksb.sb_flags.
+ LKF_NODLCKWT Do not consider this lock when trying to detect
+ deadlock conditions.
+ LKF_NODLCKBLK Not implemented
+ LKF_NOQUEUEBAST Send blocking ASTs even for NOQUEUE operations
+ LKF_HEADQUE Add locks to the head of the convert or waiting queue
+ LKF_NOORDER Avoid the VMS rules on grant order
+ LKF_ALTPR If the requested mode can't be granted (generally CW),
+ try to grant in PR and return DLM_SBF_ALTMODE.
+ LKF_ALTCW If the requested mode can't be granted (generally PR),
+ try to grant in CW and return DLM_SBF_ALTMODE.
+ LKF_TIMEOUT The lock will time out per the timeout arg.
+
+.fi
+.PP
+.B lksb
+Lock Status block
+.br
+This structure contains the returned lock ID, the actual
+status of the lock operation (all lock ops are asynchronous)
+and the value block if LKF_VALBLK is set.
+.PP
+.B name
+.br
+Name of the lock. Can be binary, max 64 bytes. Ignored for lock
+conversions. (Should be a string to work with debugging tools.)
+.PP
+.B namelen
+.br
+Length of the above name. Ignored for lock conversions.
+.PP
+.B parent
+.br
+ID of parent lock or NULL if this is a top-level lock. This is currently unused.
+.PP
+.B ast
+.br
+Address of AST routine to be called when the lock operation
+completes. The final completion status of the lock will be
+in the lksb. the AST routine must not be NULL.
+.PP
+.B astargs
+.br
+Argument to pass to the AST routine (most people pass the lksb
+in here but it can be anything you like.)
+.PP
+.B bast
+.br
+Blocking AST routine. address of a function to call if this
+lock is blocking another. The function will be called with
+astargs.
+.PP
+.B range
+.br
+This is unused.
+.PP
+.B xid
+.br
+Optional transaction ID for deadlock detection.
+.PP
+.B timeout
+.br
+Timeout in centiseconds. If it takes longer than this to acquire the lock
+(usually because it is already blocked by another lock), then the AST
+will trigger with ETIMEDOUT as the status. If the lock operation is a conversion
+then the lock will remain at its current status. If this is a new lock then
+the lock will not exist and any LKB in the lksb will be invalid. This is
+ignored without the LKF_TIMEOUT flag.
+.PP
+.SS Return values
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
+.PP
+.nf
+EINVAL An invalid parameter was passed to the call (eg bad lock
+ mode or flag)
+ENOMEM A (kernel) memory allocation failed
+EAGAIN LKF_NOQUEUE was requested and the lock could not be
+ granted
+EBUSY The lock is currently being locked or converted
+EFAULT The userland buffer could not be read/written by the
+ kernel (this indicates a library problem)
+EDEADLOCK The lock operation is causing a deadlock and has been
+ cancelled. If this was a conversion then the lock is
+ reverted to its previously granted state. If it was a
+ new lock then it has not been granted. (NB Only
+ conversion deadlocks are currently detected)
+.PP
+If an error is returned in the AST, then lksb.sb_status is set to the one of the above
values instead of zero.
+.SS Structures
+.nf
+struct dlm_lksb {
+ int sb_status; /* Final status of lock operation */
+ uint32_t sb_lkid; /* ID of lock. Returned from dlm_lock()
+ on first use. Used as input to
+ dlm_lock() for a conversion operation */
+ char sb_flags; /* Completion flags, see above */
+ char sb_lvbptr; /* Optional pointer to lock value block */
+};
+
+.fi
+.SH EXAMPLE
+.nf
+int status;
+struct dlm_lksb lksb;
+
+status = dlm_lock_wait(LKM_EXMODE,
+ &lksb,
+ LKF_NOQUEUE,
+ "MyLock",
+ strlen("MyLock"),
+ 0, // Parent,
+ NULL, // bast arg
+ NULL, // bast routine,
+ NULL); // Range
+
+if (status == 0)
+ dlm_unlock_wait(lksb.sb_lkid, 0, &lksb);
+
+.fi
+
+.SH SEE ALSO
+
+.BR libdlm (3),
+.BR dlm_unlock (3),
+.BR dlm_open_lockspace (3),
+.BR dlm_create_lockspace (3),
+.BR dlm_close_lockspace (3),
+.BR dlm_release_lockspace (3)
diff --git a/libdlm/man/dlm_lock_wait.3 b/libdlm/man/dlm_lock_wait.3
new file mode 100644
index 0000000..a99225c
--- /dev/null
+++ b/libdlm/man/dlm_lock_wait.3
@@ -0,0 +1 @@
+.so man3/dlm_lock.3
diff --git a/libdlm/man/dlm_ls_lock.3 b/libdlm/man/dlm_ls_lock.3
new file mode 100644
index 0000000..a99225c
--- /dev/null
+++ b/libdlm/man/dlm_ls_lock.3
@@ -0,0 +1 @@
+.so man3/dlm_lock.3
diff --git a/libdlm/man/dlm_ls_lock_wait.3 b/libdlm/man/dlm_ls_lock_wait.3
new file mode 100644
index 0000000..a99225c
--- /dev/null
+++ b/libdlm/man/dlm_ls_lock_wait.3
@@ -0,0 +1 @@
+.so man3/dlm_lock.3
diff --git a/libdlm/man/dlm_ls_lockx.3 b/libdlm/man/dlm_ls_lockx.3
new file mode 100644
index 0000000..a99225c
--- /dev/null
+++ b/libdlm/man/dlm_ls_lockx.3
@@ -0,0 +1 @@
+.so man3/dlm_lock.3
diff --git a/libdlm/man/dlm_ls_pthread_init.3 b/libdlm/man/dlm_ls_pthread_init.3
new file mode 100644
index 0000000..db4a9cf
--- /dev/null
+++ b/libdlm/man/dlm_ls_pthread_init.3
@@ -0,0 +1 @@
+.so man3/libdlm.3
diff --git a/libdlm/man/dlm_ls_unlock.3 b/libdlm/man/dlm_ls_unlock.3
new file mode 100644
index 0000000..91babd2
--- /dev/null
+++ b/libdlm/man/dlm_ls_unlock.3
@@ -0,0 +1 @@
+.so man3/dlm_unlock.3
diff --git a/libdlm/man/dlm_ls_unlock_wait.3 b/libdlm/man/dlm_ls_unlock_wait.3
new file mode 100644
index 0000000..91babd2
--- /dev/null
+++ b/libdlm/man/dlm_ls_unlock_wait.3
@@ -0,0 +1 @@
+.so man3/dlm_unlock.3
diff --git a/libdlm/man/dlm_new_lockspace.3 b/libdlm/man/dlm_new_lockspace.3
new file mode 100644
index 0000000..e5db408
--- /dev/null
+++ b/libdlm/man/dlm_new_lockspace.3
@@ -0,0 +1 @@
+.so man3/dlm_create_lockspace.3
diff --git a/libdlm/man/dlm_open_lockspace.3 b/libdlm/man/dlm_open_lockspace.3
new file mode 100644
index 0000000..e5db408
--- /dev/null
+++ b/libdlm/man/dlm_open_lockspace.3
@@ -0,0 +1 @@
+.so man3/dlm_create_lockspace.3
diff --git a/libdlm/man/dlm_pthread_init.3 b/libdlm/man/dlm_pthread_init.3
new file mode 100644
index 0000000..db4a9cf
--- /dev/null
+++ b/libdlm/man/dlm_pthread_init.3
@@ -0,0 +1 @@
+.so man3/libdlm.3
diff --git a/libdlm/man/dlm_release_lockspace.3 b/libdlm/man/dlm_release_lockspace.3
new file mode 100644
index 0000000..e5db408
--- /dev/null
+++ b/libdlm/man/dlm_release_lockspace.3
@@ -0,0 +1 @@
+.so man3/dlm_create_lockspace.3
diff --git a/libdlm/man/dlm_unlock.3 b/libdlm/man/dlm_unlock.3
new file mode 100644
index 0000000..9023139
--- /dev/null
+++ b/libdlm/man/dlm_unlock.3
@@ -0,0 +1,94 @@
+.TH DLM_UNLOCK 3 "July 5, 2007" "libdlm functions"
+.SH NAME
+dlm_unlock \- unlock a DLM lock
+.SH SYNOPSIS
+.nf
+#include <libdlm.h>
+
+int dlm_unlock(uint32_t lkid,
+ uint32_t flags, struct dlm_lksb *lksb, void *astarg);
+
+int dlm_unlock_wait(uint32_t lkid,
+ uint32_t flags, struct dlm_lksb *lksb);
+
+.fi
+.SH DESCRIPTION
+.B dlm_unlock()
+unlocks a lock previously acquired by dlm_lock and its variants.
+.PP
+Unless
+.B dlm_unlock_wait()
+is used unlocks are also asynchronous. The AST routine is called when the resource is
successfully unlocked (see below).
+.PP
+.B lkid
+Lock ID as returned in the lksb
+.PP
+.B flags
+flags affecting the unlock operation:
+.nf
+ LKF_CANCEL Cancel a pending lock or conversion.
+ This returns the lock to it's previously
+ granted mode (in case of a conversion) or
+ unlocks it (in case of a waiting lock).
+ LKF_IVVALBLK Invalidate value block
+ LKF_FORCEUNLOCK Unlock the lock even if it's waiting.
+.fi
+.PP
+.B lksb
+LKSB to return status and value block information.
+.PP
+.B astarg
+New parameter to be passed to the completion AST.
+The completion AST routine is the
+last completion AST routine specified in a dlm_lock call.
+If dlm_lock_wait() was the last routine to issue a lock,
+dlm_unlock_wait() must be used to release the lock. If dlm_lock()
+was the last routine to issue a lock then either dlm_unlock()
+or dlm_unlock_wait() may be called.
+.PP
+
+.SS Return values
+0 is returned if the call completed successfully. If not, -1 is returned and errno is set
to one of the following:
+.PP
+.nf
+EINVAL An invalid parameter was passed to the call (eg bad
+ lock mode or flag)
+EINPROGRESS The lock is already being unlocked
+EBUSY The lock is currently being locked or converted
+ENOTEMPTY An attempt to made to unlock a parent lock that still has
+ child locks.
+ECANCEL A lock conversion was successfully cancelled
+EUNLOCK An unlock operation completed successfully
+ (sb_status only)
+EFAULT The userland buffer could not be read/written by the
+ kernel
+.fi
+If an error is returned in the AST, then lksb.sb_status is set to the one of the above
numbers instead of zero.
+.SH EXAMPLE
+.nf
+int status;
+struct dlm_lksb lksb;
+
+status = dlm_lock_wait(LKM_EXMODE,
+ &lksb,
+ LKF_NOQUEUE,
+ "MyLock",
+ strlen("MyLock"),
+ 0, // Parent,
+ NULL, // bast arg
+ NULL, // bast routine,
+ NULL); // Range
+
+if (status == 0)
+ dlm_unlock_wait(lksb.sb_lkid, 0, &lksb);
+
+.fi
+
+.SH SEE ALSO
+
+.BR libdlm (3),
+.BR dlm_lock (3),
+.BR dlm_open_lockspace (3),
+.BR dlm_create_lockspace (3),
+.BR dlm_close_lockspace (3),
+.BR dlm_release_lockspace (3)
diff --git a/libdlm/man/dlm_unlock_wait.3 b/libdlm/man/dlm_unlock_wait.3
new file mode 100644
index 0000000..91babd2
--- /dev/null
+++ b/libdlm/man/dlm_unlock_wait.3
@@ -0,0 +1 @@
+.so man3/dlm_unlock.3
diff --git a/libdlm/man/libdlm.3 b/libdlm/man/libdlm.3
new file mode 100644
index 0000000..a020560
--- /dev/null
+++ b/libdlm/man/libdlm.3
@@ -0,0 +1,105 @@
+.TH LIBDLM 3 "July 5, 2007" "libdlm functions"
+.SH NAME
+libdlm \- dlm_get_fd, dlm_dispatch, dlm_pthread_init, dlm_ls_pthread_init, dlm_cleanup
+.SH SYNOPSIS
+.nf
+#include <libdlm.h>
+.nf
+int dlm_pthread_init();
+int dlm_ls_pthread_init(dlm_lshandle_t lockspace);
+int dlm_pthread_cleanup();
+int dlm_get_fd(void);
+int dlm_dispatch(int fd);
+
+link with -ldlm
+.fi
+.SH DESCRIPTION
+libdlm provides the programmatic userspace interface to the Distributed Lock manager. It
provides all the calls you need to manipulate locks & lockspaces
+.br
+libdlm can be used in pthread or non-pthread applications. For pthread applications
simply call the following function before doing any lock operations. If you're using
pthreads, remember to define _REENTRANT at the top of the program or using -D_REENTRANT on
the compile line.
+.br
+pthreads is the normal way of using the DLM. This way you simply initialize the DLM's
thread and all the AST routines will be delivered in that thread. You just call the
dlm_lock() etc routines in the main line of your program.
+.br
+If you don't want to use pthreads or you want to handle the dlm callback ASTs
yourself then you can get an FD handle to the DLM device and call
+.B dlm_dispatch()
+on it whenever it becomes active. That was ASTs will be delivered in the context of the
thread/process that called
+.B dlm_dispatch().
+
+
+.SS int dlm_pthread_init()
+.br
+Creates a thread to receive all lock ASTs. The AST callback function for lock operations
will be called in the context of this thread. If there is a potential for local resource
access conflicts you must provide your own pthread-based locking in the AST routine.
+.PP
+.SS int dlm_ls_pthread_init(dlm_lshandle_t lockspace)
+.br
+As dlm_pthread_init but initializes a thread for the specified lockspace.
+.PP
+.SS int dlm_pthread_cleanup()
+.br
+Cleans up the default lockspace threads after use. Normally you don't need to call
this, but if the locking code is in a dynamically loadable shared library this will
probably be necessary.
+.br
+For non-pthread based applications the DLM provides a file descriptor that the program
can feed into poll/select. If activity is detected on that FD then a dispatch function
should be called:
+.PP
+.SS int dlm_get_fd()
+Returns a file-descriptor for the DLM suitable for passing in to poll() or select().
+.PP
+.SS int dlm_dispatch(int fd)
+.br
+Reads from the DLM and calls any AST routines that may be needed. This routine runs in
the context of the caller so no extra locking is needed to protect local resources.
+.PP
+
+
+.SH libdlm_lt
+There also exists a "light" version of the libdlm library called libdlm_lt.
This is provided for those applications that do not want to use pthread functions. If you
use this library it is important that your application is NOT compiled with -D_REENTRANT
or linked with libpthread.
+
+.SH EXAMPLES
+
+Create a lockspace and start a thread to deliver its callbacks:
+.nf
+dlm_lshandle_t ls;
+
+ls = dlm_create_lockspace("myLS", 0660);
+dlm_ls_pthread_init(ls);
+
+ ...
+
+status = dlm_ls_lock(ls,
+ ... );
+
+
+.fi
+.PP
+ Using poll(2) to wait for and dispatch ASTs
+.nf
+
+
+static int poll_for_ast(dlm_lshandle_t ls)
+{
+ struct pollfd pfd;
+
+ pfd.fd = dlm_ls_get_fd(ls);
+ pfd.events = POLLIN;
+ while (!ast_called)
+ {
+ if (poll(&pfd, 1, 0) < 0)
+ {
+ perror("poll");
+ return -1;
+ }
+ dlm_dispatch(dlm_ls_get_fd(ls));
+ }
+ ast_called = 0;
+ return 0;
+}
+.fi
+
+
+.SH SEE ALSO
+
+.BR libdlm (3),
+.BR dlm_lock (3),
+.BR dlm_unlock (3),
+.BR dlm_open_lockspace (3),
+.BR dlm_create_lockspace (3),
+.BR dlm_close_lockspace (3),
+.BR dlm_release_lockspace (3)