363 lines
6.9 KiB
C
363 lines
6.9 KiB
C
/*
|
|
* Copyright (c) 2011 David Teigland
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License V2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
/* gcc dlm_seq_async.c -ldlm -o dlm_seq_async */
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <syslog.h>
|
|
#include <sys/time.h>
|
|
#include <asm/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/un.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/errno.h>
|
|
|
|
#include "libdlm.h"
|
|
|
|
#define DEFAULT_NUM_R 1000
|
|
#define DEFAULT_NUM_LPR 1
|
|
|
|
static dlm_lshandle_t *dh;
|
|
static int openclose = 0;
|
|
static int quiet = 0;
|
|
static int verbose = 0;
|
|
static int opt_convert = 0;
|
|
static int opt_unlock = 0;
|
|
static int opt_async = 0;
|
|
static int opt_delay = 0;
|
|
static unsigned int num_r = DEFAULT_NUM_R;
|
|
static unsigned int num_lpr = DEFAULT_NUM_LPR;
|
|
static unsigned int num_iter = 1;
|
|
static unsigned int iter = 0;
|
|
static uint32_t *lkids;
|
|
static struct dlm_lksb lksb;
|
|
static unsigned int cb_count;
|
|
static int libdlm_fd;
|
|
|
|
#define log_debug(fmt, args...) \
|
|
do { \
|
|
if (!quiet) \
|
|
printf(fmt "\n", ##args); \
|
|
} while (0)
|
|
|
|
#define log_error(fmt, args...) \
|
|
do { \
|
|
printf("ERROR " fmt "\n", ##args); \
|
|
exit(-1); \
|
|
} while (0)
|
|
|
|
static void astfn(void *arg)
|
|
{
|
|
int status = lksb.sb_status;
|
|
|
|
cb_count++;
|
|
|
|
printf("astfn %x status %d count %u\n", lksb.sb_lkid, status, cb_count);
|
|
|
|
if (!status)
|
|
return;
|
|
if (status == EUNLOCK)
|
|
return;
|
|
}
|
|
|
|
static void seq(int acquire, int convert, int unlock, int mode)
|
|
{
|
|
char name[DLM_RESNAME_MAXLEN];
|
|
uint32_t lkid;
|
|
int i, j, rv;
|
|
|
|
for (i = 0; i < num_r; i++) {
|
|
snprintf(name, sizeof(name), "seq.%08d", i);
|
|
|
|
for (j = 0; j < num_lpr; j++) {
|
|
memset(&lksb, 0, sizeof(lksb));
|
|
|
|
if (acquire) {
|
|
printf("acquire %s %d\n", name, mode);
|
|
|
|
rv = dlm_ls_lockx(dh, mode, &lksb, 0,
|
|
name, strlen(name), 0,
|
|
astfn, &lksb, NULL,
|
|
NULL, NULL);
|
|
}
|
|
if (convert) {
|
|
lksb.sb_lkid = lkids[(i * num_lpr) + j];
|
|
|
|
printf("convert %s %x %d\n", name, lksb.sb_lkid, mode);
|
|
|
|
rv = dlm_ls_lockx(dh, mode, &lksb, LKF_CONVERT,
|
|
name, strlen(name), 0,
|
|
astfn, &lksb, NULL,
|
|
NULL, NULL);
|
|
}
|
|
if (unlock) {
|
|
lkid = lkids[(i * num_lpr) + j];
|
|
|
|
printf("unlock %s %x\n", name, lkid);
|
|
|
|
rv = dlm_ls_unlock(dh, lkid, 0, &lksb, &lksb);
|
|
}
|
|
|
|
if (rv) {
|
|
log_error("dlm op %d %d %d %d,%d error %d",
|
|
acquire, convert, unlock, i, j, rv);
|
|
return;
|
|
}
|
|
|
|
if (acquire && lkids)
|
|
lkids[(i * num_lpr) + j] = lksb.sb_lkid;
|
|
}
|
|
}
|
|
|
|
cb_count = 0;
|
|
|
|
while (1) {
|
|
rv = dlm_dispatch(libdlm_fd);
|
|
if (rv < 0) {
|
|
printf("dlm_dispatch error %d %d\n", rv, errno);
|
|
}
|
|
|
|
if (cb_count == (num_r * num_lpr))
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void print_usage(void)
|
|
{
|
|
printf("dlm_seq [options]\n");
|
|
printf("Options:\n");
|
|
printf("\n");
|
|
printf(" -i <n> Iterations (0 no limit), default 1)\n");
|
|
printf(" -r <n> The number of resources, default %d\n", DEFAULT_NUM_R);
|
|
printf(" -l <n> The number of locks per resource, default %d\n", DEFAULT_NUM_LPR);
|
|
printf(" -c Convert locks after acquiring them all\n");
|
|
printf(" -u Unlock locks after acquire/convert\n");
|
|
printf(" -s Same resource names in each iteration\n");
|
|
printf(" -d <us> Delay us between consecutive seq\n");
|
|
printf(" -o Open/close existing lockspace\n");
|
|
printf(" -v Verbose output\n");
|
|
printf(" -q Quiet output\n");
|
|
}
|
|
|
|
static void decode_arguments(int argc, char **argv)
|
|
{
|
|
int cont = 1;
|
|
int optchar;
|
|
|
|
while (cont) {
|
|
optchar = getopt(argc, argv, "i:r:l:cuvqohad:s");
|
|
|
|
switch (optchar) {
|
|
|
|
case 'i':
|
|
num_iter = atoi(optarg);
|
|
break;
|
|
|
|
case 'r':
|
|
num_r = atoi(optarg);
|
|
break;
|
|
|
|
case 'l':
|
|
num_lpr = atoi(optarg);
|
|
break;
|
|
|
|
case 'c':
|
|
opt_convert = 1;
|
|
break;
|
|
|
|
case 'u':
|
|
opt_unlock = 1;
|
|
break;
|
|
|
|
case 'd':
|
|
opt_delay = atoi(optarg);
|
|
break;
|
|
|
|
case 'o':
|
|
openclose = 1;
|
|
break;
|
|
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
|
|
case 'q':
|
|
quiet = 1;
|
|
break;
|
|
|
|
case 'h':
|
|
print_usage();
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
|
|
case 'V':
|
|
printf("%s (built %s %s)\n", argv[0], __DATE__, __TIME__);
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
|
|
case ':':
|
|
case '?':
|
|
fprintf(stderr, "Please use '-h' for usage.\n");
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
|
|
case EOF:
|
|
cont = 0;
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "unknown option: %c\n", optchar);
|
|
exit(EXIT_FAILURE);
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
void _acquire(int mode)
|
|
{
|
|
seq(1, 0, 0, mode);
|
|
|
|
if (opt_delay)
|
|
usleep(opt_delay);
|
|
}
|
|
|
|
void _convert(int mode)
|
|
{
|
|
seq(0, 1, 0, mode);
|
|
|
|
if (opt_delay)
|
|
usleep(opt_delay);
|
|
}
|
|
|
|
void _unlock(void)
|
|
{
|
|
seq(0, 0, 1, 0);
|
|
|
|
if (opt_delay)
|
|
usleep(opt_delay);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rv, quit = 0;
|
|
|
|
decode_arguments(argc, argv);
|
|
|
|
printf("%d resources, %d locks per resource\n", num_r, num_lpr);
|
|
|
|
if (openclose) {
|
|
log_debug("dlm_open_lockspace...");
|
|
|
|
dh = dlm_open_lockspace("dlm_seq");
|
|
if (!dh) {
|
|
log_error("dlm_open_lockspace error %lu %d",
|
|
(unsigned long)dh, errno);
|
|
return -ENOTCONN;
|
|
}
|
|
} else {
|
|
log_debug("dlm_new_lockspace...");
|
|
|
|
dh = dlm_new_lockspace("dlm_seq", 0600, 0);
|
|
if (!dh) {
|
|
log_error("dlm_new_lockspace error %lu %d",
|
|
(unsigned long)dh, errno);
|
|
return -ENOTCONN;
|
|
}
|
|
}
|
|
|
|
libdlm_fd = dlm_ls_get_fd(dh);
|
|
if (libdlm_fd < 0) {
|
|
log_error("dlm_ls_get fd error %d %d", libdlm_fd, errno);
|
|
goto done;
|
|
}
|
|
|
|
lkids = malloc(sizeof(uint32_t) * (num_r * num_lpr));
|
|
if (!lkids) {
|
|
log_error("no mem");
|
|
goto done;
|
|
}
|
|
|
|
while (1) {
|
|
_acquire(LKM_EXMODE);
|
|
_convert(LKM_PRMODE);
|
|
_unlock();
|
|
_acquire(LKM_EXMODE);
|
|
_unlock();
|
|
_acquire(LKM_EXMODE);
|
|
_convert(LKM_NLMODE);
|
|
_convert(LKM_EXMODE);
|
|
_unlock();
|
|
|
|
_acquire(LKM_PRMODE);
|
|
_convert(LKM_EXMODE);
|
|
_unlock();
|
|
_acquire(LKM_PRMODE);
|
|
_unlock();
|
|
_acquire(LKM_PRMODE);
|
|
_convert(LKM_NLMODE);
|
|
_convert(LKM_PRMODE);
|
|
_unlock();
|
|
|
|
_acquire(LKM_NLMODE);
|
|
_convert(LKM_PRMODE);
|
|
_unlock();
|
|
_acquire(LKM_NLMODE);
|
|
_unlock();
|
|
_acquire(LKM_NLMODE);
|
|
_convert(LKM_EXMODE);
|
|
_convert(LKM_NLMODE);
|
|
_unlock();
|
|
|
|
iter++;
|
|
|
|
if (!num_iter)
|
|
continue;
|
|
if (iter == num_iter)
|
|
break;
|
|
}
|
|
|
|
free(lkids);
|
|
|
|
done:
|
|
if (openclose) {
|
|
log_debug("dlm_close_lockspace");
|
|
|
|
rv = dlm_close_lockspace(dh);
|
|
if (rv < 0)
|
|
log_error("dlm_close_lockspace error %d %d",
|
|
rv, errno);
|
|
} else {
|
|
log_debug("dlm_release_lockspace");
|
|
|
|
rv = dlm_release_lockspace("dlm_seq", dh, 1);
|
|
if (rv < 0)
|
|
log_error("dlm_release_lockspace error %d %d",
|
|
rv, errno);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|