diff options
author | David Teigland <teigland@redhat.com> | 2010-04-06 13:59:09 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2010-04-06 13:59:09 -0500 |
commit | 2cd320665a8f5920e5d09b59744239169d1be78d (patch) | |
tree | 611c8830841edade179332848f713ed433729ecf | |
parent | 9f2d0e1f6615d44c1e7a5ca9b65f6c23d2ac1368 (diff) | |
download | dct-stuff-2cd320665a8f5920e5d09b59744239169d1be78d.tar.gz dct-stuff-2cd320665a8f5920e5d09b59744239169d1be78d.tar.xz dct-stuff-2cd320665a8f5920e5d09b59744239169d1be78d.zip |
add new dlm and fs tests
Signed-off-by: David Teigland <teigland@redhat.com>
-rw-r--r-- | dlm/dlm_load.c | 794 | ||||
-rw-r--r-- | fs/alternate.c | 137 | ||||
-rw-r--r-- | fs/lock_load.c | 329 | ||||
-rwxr-xr-x | fs/make_panic | 162 |
4 files changed, 1422 insertions, 0 deletions
diff --git a/dlm/dlm_load.c b/dlm/dlm_load.c new file mode 100644 index 0000000..d54f414 --- /dev/null +++ b/dlm/dlm_load.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2010 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. + */ + +#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 LKM_IVMODE -1 + +#define MAX_CLIENTS 4 +#define MAX_LOCKS 32 +#define MAX_RESOURCES 32 + +static dlm_lshandle_t *dh; +static int libdlm_fd; +static uint32_t iterations = 0; +static int maxn = MAX_LOCKS; +static int maxr = MAX_RESOURCES; +static int openclose = 0; +static int quiet = 0; +static int timewarn = 0; +static uint64_t our_xid = 0; +static uint32_t ast_count = 0; + +struct client { + int fd; + char type[32]; +}; + +static int client_size = MAX_CLIENTS; +static struct client client[MAX_CLIENTS]; +static struct pollfd pollfd[MAX_CLIENTS]; + +enum { + Op_request = 1, + Op_convert, + Op_unlock, + Op_cancel, +}; + +struct lk { + int id; + int locked_stable; + int unlocked_stable; + int wait_request; + int wait_convert; + int wait_unlock; + int wait_cancel; + int rqmode; + int grmode; + int lastop; + int last_status; + int bast; + time_t wait_start; + struct dlm_lksb lksb; +}; + +static struct lk *locks; + +#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 int rand_int(int a, int b) +{ + return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0)); +} + +static const char *status_str(int status) +{ + static char sts_str[8]; + + switch (status) { + case 0: + return "0 "; + case EUNLOCK: + return "EUNLOCK"; + case ECANCEL: + return "ECANCEL"; + case EAGAIN: + return "EAGAIN "; + case EBUSY: + return "EBUSY "; + case ETIMEDOUT: + return "ETIMEDO"; + case EDEADLK: + return "EDEADLK"; + default: + snprintf(sts_str, 8, "%8x", status); + return sts_str; + } +} + +static const char *op_str(int op) +{ + switch (op) { + case Op_request: + return "request"; + case Op_convert: + return "convert"; + case Op_unlock: + return "unlock"; + case Op_cancel: + return "cancel"; + default: + return "unknown"; + } +} + +static struct lk *get_lock(int i) +{ + if (i < 0) + return NULL; + if (i >= maxn) + return NULL; + return &locks[i]; +} + +static void dump(void) +{ + struct lk *lk; + int i; + + for (i = 0; i < maxn; i++) { + lk = get_lock(i); + log_debug("lk %03u id %08x wait r%d c%d u%d c%d lastop %s gr %d rq %d\n", + i, + lk->lksb.sb_lkid, + lk->wait_request, + lk->wait_convert, + lk->wait_unlock, + lk->wait_cancel, + op_str(lk->lastop), + lk->grmode, + lk->rqmode); + } +} + +static void bastfn(void *arg) +{ + struct lk *lk = arg; + lk->bast = 1; + + ast_count++; + + log_debug("lk %03u bast %04u", lk->id, ast_count); +} + +static void astfn(void *arg) +{ + struct lk *lk = arg; + int status = lk->lksb.sb_status; + int i = lk->id; + + ast_count++; + + log_debug("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + + switch (status) { + case 0: + case EAGAIN: + if (lk->wait_request || lk->wait_convert) { + if (lk->wait_request && (status == EAGAIN)) { + lk->locked_stable = 0; + lk->unlocked_stable = 1; + } else { + lk->locked_stable = 1; + lk->unlocked_stable = 0; + } + + lk->wait_request = 0; + lk->wait_convert = 0; + + if (!status) { + lk->grmode = lk->rqmode; + lk->rqmode = LKM_IVMODE; + } else { + lk->rqmode = LKM_IVMODE; + } + } else { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 1", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + + if (lk->wait_cancel) { + lk->wait_cancel = 0; + } + + if (lk->wait_unlock) { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 2", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + break; + + case EUNLOCK: + if (lk->wait_unlock) { + lk->locked_stable = 0; + lk->unlocked_stable = 1; + + lk->wait_unlock = 0; + + lk->grmode = LKM_IVMODE; + lk->bast = 0; + } else { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 3", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + + if (lk->wait_request || lk->wait_convert || lk->wait_cancel) { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 4", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + break; + + case ECANCEL: + if (lk->wait_cancel) { + if (lk->grmode > LKM_IVMODE) { + lk->locked_stable = 1; + lk->unlocked_stable = 0; + } else { + lk->locked_stable = 0; + lk->unlocked_stable = 1; + } + + lk->wait_cancel = 0; + + lk->rqmode = LKM_IVMODE; + } else { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 5", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + + if (lk->wait_request || lk->wait_convert) { + lk->wait_request = 0; + lk->wait_convert = 0; + } + + if (lk->wait_unlock) { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 6", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + break; + + case ETIMEDOUT: + log_error("lk %03u cast %04u %s %08x not using timeouts", + i, ast_count, status_str(status), + lk->lksb.sb_lkid); + break; + + case EDEADLK: + if (lk->wait_convert) { + lk->locked_stable = 1; + lk->unlocked_stable = 0; + + lk->wait_convert = 0; + + lk->rqmode = LKM_IVMODE; + } else { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 7", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + + if (lk->wait_request || lk->wait_unlock || lk->wait_cancel) { + /* wait state error */ + log_error("lk %03u cast %04u %s %08x " + "wait r%d c%d u%d c%d " + "gr %2d rq %2d last %s wait state error 8", + i, ast_count, status_str(status), + lk->lksb.sb_lkid, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, + lk->grmode, lk->rqmode, + op_str(lk->lastop)); + } + + break; + + default: + log_error("lk %03u cast %04u %d %08x error unexpected status", + i, ast_count, status, lk->lksb.sb_lkid); + }; +} + +static int do_request(struct lk *lk, int mode, int noqueue) +{ + char name[DLM_RESNAME_MAXLEN]; + uint64_t *timeout_arg = NULL; + uint32_t flags = 0; + int i = lk->id; + int rv; + + if (noqueue) + flags |= LKF_NOQUEUE; + + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "test%d", (i % maxr)); + + log_debug("lk %03u request mode %d noqueue %d", i, mode, noqueue); + + rv = dlm_ls_lockx(dh, mode, &lk->lksb, flags, name, strlen(name), 0, + astfn, (void *)lk, bastfn, &our_xid, timeout_arg); + + if (rv) { + log_error("lk %03u request errno %d wait r%d c%d u%d c%d lastop %s", + i, errno, lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, op_str(lk->lastop)); + } + return rv; +} + +static int do_convert(struct lk *lk, int mode, int noqueue) +{ + char name[DLM_RESNAME_MAXLEN]; + uint64_t *timeout_arg = NULL; + uint32_t flags = LKF_CONVERT; + int i = lk->id; + int rv; + + if (noqueue) + flags |= LKF_NOQUEUE; + + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "test%d", (i % maxr)); + + log_debug("lk %03u convert mode %d noqueue %d", i, mode, noqueue); + + rv = dlm_ls_lockx(dh, mode, &lk->lksb, flags, name, strlen(name), 0, + astfn, (void *)lk, bastfn, &our_xid, timeout_arg); + + if (rv) { + log_error("lk %03u convert errno %d wait r%d c%d u%d c%d lastop %s", + i, errno, lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, op_str(lk->lastop)); + } + return rv; +} + +static int do_unlock(struct lk *lk) +{ + uint32_t lkid = lk->lksb.sb_lkid; + uint32_t flags = 0; + int i = lk->id; + int rv; + + log_debug("lk %03u unlock", i); + + rv = dlm_ls_unlock(dh, lkid, flags, &lk->lksb, lk); + + if (rv) { + log_error("lk %03u unlock errno %d wait r%d c%d u%d c%d lastop %s", + i, errno, lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, op_str(lk->lastop)); + } + return rv; +} + +static int do_cancel(struct lk *lk) +{ + uint32_t lkid = lk->lksb.sb_lkid; + uint32_t flags = LKF_CANCEL; + int i = lk->id; + int rv; + + log_debug("lk %03u cancel", i); + + rv = dlm_ls_unlock(dh, lkid, flags, &lk->lksb, lk); + + if (rv) { + log_error("lk %03u cancel errno %d wait r%d c%d u%d c%d lastop %s", + i, errno, lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel, op_str(lk->lastop)); + } + return rv; +} + +static void loop(void) +{ + struct lk *lk; + uint32_t n = 0; + int locknum, noqueue, rqmode, rv; + + while (1) { + dlm_dispatch(libdlm_fd); + + n++; + if (iterations && n == iterations) + break; + if (!(n % 10)) + usleep(200000); + + locknum = rand_int(0, maxn - 1); + noqueue = rand_int(0, 1); + rqmode = rand_int(0, LKM_EXMODE); + + lk = get_lock(locknum); + if (!lk) + continue; + + if (lk->unlocked_stable) { + rv = do_request(lk, rqmode, noqueue); + if (!rv) { + lk->lastop = Op_request; + lk->rqmode = rqmode; + lk->wait_start = time(NULL); + + lk->wait_request = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + continue; + } + + if (lk->locked_stable && lk->bast) { + if (rand_int(0, 1)) { + rv = do_convert(lk, LKM_NLMODE, 0); + if (!rv) { + lk->lastop = Op_convert; + lk->rqmode = LKM_NLMODE; + lk->bast = 0; + lk->wait_start = time(NULL); + + lk->wait_convert = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + } else { + rv = do_unlock(lk); + if (!rv) { + lk->lastop = Op_unlock; + lk->rqmode = LKM_IVMODE; + lk->bast = 0; + + lk->wait_unlock = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + } + continue; + } + + if (lk->locked_stable) { + if (rand_int(0, 1)) { + rv = do_convert(lk, rqmode, noqueue); + if (!rv) { + lk->lastop = Op_convert; + lk->rqmode = rqmode; + lk->wait_start = time(NULL); + + lk->wait_convert = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + } else { + rv = do_unlock(lk); + if (!rv) { + lk->lastop = Op_unlock; + lk->rqmode = LKM_IVMODE; + + lk->wait_unlock = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + } + continue; + } + + if ((lk->wait_request || lk->wait_convert) && !lk->wait_cancel) { + if (time(NULL) - lk->wait_start > 2) { + rv = do_cancel(lk); + if (!rv) { + lk->lastop = Op_cancel; + + lk->wait_cancel = 1; + lk->locked_stable = 0; + lk->unlocked_stable = 0; + } + } + } + + log_debug("lk %03u busy locked %d unlocked %d " + "wait r%d c%d u%d c%d", + lk->id, lk->locked_stable, lk->unlocked_stable, + lk->wait_request, lk->wait_convert, + lk->wait_unlock, lk->wait_cancel); + } +} + +static int client_add(int fd, int *maxi) +{ + int i; + + for (i = 0; i < client_size; i++) { + if (client[i].fd == -1) { + client[i].fd = fd; + pollfd[i].fd = fd; + pollfd[i].events = POLLIN; + if (i > *maxi) + *maxi = i; + log_debug("client %d fd %d added", i, fd); + return i; + } + } + log_error("client add failed"); + return -1; +} + +static void client_dead(int ci) +{ + log_debug("client %d fd %d dead", ci, client[ci].fd); + close(client[ci].fd); + client[ci].fd = -1; + pollfd[ci].fd = -1; +} + +static void client_init(void) +{ + int i; + + for (i = 0; i < client_size; i++) + client[i].fd = -1; +} + +static void print_usage(void) +{ + printf("Options:\n"); + printf("\n"); + printf(" -n The number of locks to work with, default %d\n", MAX_LOCKS); + printf(" -r The number of resources to work with, default %d\n", MAX_RESOURCES); + printf(" -i Iterations in looping stress test, default 0 is no limit\n"); + printf(" -o Open/close existing lockspace\n"); + printf(" -q Quiet output, only print errors\n"); +} + +static void decode_arguments(int argc, char **argv) +{ + int cont = 1; + int optchar; + + while (cont) { + optchar = getopt(argc, argv, "n:r:i:qoh"); + + switch (optchar) { + + case 'n': + maxn = atoi(optarg); + break; + + case 'r': + maxr = atoi(optarg); + break; + + case 'i': + iterations = atoi(optarg); + break; + + case 'o': + openclose = 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; + }; + } +} + +int main(int argc, char *argv[]) +{ + uint32_t major, minor, patch; + struct lk *lk; + int i, rv, maxi = 0, quit = 0; + + srandom(time(NULL)); + + decode_arguments(argc, argv); + + if (maxn < maxr) { + log_error("number of resources must be >= number of locks"); + return -1; + } + if (maxn % maxr) { + log_error("number of locks must be multiple of number of resources"); + return -1; + } + + log_debug("maxn = %d", maxn); + log_debug("maxr = %d", maxr); + log_debug("locks per resource = %d", maxn / maxr); + + client_init(); + + locks = malloc(maxn * sizeof(struct lk)); + if (!locks) { + log_error("no mem for %d locks", maxn); + return 0; + } + memset(locks, 0, sizeof(*locks)); + + lk = locks; + for (i = 0; i < maxn; i++) { + lk->id = i; + lk->grmode = -1; + lk->rqmode = -1; + lk->unlocked_stable = 1; + lk++; + } + + rv = dlm_kernel_version(&major, &minor, &patch); + if (rv < 0) { + log_error("can't detect dlm in kernel %d", errno); + return -1; + } + log_debug("dlm kernel version: %u.%u.%u", major, minor, patch); + dlm_library_version(&major, &minor, &patch); + log_debug("dlm library version: %u.%u.%u", major, minor, patch); + + if (openclose) { + log_debug("dlm_open_lockspace..."); + + dh = dlm_open_lockspace("test"); + 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("test", 0600, + timewarn ? DLM_LSFL_TIMEWARN : 0); + if (!dh) { + log_error("dlm_new_lockspace error %lu %d", + (unsigned long)dh, errno); + return -ENOTCONN; + } + } + + rv = dlm_ls_get_fd(dh); + if (rv < 0) { + log_error("dlm_ls_get_fd error %d %d", rv, errno); + dlm_release_lockspace("test", dh, 1); + return rv; + } + libdlm_fd = rv; + + client_add(libdlm_fd, &maxi); + + loop(); + + 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("test", dh, 1); + if (rv < 0) + log_error("dlm_release_lockspace error %d %d", + rv, errno); + } + + return 0; +} + diff --git a/fs/alternate.c b/fs/alternate.c new file mode 100644 index 0000000..942f3b9 --- /dev/null +++ b/fs/alternate.c @@ -0,0 +1,137 @@ +/****************************************************************************** +******************************************************************************* +** +** Copyright 2001 Sistina Software, Inc. +** +** This is free software released under the GNU General Public License. +** There is no warranty for this software. See the file COPYING for +** details. +** +******************************************************************************* +******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> + +#define die(fmt, args...) \ +{ \ + fprintf(stderr, "%s: ", prog_name); \ + fprintf(stderr, fmt, ##args); \ + exit(EXIT_FAILURE); \ +} + +#define do_lseek(fd, off) \ +{ \ + if (lseek((fd), (off), SEEK_SET) != (off)) \ + die("bad seek: %s on line %d of file %s\n", \ + strerror(errno),__LINE__, __FILE__); \ +} + +#define do_read(fd, buff, len) \ +{ \ + if (read((fd), (buff), (len)) != (len)) \ + die("bad read: %s on line %d of file %s\n", \ + strerror(errno), __LINE__, __FILE__); \ +} + +#define do_write(fd, buff, len) \ +{ \ + if (write((fd), (buff), (len)) != (len)) \ + die("bad write: %s on line %d of file %s\n", \ + strerror(errno), __LINE__, __FILE__); \ +} + +#define BLOCK_SIZE (512) + +char *prog_name; + +unsigned int wait; +unsigned int delay = 0; + +int main(int argc, char *argv[]) +{ + int cont = 1; + int optchar; + int fd; + char *filename; + char buf[BLOCK_SIZE]; + unsigned long long offset; + unsigned long long num, last_num = 0; + unsigned int id, clients; + unsigned long long skip = 0; + unsigned int iterations = 0; + unsigned int delay = 0; + + prog_name = argv[0]; + + while (cont) { + optchar = getopt(argc, argv, "i:s:"); + switch (optchar) { + case 'i': + iterations = atoi(optarg); + break; + case 's': + delay = atoi(optarg); + break; + case 'h': + die("[-i iterations] [-s usleep] filename offset id clients\n"); + case EOF: + cont = 0; + break; + } + } + + if (argc - optind < 4) + die("[-i iterations] [-s usleep] filename offset id clients\n"); + + filename = argv[optind]; + offset = atoll(argv[optind + 1]); + id = atoi(argv[optind + 2]); + clients = atoi(argv[optind + 3]); + + fd = open(filename, O_RDWR | O_CREAT, 0644); + if (fd < 0) + die("can't open file %s: %s\n", argv[1], strerror(errno)); + + for (;;) { + do_lseek(fd, offset); + + do_read(fd, buf, BLOCK_SIZE); + + num = atoll(buf); + if (num % clients == id) { + num++; + sprintf(buf, "%llu\n", num); + printf("%llu %llu\n", num, skip); + + if (last_num && last_num + clients != num) + die("bad\n"); + + do_lseek(fd, offset); + + do_write(fd, buf, BLOCK_SIZE); + + if (iterations && num >= iterations) + break; + + last_num = num; + skip = 0; + } else { + skip++; + } + + if (delay) + usleep(delay); + } + + close(fd); + + exit(EXIT_SUCCESS); +} + diff --git a/fs/lock_load.c b/fs/lock_load.c new file mode 100644 index 0000000..79c449f --- /dev/null +++ b/fs/lock_load.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2009 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/file.h> +#include <fcntl.h> +#include <unistd.h> + +#define die(fmt, args...) \ +{ \ + fprintf(stderr, "%s: ", prog_name); \ + fprintf(stderr, fmt, ##args); \ + exit(EXIT_FAILURE); \ +} + +#define MAX_FILES 1000 +int fda[MAX_FILES]; +unsigned int inodea[MAX_FILES]; + +int do_create; +int use_flock; +int use_plock; +int filecount; +int iterations; +int our_pid; +char *prog_name; +int blocking; +int delay = 10; /* milliseconds */ + +void read_flock(int fd) +{ + int error; + int mode = LOCK_SH; + + if (!blocking) + mode |= LOCK_NB; + + error = flock(fd, mode); + if (error < 0) { + printf("%d read lock failed %d errno %d\n", + our_pid, error, errno); + } +} + +void write_flock(int fd) +{ + int error; + int mode = LOCK_EX; + + if (!blocking) + mode |= LOCK_NB; + + error = flock(fd, mode); + if (error < 0) { + printf("%d write lock failed %d errno %d\n", + our_pid, error, errno); + } +} + +void unlock_flock(int fd) +{ + int error; + + error = flock(fd, LOCK_UN); + if (error < 0) { + printf("%d unlock failed %d errno %d\n", + our_pid, error, errno); + } +} + +int do_plock(int fd, int offset, int len, int type) +{ + struct flock lock; + int action; + + lock.l_type = type; + lock.l_start = offset; + lock.l_whence = SEEK_SET; + lock.l_len = len; + + if (blocking) + action = F_SETLKW; + else + action = F_SETLK; + + return fcntl(fd, action, &lock); +} + +int rand_int(int a, int b) +{ + return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0)); +} + +void rand_range(int *offset, int *len) +{ + switch (rand_int(0, 2)) { + case 0: + *offset = 0; + *len = 10; + return; + case 1: + *offset = 0; + *len = 5; + return; + case 2: + *offset = 5; + *len = 5; + return; + } +} + +static uint64_t dt_usec(struct timeval *start, struct timeval *stop) +{ + uint64_t dt; + + dt = stop->tv_sec - start->tv_sec; + dt *= 1000000; + dt += stop->tv_usec - start->tv_usec; + return dt; +} + +void loop_plock(void) +{ + struct timeval t1, t2; + int i, fdi, fd, offset, len, rv; + + for (i = 0;; i++) { + + fdi = rand_int(0, filecount-1); + fd = fda[fdi]; + + rand_range(&offset, &len); + + switch (rand_int(0, 2)) { + case 0: + gettimeofday(&t1, NULL); + rv = do_plock(fd, offset, len, F_UNLCK); + gettimeofday(&t2, NULL); + + printf("%06d file%04d ino %04x U %02d-%02d pid %d err %02d sec %.6f\n", + i, fdi, inodea[fdi], offset, offset+len-1, our_pid, + rv ? errno : 0, 1.e-6 * dt_usec(&t1, &t2)); + break; + + case 1: + gettimeofday(&t1, NULL); + rv = do_plock(fd, offset, len, F_RDLCK); + gettimeofday(&t2, NULL); + + printf("%06d file%04d ino %04x R %02d-%02d pid %d err %02d sec %.6f\n", + i, fdi, inodea[fdi], offset, offset+len-1, our_pid, + rv ? errno : 0, 1.e-6 * dt_usec(&t1, &t2)); + + break; + case 2: + gettimeofday(&t1, NULL); + rv = do_plock(fd, offset, len, F_WRLCK); + gettimeofday(&t2, NULL); + + printf("%06d file%04d ino %04x W %02d-%02d pid %d err %02d sec %.6f\n", + i, fdi, inodea[fdi], offset, offset+len-1, our_pid, + rv ? errno : 0, 1.e-6 * dt_usec(&t1, &t2)); + break; + } + + if (iterations && i == iterations) + break; + + if (delay) + usleep(delay * 1000); + } +} + +void loop_flock(void) +{ + return; +} + +int open_all_files(void) +{ + int i, fd; + struct stat st; + char path[64]; + + for (i = 0; i < filecount; i++) { + memset(path, 0, sizeof(path)); + sprintf(path, "file%04u", i); + + fd = open(path, O_RDWR | O_CREAT, 0644); + if (fd < 0) + die("can't open file %s\n", strerror(errno)); + fda[i] = fd; + + memset(&st, 0, sizeof(st)); + fstat(fd, &st); + inodea[i] = (unsigned int)st.st_ino; + } +} + +void close_all_files(void) +{ + int i; + + for (i = 0; i < filecount; i++) + close(fda[i]); +} + +void print_usage(void) +{ + fprintf(stderr, "lock_load\n"); + fprintf(stderr, " -i <n> iterations (default 0, no limit)\n"); + fprintf(stderr, " -n <n> number of files (default 100)\n"); + fprintf(stderr, " -c only create files\n"); + fprintf(stderr, " -f use flock\n"); + fprintf(stderr, " -p use plock (default)\n"); + fprintf(stderr, " -d <ms> millisecond delay between each op (default 10)\n"); + fprintf(stderr, " -b use blocking locks (default non-blocking)\n"); + fprintf(stderr, " (warning: can easily deadlock)\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int cont = 1; + int optchar; + + do_create = 0; + use_flock = 0; + use_plock = 1; + filecount = 100; + iterations = 0; + blocking = 0; + delay = 10; + + while (cont) { + optchar = getopt(argc, argv, "cfpn:i:d:bh"); + + switch (optchar) { + case 'c': + do_create = 1; + break; + + case 'f': + use_flock = 1; + break; + + case 'p': + use_plock = 1; + break; + + case 'n': + filecount = atoi(optarg); + break; + + case 'i': + iterations = atoi(optarg); + break; + + case 'd': + delay = atoi(optarg); + break; + + case 'b': + blocking = 1; + break; + + + case EOF: + cont = 0; + break; + + case 'h': + default: + print_usage(); + break; + }; + } + + srandom(time(NULL)); + prog_name = argv[0]; + our_pid = getpid(); + + if (filecount > MAX_FILES) { + fprintf(stderr, "max files is %d\n", MAX_FILES); + return -1; + } + + if (do_create) { + open_all_files(); + close_all_files(); + return 0; + } + + open_all_files(); + + if (use_flock) + loop_flock(); + else if (use_plock) + loop_plock(); + else + fprintf(stderr, "use -f or -p for flock or plock\n"); + + close_all_files(); + + return 0; +} + diff --git a/fs/make_panic b/fs/make_panic new file mode 100755 index 0000000..fd27fb8 --- /dev/null +++ b/fs/make_panic @@ -0,0 +1,162 @@ +#!/usr/bin/perl + +############################################################# +############################################################# +## +## Copyright 2001 Sistina Software Inc. +## +## This is free software released under the GNU General +## Public License. There is no warranty for this +## software. See the file COPYING for details. +## +############################################################# +############################################################# + +use Getopt::Std; + +exit(1) unless getopts('s:f:e:hdqr:l:'); + +if (defined $opt_h) +{ + print << "EndHelp"; +Usage: make_panic [OPTION] + -e <iterations> number of iterations, infinite if not defined + -f <forks> number of processes to fork + -h help + -s <seed> seed for random number generator + -d drop seed so you could use it next time + -q Don't print out the status updates. (slient) + -r Number of directories + -l Number of files +EndHelp + + exit(0); +} + + +if (defined $opt_f) +{ + $opt_f = 1 if $opt_f <=0; + while (--$opt_f) + { + if ($pid = fork()) + { + #parent + } + elsif (defined $pid) + { + last; + } + else + { + die "Fork error $!"; + } + } +} + +if(defined $opt_s) +{ + $seed = $opt_s; +} +else +{ + $seed = time ^ $$; +} +if(defined($opt_d)) +{ + system("echo $seed > /make_panic_seed.$$"); +} +srand($seed); + +if (defined $opt_r) +{ + $dirs = $opt_r; +} +else +{ + $dirs = 50; +} + +if (defined $opt_l) +{ + $files = $opt_l; +} +else +{ + $files = 1000; +} + + +for ($x = 0; $x < $dirs; $x++) +{ + mkdir(sprintf("dir%.10u", $x), 0755); +} + +$last = time(); +$ops_at_last_tick = 0; + +while ( (defined $opt_e)?($opt_e-- > 0):1 ) +{ + $v = int(rand(6)); + + $x = int(rand($dirs)); + $y = int(rand($files)); + $file = sprintf("dir%.10u/file%.10u", $x, $y); + + if ($v == 0) + { + open(DATAFILE, ">> $file") || die; + close(DATAFILE); + } + elsif ($v == 1 || $v == 2) + { + $z = int(rand(1000000000)); + if (open(DATAFILE, "+< $file")) + { + seek(DATAFILE, $z, 0); + print DATAFILE "$z\n"; + close(DATAFILE); + } + } + elsif ($v == 3 || $v == 4) + { + $z = int(rand(1000000000)); + if (open(DATAFILE, "< $file")) + { + seek(DATAFILE, -100, 2); + read(DATAFILE, $tmp, 100) == 100; + close(DATAFILE); + } + } + elsif ($v == 5) + { + unlink "$file"; + } + + + $ops++; +# if ($ops % 250 == 0) +# { +# $new = time(); +# $last-- if ($new == $last); +# $rate = 250 / ($new - $last); +# $pretty_rate = sprintf("%.2f", $rate); +# $last = $new; +# } + + $new = time(); + + if ($new != $last) { + $rate = ($ops - $ops_at_last_tick) / ($new - $last); + $pretty_rate = sprintf("%.2f", $rate); + $ops_at_last_tick = $ops; + $last = $new; + } + + if( ! defined $opt_q ) { + print "$ops:$v: $pretty_rate\n"; + } +} + + + |