From 637ec3fc4ea7e756ba62a69e7ebe7a15713626b9 Mon Sep 17 00:00:00 2001 From: Thomas Schoebel-Theuer Date: Thu, 4 Jul 2013 07:16:38 +0200 Subject: [PATCH] tools: new checking tool write-reboot.c Use this for testing the power blackout safety. --- userspace/write-reboot.c | 162 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 userspace/write-reboot.c diff --git a/userspace/write-reboot.c b/userspace/write-reboot.c new file mode 100644 index 00000000..1d268b4b --- /dev/null +++ b/userspace/write-reboot.c @@ -0,0 +1,162 @@ +// (c) 2013 Thomas Schoebel-Theuer / 1&1 Internet AG + +/* This is a trivial hacker's tool for testing the reboot saftey of MARS + * (or other system software). + * + * The trick is to reboot _immediately_ after the last IO operation. + * Will the block layer contain _all_ the data, at least if it had been + * sync()ed before? + * + * Note: the transaction logfiles of MARS may contain an incomplete + * log record at the end if there was (additional) IO running _in parallel_ + * to the reboot operation. + * Even then, the transaction logfile must contain all the data which + * has been reported as "completed" by O_DIRECT or O_SYNC or by one + * of the fsync() / fdatasync() operations. + * In addition, MARS must tolerate such incomplete records because they + * are unavoidable as such (races between IO and reboot / reset). + * + * Exception: when /proc/sys/mars/logger_completion_semantics is deliberately + * set to 0, some synced IO may get lost. However, even then the _order_ must + * be correct. + * + * Hint: you may also try physical reset via IPMI + */ + +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define BLK_SIZE 1024 + +static +time_t now = 0; + +static +int blk_size = BLK_SIZE; + +void write_block(int fd, int nr) +{ + char *buf = aligned_alloc(blk_size, blk_size); + int status; + + if (!buf) { + fprintf(stderr, "no mem\n"); + exit (-1); + } + + /* Hint: you may simply use the tool "strings" to dig for + * the markers produced by this. + * When running multiple times, check the correctness of the + * timestamps. + */ + memset(buf, 0, blk_size); + snprintf(buf, blk_size, "timestamp %lld block %05d\n", (long long)now, nr); + + status = write(fd, buf, blk_size); + if (status != blk_size) { + fprintf(stderr, "write() #%d failed, status = %d, errno = %d %s\n", nr, status, errno, strerror(errno)); + exit (-1); + } + + free(buf); +} + +int main(int argc, char *argv[]) +{ + /* smode: + * 0 = only write blocks (see fmode) [DEFAULT] + * 1 = immedialtely reboot afterwards (no sync, no pause) + * 2 = use fdatasync() before reboot + * 3 = use fsync() before reboot + */ + int smode = 0; + + /* fmode: + * 0 = buffered write (IO may get lost because of buffering) + * 1 = use O_DIRECT (IO should not get lost) [DEFAULT] + * 2 = use O_SYNC (IO should not get lost) + * [combine the bits like a bitmask] + */ + int fmode = 1; + int flags = O_WRONLY | O_CREAT; + + int count = 1000; + int fd; + int i; + + if (argc < 2) { + fprintf(stderr, "usage: write-reboot [] [] [] []\n"); + exit (-1); + } + if (argc > 2) { + smode = atoi(argv[2]); + } + if (argc > 3) { + fmode = atoi(argv[3]); + } + if (fmode & 1) + flags |= O_DIRECT; + if (fmode & 2) + flags |= O_SYNC; + if (argc > 4) { + count = atoi(argv[4]); + } + if (argc > 5) { + blk_size = atoi(argv[5]); + } + + time(&now); + + printf("now = %lld file = '%s' fmode = %d smode = %d count = %d blk_size = %d\n", + (long long)now, + argv[1], + fmode, + smode, + count, + blk_size); + + fd = open(argv[1], flags, 0600); + if (fd < 0) { + fprintf(stderr, "open() with flags %d failed, errno = %d %s\n", flags, errno, strerror(errno)); + exit (-1); + } + printf("fd = %d\n", fd); + + for (i = 0; i < count; i++) { + write_block(fd, i); + } + + printf("done.\n"); + + if (smode > 2) { + printf("fsync()\n"); + fsync(fd); + } else + if (smode > 1) { + printf("fdatasync()\n"); + fdatasync(fd); + } + + if (smode > 0) { + printf("reboot...\n"); + reboot(LINUX_REBOOT_CMD_RESTART); + } + + return 0; +}