src/token_manager.c | 3
tests/Makefile | 9
tests/sanlk_load.c | 609 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 618 insertions(+), 3 deletions(-)
New commits:
commit fd36a8f91b0eb40dac1f3d93f26e9115136438de
Author: David Teigland <teigland(a)redhat.com>
Date: Fri Jun 17 16:34:23 2011 -0500
sanlk_load: add new test
diff --git a/src/token_manager.c b/src/token_manager.c
index c0fc485..0c85197 100644
--- a/src/token_manager.c
+++ b/src/token_manager.c
@@ -68,7 +68,8 @@ int add_resource(struct token *token, int pid)
r = find_resource(token, &resources);
if (r) {
- log_errot(token, "add_resource name exists");
+ if (!com.quiet_fail)
+ log_errot(token, "add_resource name exists");
rv = -EEXIST;
goto out;
}
diff --git a/tests/Makefile b/tests/Makefile
index 4041a8e..77b60c2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,6 +1,8 @@
TARGET = devcount
+TARGET2 = sanlk_load
SOURCE = devcount.c
+SOURCE2 = sanlk_load.c
CFLAGS += -D_GNU_SOURCE -g \
-Wall \
@@ -23,11 +25,14 @@ CFLAGS += -D_GNU_SOURCE -g \
LDFLAGS = -lrt -laio -lblkid -lsanlock
-all: $(TARGET)
+all: $(TARGET) $(TARGET2)
$(TARGET): $(SOURCE)
$(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE) -o $@ -L. -L../src
+$(TARGET2): $(SOURCE2)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(SOURCE2) -o $@ -L. -L../src
+
clean:
- rm -f *.o *.so *.so.* $(TARGET)
+ rm -f *.o *.so *.so.* $(TARGET) $(TARGET2)
diff --git a/tests/sanlk_load.c b/tests/sanlk_load.c
new file mode 100644
index 0000000..27d2221
--- /dev/null
+++ b/tests/sanlk_load.c
@@ -0,0 +1,609 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <sys/mount.h>
+#include <sys/signalfd.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+#include <signal.h>
+
+#include "sanlock.h"
+#include "sanlock_admin.h"
+#include "sanlock_resource.h"
+#include "sanlock_direct.h"
+
+#define ONEMB 1048576
+#define LEASE_SIZE ONEMB
+
+#define MAX_LS_COUNT 64
+#define MAX_RES_COUNT 64
+#define DEFAULT_LS_COUNT 4
+#define DEFAULT_RES_COUNT 4
+#define DEFAULT_PID_COUNT 4
+#define MAX_RV 300
+
+char lock_disk_base[PATH_MAX];
+int lock_state[MAX_LS_COUNT][MAX_RES_COUNT];
+int ls_count = DEFAULT_LS_COUNT;
+int res_count = DEFAULT_RES_COUNT;
+int pid_count = DEFAULT_PID_COUNT;
+int our_hostid;
+int acquire_rv[MAX_RV];
+int release_rv[MAX_RV];
+int debug = 0;
+
+
+#define log_debug(fmt, args...) \
+do { \
+ if (debug) printf("%llu " fmt "\n", (unsigned long long)time(NULL),
##args); \
+} while (0)
+
+#define log_error(fmt, args...) \
+do { \
+ printf("ERROR %llu " fmt "\n", (unsigned long long)time(NULL),
##args); \
+} while (0)
+
+
+static int get_rand(int a, int b)
+{
+ return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0));
+}
+
+static void save_rv(int rv, int acquire)
+{
+ if (rv > 0)
+ goto fail;
+ if (-rv > MAX_RV)
+ goto fail;
+
+ if (acquire) {
+ if (!rv)
+ acquire_rv[0]++;
+ else
+ acquire_rv[-rv]++;
+ } else {
+ if (!rv)
+ release_rv[0]++;
+ else
+ release_rv[-rv]++;
+ }
+ return;
+
+ fail:
+ log_error("save_rv %d %d", rv, acquire);
+ while (1)
+ sleep(10);
+}
+
+static void display_rv(int pid)
+{
+ int i;
+
+ printf("%llu %d results acquire ", (unsigned long long)time(NULL), pid);
+ for (i = 0; i < MAX_RV; i++) {
+ if (acquire_rv[i])
+ printf("%d:%d ", i, acquire_rv[i]);
+ }
+
+ printf("release ");
+ for (i = 0; i < MAX_RV; i++) {
+ if (release_rv[i])
+ printf("%d:%d ", i, release_rv[i]);
+ }
+ printf("\n");
+}
+
+static void dump_lock_state(int pid)
+{
+ int i, j;
+
+ for (i = 0; i < ls_count; i++) {
+ for (j = 0; j < res_count; j++) {
+ if (!lock_state[i][j])
+ continue;
+ log_error("%d lockspace%d:resource%d", pid, i, j);
+ }
+ }
+}
+
+static int check_lock_state(int pid, int result, int count, char *res_state)
+{
+ char buf[128];
+ char *found;
+ int found_count = 0;
+ int none_count = 0;
+ int bad_count = 0;
+ int i, j;
+
+ if (result < 0)
+ goto fail;
+
+ for (i = 0; i < ls_count; i++) {
+ for (j = 0; j < res_count; j++) {
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "lockspace%d:resource%d:", i, j);
+
+ found = strstr(res_state, buf);
+
+ if (found && lock_state[i][j]) {
+ found_count++;
+ } else if (!found && !lock_state[i][j]) {
+ none_count++;
+ } else {
+ bad_count++;
+
+ log_error("%d check_lock_state %s lock_state %d res_state %s",
+ pid, buf, lock_state[i][j], res_state);
+ }
+ }
+ }
+
+ if ((found_count != count) || bad_count)
+ goto fail;
+
+ if (res_state)
+ free(res_state);
+ return 0;
+
+ fail:
+ log_error("%d check_lock_state result %d count %d res_state %s",
+ pid, result, count, res_state);
+
+ log_error("%d check_lock_state found %d none %d bad %d",
+ pid, found_count, none_count, bad_count);
+
+ dump_lock_state(pid);
+
+ while (1)
+ sleep(10);
+}
+
+static int add_lockspaces(void)
+{
+ struct sanlk_lockspace ls;
+ int i, rv;
+
+ for (i = 0; i < ls_count; i++) {
+ memset(&ls, 0, sizeof(ls));
+ sprintf(ls.host_id_disk.path, "%s%d", lock_disk_base, i);
+ sprintf(ls.name, "lockspace%d", i);
+ ls.host_id = our_hostid;
+
+ rv = sanlock_add_lockspace(&ls, 0);
+ if (rv < 0) {
+ log_error("sanlock_add_lockspace error %d %s", rv,
+ ls.host_id_disk.path);
+ return -1;
+ }
+
+ log_debug("add lockspace %s:%llu:%s:%d",
+ ls.name, (unsigned long long)ls.host_id,
+ ls.host_id_disk.path, 0);
+ }
+
+ return 0;
+}
+
+static int do_one(int pid, int fd, int ls1, int res1, int *full, int acquire)
+{
+ char buf1[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ struct sanlk_resource *r1;
+ int rv;
+
+ memset(buf1, 0, sizeof(buf1));
+ r1 = (struct sanlk_resource *)&buf1;
+
+ sprintf(r1->lockspace_name, "lockspace%d", ls1);
+ sprintf(r1->name, "resource%d", res1);
+ sprintf(r1->disks[0].path, "%s%d", lock_disk_base, ls1);
+ r1->disks[0].offset = (res1+1)*LEASE_SIZE;
+ r1->num_disks = 1;
+
+ if (acquire) {
+ rv = sanlock_acquire(fd, -1, 0, 1, &r1, NULL);
+
+ if (rv == -E2BIG || rv == -ENOENT)
+ *full = 1;
+ } else {
+ rv = sanlock_release(fd, -1, 0, 1, &r1);
+ }
+
+ log_debug("%d %s %d,%d = %d",
+ pid, acquire ? "acquire" : "release", ls1, res1, rv);
+
+ save_rv(rv, acquire);
+
+ return rv;
+}
+
+static int do_two(int pid, int fd, int ls1, int res1, int ls2, int res2, int *full, int
acquire)
+{
+ char buf1[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ char buf2[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ struct sanlk_resource *r1;
+ struct sanlk_resource *r2;
+ struct sanlk_resource **res_args;
+ int rv;
+
+ res_args = malloc(2 * sizeof(struct sanlk_resource *));
+ if (!res_args)
+ return -ENOMEM;
+
+ memset(buf1, 0, sizeof(buf1));
+ memset(buf2, 0, sizeof(buf2));
+ r1 = (struct sanlk_resource *)&buf1;
+ r2 = (struct sanlk_resource *)&buf2;
+ res_args[0] = r1;
+ res_args[1] = r2;
+
+ sprintf(r1->lockspace_name, "lockspace%d", ls1);
+ sprintf(r1->name, "resource%d", res1);
+ sprintf(r1->disks[0].path, "%s%d", lock_disk_base, ls1);
+ r1->disks[0].offset = (res1+1)*LEASE_SIZE;
+ r1->num_disks = 1;
+
+ sprintf(r2->lockspace_name, "lockspace%d", ls2);
+ sprintf(r2->name, "resource%d", res2);
+ sprintf(r2->disks[0].path, "%s%d", lock_disk_base, ls2);
+ r2->disks[0].offset = (res2+1)*LEASE_SIZE;
+ r2->num_disks = 1;
+
+ if (acquire) {
+ rv = sanlock_acquire(fd, -1, 0, 2, res_args, NULL);
+
+ if (rv == -E2BIG || rv == -ENOENT)
+ *full = 1;
+ } else {
+ rv = sanlock_release(fd, -1, 0, 2, res_args);
+ }
+
+ log_debug("%d %s %d,%d %d,%d = %d",
+ pid, acquire ? "acquire" : "release", ls1, res1, ls2, res2, rv);
+
+ save_rv(rv, acquire);
+
+ free(res_args);
+ return rv;
+}
+
+static int acquire_one(int pid, int fd, int ls1, int res1, int *full)
+{
+ return do_one(pid, fd, ls1, res1, full, 1);
+}
+
+static int acquire_two(int pid, int fd, int ls1, int res1, int ls2, int res2, int *full)
+{
+ return do_two(pid, fd, ls1, res1, ls2, res2, full, 1);
+}
+
+static int release_one(int pid, int fd, int ls1, int res1)
+{
+ return do_one(pid, fd, ls1, res1, NULL, 0);
+}
+
+static int release_two(int pid, int fd, int ls1, int res1, int ls2, int res2)
+{
+ return do_two(pid, fd, ls1, res1, ls2, res2, NULL, 0);
+}
+
+static int release_all(int pid, int fd)
+{
+ int rv;
+
+ rv = sanlock_release(fd, -1, SANLK_REL_ALL, 0, NULL);
+
+ log_debug("%d release all = %d", pid, rv);
+
+ save_rv(rv, 0);
+
+ return rv;
+}
+
+static void inquire_all(int pid, int fd)
+{
+ int rv, count = 0;
+ char *state = NULL;
+
+ rv = sanlock_inquire(fd, -1, 0, &count, &state);
+
+ log_debug("%d inquire all = %d", pid, rv);
+
+ check_lock_state(pid, rv, count, state);
+}
+
+int do_rand_child(void)
+{
+ int ls1, ls2, res1, res2, state1, state2, full;
+ int fd, rv;
+ int iter = 1;
+ int pid = getpid();
+
+ srandom(pid);
+
+ memset(lock_state, 0, sizeof(lock_state));
+
+ fd = sanlock_register();
+ if (fd < 0) {
+ log_error("%d sanlock_register error %d", pid, fd);
+ exit(-1);
+ }
+
+ while (1) {
+ ls1 = get_rand(0, ls_count-1);
+ res1 = get_rand(0, res_count-1);
+ state1 = lock_state[ls1][res1];
+
+ ls2 = -1;
+ res2 = -1;
+ state2 = -1;
+
+ if (get_rand(1, 3) == 2) {
+ ls2 = get_rand(0, ls_count-1);
+ res2 = get_rand(0, res_count-1);
+ state2 = lock_state[ls2][res2];
+
+ if (ls1 == ls2 && res1 == res2) {
+ ls2 = -1;
+ res2 = -1;
+ state2 = -1;
+ }
+ }
+
+ full = 0;
+
+ if (state1 == 0 && state2 == 0) {
+ /* both picks are unlocked, lock both together */
+
+ rv = acquire_two(pid, fd, ls1, res1, ls2, res2, &full);
+ if (!rv) {
+ lock_state[ls1][res1] = 1;
+ lock_state[ls2][res2] = 1;
+ }
+ state1 = -1;
+ state2 = -1;
+ }
+ if (state1 == 1 && state2 == 1) {
+ /* both picks are locked, unlock both together */
+
+ rv = release_two(pid, fd, ls1, res1, ls2, res2);
+ if (!rv) {
+ lock_state[ls1][res1] = 0;
+ lock_state[ls2][res2] = 0;
+ }
+ state1 = -1;
+ state2 = -1;
+ }
+ if (state1 == 0) {
+ rv = acquire_one(pid, fd, ls1, res1, &full);
+ if (!rv)
+ lock_state[ls1][res1] = 1;
+ }
+ if (state2 == 0) {
+ rv = acquire_one(pid, fd, ls2, res2, &full);
+ if (!rv)
+ lock_state[ls2][res2] = 1;
+ }
+ if (state1 == 1) {
+ rv = release_one(pid, fd, ls1, res1);
+ if (!rv)
+ lock_state[ls1][res1] = 0;
+ }
+ if (state2 == 1) {
+ rv = release_one(pid, fd, ls2, res2);
+ if (!rv)
+ lock_state[ls2][res2] = 0;
+ }
+ if (full) {
+ rv = release_all(pid, fd);
+ if (!rv)
+ memset(lock_state, 0, sizeof(lock_state));
+ }
+ if ((iter % 10) == 0) {
+ display_rv(pid);
+ inquire_all(pid, fd);
+ }
+ iter++;
+ }
+}
+
+/*
+ * sanlk_load rand <lock_disk_base> -i <host_id> [-D -s <ls_count> -r
<res_count> -p <pid_count>]
+ */
+
+void get_options(int argc, char *argv[])
+{
+ char optchar;
+ char *optionarg;
+ char *p;
+ int i = 3;
+
+ for (; i < argc; ) {
+ p = argv[i];
+
+ if ((p[0] != '-') || (strlen(p) != 2)) {
+ log_error("unknown option %s", p);
+ log_error("space required before option value");
+ exit(EXIT_FAILURE);
+ }
+
+ optchar = p[1];
+ i++;
+
+ if (optchar == 'D') {
+ debug = 1;
+ continue;
+ }
+
+ if (i >= argc) {
+ log_error("option '%c' requires arg", optchar);
+ exit(EXIT_FAILURE);
+ }
+
+ optionarg = argv[i];
+
+ switch (optchar) {
+ case 'i':
+ our_hostid = atoi(optionarg);
+ break;
+ case 's':
+ ls_count = atoi(optionarg);
+ break;
+ case 'r':
+ res_count = atoi(optionarg);
+ break;
+ case 'p':
+ pid_count = atoi(optionarg);
+ default:
+ log_error("unknown option: %c", optchar);
+ exit(EXIT_FAILURE);
+ }
+
+ i++;
+ }
+}
+
+int do_rand(int argc, char *argv[])
+{
+ int children[pid_count];
+ int run_count = 0;
+ int i, rv, pid, status;
+
+ if (argc < 5)
+ return -1;
+
+ strcpy(lock_disk_base, argv[2]);
+
+ get_options(argc, argv);
+
+ rv = add_lockspaces();
+ if (rv < 0)
+ return rv;
+
+ for (i = 0; i < pid_count; i++) {
+ pid = fork();
+
+ if (!pid) {
+ do_rand_child();
+ exit(-1);
+ }
+
+ children[i] = pid;
+ run_count++;
+ }
+
+ while (run_count) {
+ pid = wait(&status);
+ if (pid > 0)
+ run_count--;
+ }
+
+ /*
+ * periodically:
+ * - kill a random pid, and fork a new one to replace it
+ * - rem a random ls and add it again
+ */
+
+ return 0;
+}
+
+/*
+ * sanlk_load init <lock_disk_base> [<ls_count> <res_count>]
+ * lock_disk_base = /dev/vg/foo
+ *
+ * sanlock direct init -s lockspace0:0:/dev/vg/foo0:0
+ * sanlock direct init -r lockspace0:resource0:/dev/vg/foo0:1M
+ * sanlock direct init -r lockspace0:resource1:/dev/vg/foo0:2M
+ * ...
+ * sanlock direct init -s lockspace1:0:/dev/vg/foo1:0
+ * sanlock direct init -r lockspace1:resource0:/dev/vg/foo1:1M
+ * sanlock direct init -r lockspace1:resource1:/dev/vg/foo1:2M
+ * ...
+ */
+
+#define INIT_NUM_HOSTS 8
+
+int do_init(int argc, char *argv[])
+{
+ char resbuf[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
+ struct sanlk_resource *res;
+ struct sanlk_lockspace ls;
+ int i, j, rv;
+
+ if (argc < 3)
+ return -1;
+
+ strcpy(lock_disk_base, argv[2]);
+
+ if (argc > 3)
+ ls_count = atoi(argv[3]);
+ if (argc > 4)
+ res_count = atoi(argv[4]);
+
+ for (i = 0; i < ls_count; i++) {
+
+ memset(&ls, 0, sizeof(ls));
+ sprintf(ls.host_id_disk.path, "%s%d", lock_disk_base, i);
+ sprintf(ls.name, "lockspace%d", i);
+
+ rv = sanlock_direct_init(&ls, NULL, 0, INIT_NUM_HOSTS, 1);
+ if (rv < 0) {
+ printf("sanlock_direct_init lockspace error %d %s\n", rv,
+ ls.host_id_disk.path);
+ return -1;
+ }
+
+ for (j = 0; j < res_count; j++) {
+
+ memset(resbuf, 0, sizeof(resbuf));
+ res = (struct sanlk_resource *)&resbuf;
+
+ strcpy(res->lockspace_name, ls.name);
+ sprintf(res->name, "resource%d", j);
+ res->num_disks = 1;
+ strcpy(res->disks[0].path, ls.host_id_disk.path);
+ res->disks[0].offset = (j+1)*LEASE_SIZE;
+
+ rv = sanlock_direct_init(NULL, res, 0, INIT_NUM_HOSTS, 0);
+ if (rv < 0) {
+ printf("sanlock_direct_init resource error %d\n", rv);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int rv = -1;
+
+ if (argc < 2)
+ goto out;
+
+ if (!strcmp(argv[1], "init"))
+ rv = do_init(argc, argv);
+
+ else if (!strcmp(argv[1], "rand"))
+ rv = do_rand(argc, argv);
+
+ if (!rv)
+ return 0;
+
+ out:
+ printf("sanlk_load init <lock_disk_base> [<ls_count>
<res_count>]\n");
+ printf("\n");
+ printf("sanlk_load rand\n");
+ printf("\n");
+ return -1;
+}
+