diff options
Diffstat (limited to 'dlm/dlm_klock')
-rw-r--r-- | dlm/dlm_klock/Kbuild | 2 | ||||
-rw-r--r-- | dlm/dlm_klock/Makefile | 6 | ||||
-rw-r--r-- | dlm/dlm_klock/build.sh | 4 | ||||
-rw-r--r-- | dlm/dlm_klock/dlm_klock.c | 372 |
4 files changed, 384 insertions, 0 deletions
diff --git a/dlm/dlm_klock/Kbuild b/dlm/dlm_klock/Kbuild new file mode 100644 index 0000000..b9df5a5 --- /dev/null +++ b/dlm/dlm_klock/Kbuild @@ -0,0 +1,2 @@ +obj-m := dlm_klock.o + diff --git a/dlm/dlm_klock/Makefile b/dlm/dlm_klock/Makefile new file mode 100644 index 0000000..018691f --- /dev/null +++ b/dlm/dlm_klock/Makefile @@ -0,0 +1,6 @@ + +KERNELDIR := /lib/modules/`uname -r`/build + +all:: + $(MAKE) -C $(KERNELDIR) M=`pwd` $@ + diff --git a/dlm/dlm_klock/build.sh b/dlm/dlm_klock/build.sh new file mode 100644 index 0000000..1639c75 --- /dev/null +++ b/dlm/dlm_klock/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +make -C /lib/modules/`uname -r`/build M=`pwd` + diff --git a/dlm/dlm_klock/dlm_klock.c b/dlm/dlm_klock/dlm_klock.c new file mode 100644 index 0000000..a7b533f --- /dev/null +++ b/dlm/dlm_klock/dlm_klock.c @@ -0,0 +1,372 @@ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/file.h> +#include <linux/types.h> +#include <linux/wait.h> +#include <linux/string.h> +#include <linux/list.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/jiffies.h> + +#include <linux/dlm.h> + +static struct proc_dir_entry *proc_dir = NULL; +static char ls_name[32]; +static dlm_lockspace_t *ls; +static struct dlm_lksb lksb; +static wait_queue_head_t wq; +static int ast_done; + +/* + * To test time of remote locks: + * + * node1: + * insmod dlm_klock + * echo "1" > /proc/dlm_klock/join + * echo "3" > /proc/dlm_klock/lock + * + * node2: + * insmod dlm_klock + * echo "1" > /proc/dlm_klock/join + * echo "1000" > /proc/dlm_klock/loop + * + * To test time of local locks: + * + * node1: + * insmod dlm_klock + * echo "1" > /proc/dlm_klock/join + * echo "1000" > /proc/dlm_klock/loop + */ + +static int wait_done(void) +{ + return ast_done; +} + +static void bastfn(void *arg, int mode) +{ + printk("bast %d\n", mode); +} + +static void astfn(void *arg) +{ + ast_done = 1; + wake_up(&wq); +} + +static int lock(int mode) +{ + int rv; + + memset(&lksb, 0, sizeof(lksb)); + + rv = dlm_lock(ls, mode, &lksb, 0, + "klock", 5, 0, astfn, &lksb, bastfn); + + if (rv < 0) { + printk("dlm_lock mode %d error %d\n", mode, rv); + return rv; + } + + wait_event(wq, wait_done()); + ast_done = 0; + + if (lksb.sb_status != 0) { + printk("dlm_lock mode %d status %d\n", mode, lksb.sb_status); + return -1; + } + + return 0; +} + +static int convert(int mode) +{ + int rv; + + rv = dlm_lock(ls, mode, &lksb, DLM_LKF_CONVERT, + "klock", 5, 0, astfn, &lksb, bastfn); + + if (rv < 0) { + printk("dlm_lock convert mode %d error %d\n", mode, rv); + return rv; + } + + wait_event(wq, wait_done()); + ast_done = 0; + + if (lksb.sb_status != 0) { + printk("dlm_lock convert mode %d status %d\n", mode, lksb.sb_status); + return -1; + } + + return 0; +} + +static void unlock(void) +{ + int rv; + + rv = dlm_unlock(ls, lksb.sb_lkid, 0, &lksb, &lksb); + if (rv < 0) { + printk("dlm_unlock %x error %d\n", lksb.sb_lkid, rv); + return; + } + + wait_event(wq, wait_done()); + ast_done = 0; + + if (lksb.sb_status != -DLM_EUNLOCK) + printk("dlm_unlock status %d\n", lksb.sb_status); +} + +static int loop_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long t1, t2, t3, t4; + char str[32]; + int num, i, rv; + + if (!ls) + return -1; + + memset(str, 0, sizeof(str)); + + if (copy_from_user(str, buffer, count)) + return -EFAULT; + num = (int)simple_strtol(str, NULL, 0); + + printk("loop %d begin\n", num); + + t1 = jiffies; + + rv = lock(DLM_LOCK_NL); + if (rv < 0) + return -1; + printk("lock id %x\n", lksb.sb_lkid); + + t2 = jiffies; + + for (i = 0; i < num; i++) { + rv = convert(DLM_LOCK_PR); + if (rv < 0) + break; + + rv = convert(DLM_LOCK_NL); + if (rv < 0) + break; + } + + t3 = jiffies; + + unlock(); + + t4 = jiffies; + + printk("loop %d i %d\n", num, i); + printk("jiffies t1 %lu t2 %lu t3 %lu t4 %lu\n", t1, t2, t3, t4); + printk("ms lock %u loop %u unlock %u total %u\n", + jiffies_to_msecs(t2 - t1), + jiffies_to_msecs(t3 - t2), + jiffies_to_msecs(t4 - t3), + jiffies_to_msecs(t4 - t1)); + + return count; +} + +static int lock_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char str[8]; + int mode; + + if (!ls) + return -1; + + memset(str, 0, sizeof(str)); + + if (copy_from_user(str, buffer, count)) + return -EFAULT; + mode = (int)simple_strtol(str, NULL, 0); + + lock(mode); + + return count; +} + +static int unlock_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (!ls) + return -1; + + unlock(); + return count; +} + + +static int join_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int rv, i; + + if (ls) + return -EBUSY; + + /* + if (copy_from_user(ls_name, buffer, count)) + return -EFAULT; + + memset(ls_name, 0, sizeof(ls_name)); + + for (i = 0; i < strlen(ls_name); i++) { + if (ls_name[i] == '\n') { + ls_name[i] = '\0'; + break; + } + } + */ + +#ifdef RHEL4 + rv = dlm_new_lockspace("klock", 5, &ls, DLM_LSF_NOTIMERS); +#else + rv = dlm_new_lockspace("klock", 5, &ls, DLM_LSFL_FS, 32); +#endif + if (rv < 0) + printk("dlm join error %d\n", rv); + return count; +} + +static int leave_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char str[40]; + int rv; + + if (!ls) + return -EINVAL; + + memset(str, 0, sizeof(str)); + + if (copy_from_user(str, buffer, count)) + return -EFAULT; + + rv = dlm_release_lockspace(ls, 2); + if (rv < 0) + return rv; + + ls = NULL; + return count; +} + +static void create_proc_entries(void) +{ + struct proc_dir_entry *p, *join, *leave, *loop, *lock, *unlock; + + p = join = leave = loop = lock = unlock = NULL; + + proc_dir = proc_mkdir("dlm_klock", 0); + if (!proc_dir) + return; + proc_dir->owner = THIS_MODULE; + + p = create_proc_entry("join", 0666, proc_dir); + if (!p) + goto out; + p->owner = THIS_MODULE; + p->write_proc = join_write; + join = p; + + p = create_proc_entry("leave", 0666, proc_dir); + if (!p) + goto out; + p->owner = THIS_MODULE; + p->write_proc = leave_write; + leave = p; + + p = create_proc_entry("loop", 0666, proc_dir); + if (!p) + goto out; + p->owner = THIS_MODULE; + p->write_proc = loop_write; + loop = p; + + p = create_proc_entry("lock", 0666, proc_dir); + if (!p) + goto out; + p->owner = THIS_MODULE; + p->write_proc = lock_write; + lock = p; + + p = create_proc_entry("unlock", 0666, proc_dir); + if (!p) + goto out; + p->owner = THIS_MODULE; + p->write_proc = unlock_write; + unlock = p; + + return; + + out: + if (join) + remove_proc_entry("join", proc_dir); + if (leave) + remove_proc_entry("leave", proc_dir); + if (loop) + remove_proc_entry("loop", proc_dir); + if (lock) + remove_proc_entry("lock", proc_dir); + if (unlock) + remove_proc_entry("unlock", proc_dir); + + remove_proc_entry("dlm_klock", NULL); + proc_dir = NULL; +} + +static void remove_proc_entries(void) +{ + if (proc_dir) { + remove_proc_entry("join", proc_dir); + remove_proc_entry("leave", proc_dir); + remove_proc_entry("loop", proc_dir); + remove_proc_entry("lock", proc_dir); + remove_proc_entry("unlock", proc_dir); + proc_dir = NULL; + } +} + +int __init init_klock(void) +{ +#ifdef RHEL4 + int rv; + + rv = dlm_init(); + if (rv < 0) + return rv; +#endif + init_waitqueue_head(&wq); + + create_proc_entries(); + + printk("dlm_klock (built %s %s) installed\n", __DATE__, __TIME__); + return 0; +} + +void __exit exit_klock(void) +{ +#ifdef RHEL4 + dlm_release(); +#endif + remove_proc_entries(); +} + +module_init(init_klock); +module_exit(exit_klock); + +MODULE_DESCRIPTION("DLM kernel locking test"); +MODULE_LICENSE("GPL"); + |