sanlock/tests/scripts/sanlk_load.c
2023-12-15 09:46:40 -06:00

1112 lines
20 KiB
C

#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 <syslog.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 512
#define MAX_PID_COUNT 256
#define DEFAULT_LS_COUNT 4
#define DEFAULT_RES_COUNT 4
#define DEFAULT_PID_COUNT 4
#define MAX_RV 300
#define IV -1
#define UN 0
#define SH 3
#define EX 5
int prog_stop;
int debug = 0;
int debug_verbose = 0;
char error_buf[4096];
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 one_mode = 0;
int our_hostid;
int run_sec;
int count_sec;
int error_count;
int error_range = 1;
int acquire_rv[MAX_RV];
int release_rv[MAX_RV];
#define log_debug(fmt, args...) \
do { \
if (debug) printf("%lu " fmt "\n", time(NULL), ##args); \
} while (0)
#define log_error(fmt, args...) \
do { \
memset(error_buf, 0, sizeof(error_buf)); \
snprintf(error_buf, 4095, "%ld " fmt "\n", time(NULL), ##args); \
printf("ERROR: %s\n", error_buf); \
syslog(LOG_ERR, "%s", error_buf); \
error_count++; \
} while (0)
static void sigterm_handler(int sig)
{
if (sig == SIGTERM)
prog_stop = 1;
}
static int get_rand(int a, int b)
{
return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0));
}
static int get_rand_sh_ex(void)
{
unsigned int n;
if (one_mode == SH)
return SH;
if (one_mode == EX)
return EX;
n = (unsigned int)random();;
if (n % 2)
return SH;
return EX;
}
static void save_rv(int pid, 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]++;
}
if (error_range == 1) {
switch (rv) {
case 0:
case -EBUSY:
/* -16 */
case -EEXIST:
/* -17 */
case -EAGAIN:
/* -11 */
break;
default:
log_error("%d ERROR range %d save_rv %d %d", pid, error_range, rv, acquire);
break;
};
} else if (error_range == 2) {
switch (rv) {
case 0:
case -EBUSY:
/* -16 */
case -EEXIST:
/* -17 */
case -EAGAIN:
/* -11 */
break;
case -243:
case -244:
case -245:
break;
default:
log_error("%d ERROR range %d save_rv %d %d", pid, error_range, rv, acquire);
break;
};
}
return;
fail:
log_error("%d save_rv %d %d", pid, rv, acquire);
printf("%lu %d ERROR save_rv %d %d", time(NULL), pid, rv, acquire);
}
static void display_rv(int pid)
{
int i;
printf("%lu %d results acquire ", 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 void dump_inquire_state(int pid, char *state)
{
char *p = state;
int len = strlen(state);
int i;
if (!len)
return;
for (i = 0; i < len; i++) {
if (state[i] == ' ') {
state[i] = '\0';
if (!i)
log_debug("%d leading space", pid);
else
log_debug("%d %s", pid, p);
p = state + i + 1;
}
}
log_debug("%d %s", pid, p);
}
static int check_lock_state(int pid, int result, int count, char *res_state)
{
char buf[128];
char *found = NULL;
int found_count = 0;
int none_count = 0;
int bad_count = 0;
int i, j;
memset(buf, 0, sizeof(buf));
if (result < 0)
goto fail;
if (!count) {
if (res_state) {
log_error("%d check_lock_state zero count res_state %s",
pid, res_state);
}
for (i = 0; i < ls_count; i++) {
for (j = 0; j < res_count; j++) {
if (lock_state[i][j]) {
bad_count++;
log_error("%d check_lock_state zero count %d %d lock", pid, i, j);
}
}
}
if (bad_count)
goto fail;
return 0;
}
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;
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);
printf("%lu %d ERROR check_lock_state result %d count %d found %d bad %d res_state %s",
time(NULL), pid, result, count, found_count, bad_count, res_state);
return -1;
}
#if 0
static int remove_lockspace(int i)
{
struct sanlk_lockspace ls;
int rv;
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;
printf("rem lockspace%d...\n", i);
rv = sanlock_rem_lockspace(&ls, 0);
if (rv < 0) {
log_error("sanlock_rem_lockspace error %d %s", rv,
ls.host_id_disk.path);
return -1;
}
printf("rem done\n");
return 0;
}
#endif
static int add_lockspace(int i)
{
struct sanlk_lockspace ls;
int rv;
int async = !(i % 2);
uint32_t flags = 0;
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;
if (async)
flags = SANLK_ADD_ASYNC;
printf("add lockspace%d...\n", i);
rv = sanlock_add_lockspace(&ls, flags);
if (rv == -EEXIST)
return 0;
if (rv < 0) {
log_error("sanlock_add_lockspace error %d %s", rv,
ls.host_id_disk.path);
return -1;
}
if (!async)
goto out;
while (1) {
rv = sanlock_inq_lockspace(&ls, 0);
if (!rv)
goto out;
if (rv == -EINPROGRESS) {
sleep(2);
continue;
}
log_error("sanlock_inq_lockspace error %d", rv);
return -1;
}
out:
printf("add done\n");
return 0;
}
static int add_lockspaces(void)
{
int i, rv;
for (i = 0; i < ls_count; i++) {
rv = add_lockspace(i);
if (rv < 0)
return rv;
}
return 0;
}
static const char *mode_str(int n)
{
if (n == SH)
return "sh";
if (n == EX)
return "ex";
if (n == UN)
return "un";
if (n == IV)
return "iv";
return "er";
}
static int do_one(int pid, int fd, int _s1, int _r1, int _n1, int *full)
{
char buf1[sizeof(struct sanlk_resource) + sizeof(struct sanlk_disk)];
struct sanlk_resource *r1;
int acquire = (_n1 != UN);
int rv;
memset(buf1, 0, sizeof(buf1));
r1 = (struct sanlk_resource *)&buf1;
sprintf(r1->lockspace_name, "lockspace%d", _s1);
sprintf(r1->name, "resource%d", _r1);
sprintf(r1->disks[0].path, "%s%d", lock_disk_base, _s1);
r1->disks[0].offset = (_r1+1)*LEASE_SIZE;
r1->num_disks = 1;
if (_n1 == SH)
r1->flags |= SANLK_RES_SHARED;
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 %s = %d",
pid,
acquire ? "acquire" : "release",
_s1, _r1, mode_str(_n1),
rv);
save_rv(pid, rv, acquire);
return rv;
}
static int do_two(int pid, int fd, int _s1, int _r1, int _n1, int _s2, int _r2, int _n2, int *full)
{
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 acquire = (_n1 != UN);
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", _s1);
sprintf(r1->name, "resource%d", _r1);
sprintf(r1->disks[0].path, "%s%d", lock_disk_base, _s1);
r1->disks[0].offset = (_r1+1)*LEASE_SIZE;
r1->num_disks = 1;
if (_n1 == SH)
r1->flags |= SANLK_RES_SHARED;
sprintf(r2->lockspace_name, "lockspace%d", _s2);
sprintf(r2->name, "resource%d", _r2);
sprintf(r2->disks[0].path, "%s%d", lock_disk_base, _s2);
r2->disks[0].offset = (_r2+1)*LEASE_SIZE;
r2->num_disks = 1;
if (_n2 == SH)
r2->flags |= SANLK_RES_SHARED;
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 %s %d,%d %s = %d",
pid,
acquire ? "acquire" : "release",
_s1, _r1, mode_str(_n1),
_s2, _r2, mode_str(_n2),
rv);
save_rv(pid, rv, acquire);
free(res_args);
return rv;
}
static int acquire_one(int pid, int fd, int s1, int r1, int n1, int *full)
{
return do_one(pid, fd, s1, r1, n1, full);
}
static int acquire_two(int pid, int fd, int s1, int r1, int n1, int s2, int r2, int n2, int *full)
{
return do_two(pid, fd, s1, r1, n1, s2, r2, n2, full);
}
static int release_one(int pid, int fd, int s1, int r1)
{
return do_one(pid, fd, s1, r1, UN, NULL);
}
static int release_two(int pid, int fd, int s1, int r1, int s2, int r2)
{
return do_two(pid, fd, s1, r1, UN, s2, r2, UN, NULL);
}
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(pid, rv, 0);
return rv;
}
static void inquire_all(int pid, int fd)
{
int rv, count = 0;
char *state = NULL;
if (prog_stop)
return;
rv = sanlock_inquire(fd, -1, 0, &count, &state);
log_debug("%d inquire all = %d %d", pid, rv, count);
if (prog_stop)
return;
check_lock_state(pid, rv, count, state);
if (count && debug_verbose)
dump_inquire_state(pid, state);
if (state)
free(state);
}
int do_rand_child(void)
{
int s1, s2, r1, r2, m1, m2, n1, n2, full;
int fd, rv;
int iter = 1;
int pid = getpid();
error_count = 0;
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 (!prog_stop) {
s1 = get_rand(0, ls_count-1);
r1 = get_rand(0, res_count-1);
m1 = lock_state[s1][r1];
s2 = -1;
r2 = -1;
m2 = IV;
if (get_rand(1, 3) == 2) {
s2 = get_rand(0, ls_count-1);
r2 = get_rand(0, res_count-1);
m2 = lock_state[s2][r2];
if (s1 == s2 && r1 == r2) {
s2 = -1;
r2 = -1;
m2 = IV;
}
}
full = 0;
if (m1 == UN && m2 == UN) {
/* both picks are unlocked, lock both together */
n1 = get_rand_sh_ex();
n2 = get_rand_sh_ex();
rv = acquire_two(pid, fd, s1, r1, n1, s2, r2, n2, &full);
if (!rv) {
lock_state[s1][r1] = n1;
lock_state[s2][r2] = n2;
}
m1 = IV;
m2 = IV;
}
if (m1 > UN && m2 > UN) {
/* both picks are locked, unlock both together */
release_two(pid, fd, s1, r1, s2, r2);
lock_state[s1][r1] = UN;
lock_state[s2][r2] = UN;
m1 = IV;
m2 = IV;
}
if (m1 == UN) {
n1 = get_rand_sh_ex();
rv = acquire_one(pid, fd, s1, r1, n1, &full);
if (!rv)
lock_state[s1][r1] = n1;
}
if (m2 == UN) {
n2 = get_rand_sh_ex();
rv = acquire_one(pid, fd, s2, r2, n2, &full);
if (!rv)
lock_state[s2][r2] = n2;
}
if (m1 > UN) {
release_one(pid, fd, s1, r1);
lock_state[s1][r1] = UN;
}
if (m2 > UN) {
release_one(pid, fd, s2, r2);
lock_state[s2][r2] = UN;
}
if (full) {
release_all(pid, fd);
memset(lock_state, 0, sizeof(lock_state));
}
if ((iter % 10) == 0) {
display_rv(pid);
inquire_all(pid, fd);
}
iter++;
}
display_rv(pid);
if (error_count) {
printf("pid %d done error_count %d\n", pid, error_count);
exit(EXIT_FAILURE);
}
printf("pid %d done\n", pid);
exit(EXIT_SUCCESS);
}
int do_all_child(void)
{
int sx, rx, full;
int fd, rv;
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 (!prog_stop) {
for (sx = 0; sx < ls_count; sx++) {
for (rx = 0; rx < res_count; rx++) {
rv = acquire_one(pid, fd, sx, rx, EX, &full);
if (!rv)
lock_state[sx][rx] = EX;
}
inquire_all(pid, fd);
for (rx = 0; rx < res_count-1; rx++) {
rv = release_one(pid, fd, sx, rx);
lock_state[sx][rx] = UN;
}
inquire_all(pid, fd);
}
}
display_rv(pid);
return 0;
}
/*
* 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 (optchar == 'V') {
debug_verbose = 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':
run_sec = atoi(optionarg);
break;
case 's':
ls_count = atoi(optionarg);
if (ls_count > MAX_LS_COUNT) {
log_error("max ls_count %d", MAX_LS_COUNT);
exit(-1);
}
break;
case 'r':
res_count = atoi(optionarg);
if (res_count > MAX_RES_COUNT) {
log_error("max res_count %d", MAX_RES_COUNT);
exit(-1);
}
break;
case 'p':
pid_count = atoi(optionarg);
if (pid_count > MAX_PID_COUNT) {
log_error("max pid_count %d", MAX_PID_COUNT);
exit(-1);
}
break;
case 'm':
one_mode = atoi(optionarg);
break;
case 'e':
error_range = atoi(optionarg);
break;
default:
log_error("unknown option: %c", optchar);
exit(EXIT_FAILURE);
}
i++;
}
}
int find_pid(int *kids, int pid)
{
int i;
for (i = 0; i < pid_count; i++) {
if (kids[i] == pid)
return i;
}
return -1;
}
int do_rand(int argc, char *argv[])
{
struct sigaction act;
int children[MAX_PID_COUNT];
int run_count = 0;
int i, rv, pid, status;
if (argc < 5)
return -1;
memset(&act, 0, sizeof(act));
act.sa_handler = sigterm_handler;
sigaction(SIGTERM, &act, NULL);
strcpy(lock_disk_base, argv[2]);
get_options(argc, argv);
rv = add_lockspaces();
if (rv < 0)
return rv;
printf("forking %d pids\n", pid_count);
for (i = 0; i < pid_count; i++) {
pid = fork();
if (pid < 0) {
log_error("fork %d failed %d run_count %d", i, errno, run_count);
break;
}
if (!pid) {
do_rand_child();
exit(-1);
}
children[i] = pid;
run_count++;
}
printf("children running\n");
while (!prog_stop) {
#if 0
/*
* kill and replace a random pid
*/
sleep(get_rand(1, 60));
if (prog_stop)
break;
i = get_rand(0, pid_count);
pid = children[i];
printf("kill pid %d\n", pid);
kill(pid, SIGKILL);
rv = waitpid(pid, &status, 0);
if (rv <= 0)
continue;
pid = fork();
if (pid < 0) {
log_error("fork failed %d", errno);
break;
} else if (!pid) {
do_rand_child();
exit(-1);
} else {
children[i] = pid;
}
#endif
#if 0
/*
* remove a random lockspace, replace any pids that were using
* it, replace the lockspace
*/
sleep(get_rand(1, 60));
if (prog_stop)
break;
lsi = get_rand(0, ls_count-1);
remove_lockspace(lsi);
while (1) {
rv = waitpid(-1, &status, WNOHANG);
if (rv <= 0)
break;
if (!WIFEXITED(status))
continue;
printf("exit pid %d\n", pid);
i = find_pid(children, rv);
if (i < 0)
continue;
pid = fork();
if (pid < 0) {
log_error("fork failed %d", errno);
break;
} else if (!pid) {
do_rand_child();
exit(-1);
} else {
children[i] = pid;
}
}
add_lockspace(lsi);
#endif
if (run_sec && (count_sec >= run_sec))
break;
count_sec++;
sleep(1);
}
printf("stopping pids ");
for (i = 0; i < pid_count; i++)
kill(children[i], SIGTERM);
while (run_count) {
status = 0;
pid = wait(&status);
if (pid > 0) {
run_count--;
if (!WIFEXITED(status)) {
error_count++;
printf("-");
} else if (WEXITSTATUS(status)) {
error_count++;
printf("x");
} else {
printf(".");
}
}
}
printf("\n");
if (error_count) {
printf("child errors %d\n", error_count);
exit(EXIT_FAILURE);
}
return 0;
}
int do_all(int argc, char *argv[])
{
struct sigaction act;
int children[MAX_PID_COUNT];
int run_count = 0;
int i, rv, pid, status;
if (argc < 5)
return -1;
memset(&act, 0, sizeof(act));
act.sa_handler = sigterm_handler;
sigaction(SIGTERM, &act, NULL);
strcpy(lock_disk_base, argv[2]);
get_options(argc, argv);
rv = add_lockspaces();
if (rv < 0)
return rv;
printf("forking %d pids\n", pid_count);
for (i = 0; i < pid_count; i++) {
pid = fork();
if (pid < 0) {
log_error("fork %d failed %d run_count %d", i, errno, run_count);
break;
}
if (!pid) {
do_all_child();
exit(-1);
}
children[i] = pid;
run_count++;
}
printf("children running\n");
while (!prog_stop) {
sleep(1);
}
printf("stopping pids");
for (i = 0; i < pid_count; i++)
kill(children[i], SIGTERM);
while (run_count) {
pid = wait(&status);
if (pid > 0) {
run_count--;
printf(".");
}
}
printf("\n");
if (error_count) {
printf("error_count %d\n", error_count);
exit(EXIT_FAILURE);
}
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 64
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);
else if (!strcmp(argv[1], "all"))
rv = do_all(argc, argv);
if (!rv)
return 0;
out:
printf("sanlk_load init <disk_base> [<ls_count> <res_count>]\n");
printf(" init ls_count lockspaces, each with res_count resources\n");
printf(" devices for lockspaces 0..N are disk_base0..disk_baseN\n");
printf(" e.g. /dev/lock0, /dev/lock1, ... /dev/lockN\n");
printf("\n");
printf("sanlk_load rand <disk_base> -i <host_id> [options]\n");
printf(" -s <num> number of lockspaces\n");
printf(" -r <num> number of resources per lockspace\n");
printf(" -p <num> number of processes\n");
printf(" -m <num> use one mode for all locks, 3 = SH, 5 = EX\n");
printf(" -S <num> seconds to run (0 unlimited)\n");
printf(" -e <num> error range expected (1 single node, 2 multi node)\n");
printf(" -D debug output\n");
printf(" -V verbose debug output\n");
printf("\n");
return -1;
}