From 77adf4cd648dce41f89469dd185deec6b6b53a0b Mon Sep 17 00:00:00 2001 From: Vikas Gorur Date: Wed, 18 Feb 2009 17:36:07 +0530 Subject: Added all files --- extras/Makefile.am | 13 + extras/Portfile | 26 ++ extras/benchmarking/Makefile.am | 7 + extras/benchmarking/README | 18 + extras/benchmarking/glfs-bm.c | 619 ++++++++++++++++++++++++++++++++ extras/benchmarking/launch-script.sh | 18 + extras/benchmarking/local-script.sh | 26 ++ extras/glusterfs-mode.el | 112 ++++++ extras/glusterfs.vim | 211 +++++++++++ extras/init.d/Makefile.am | 9 + extras/init.d/glusterfs-server | 100 ++++++ extras/init.d/glusterfs-server.plist.in | 15 + extras/init.d/glusterfsd | 110 ++++++ extras/specgen.scm | 98 +++++ extras/stripe-merge.c | 48 +++ extras/test/Makefile.am | 3 + extras/test/rdd.c | 457 +++++++++++++++++++++++ 17 files changed, 1890 insertions(+) create mode 100644 extras/Makefile.am create mode 100644 extras/Portfile create mode 100644 extras/benchmarking/Makefile.am create mode 100644 extras/benchmarking/README create mode 100644 extras/benchmarking/glfs-bm.c create mode 100755 extras/benchmarking/launch-script.sh create mode 100755 extras/benchmarking/local-script.sh create mode 100644 extras/glusterfs-mode.el create mode 100644 extras/glusterfs.vim create mode 100644 extras/init.d/Makefile.am create mode 100755 extras/init.d/glusterfs-server create mode 100644 extras/init.d/glusterfs-server.plist.in create mode 100755 extras/init.d/glusterfsd create mode 100755 extras/specgen.scm create mode 100644 extras/stripe-merge.c create mode 100644 extras/test/Makefile.am create mode 100644 extras/test/rdd.c (limited to 'extras') diff --git a/extras/Makefile.am b/extras/Makefile.am new file mode 100644 index 00000000000..f243a0da5b6 --- /dev/null +++ b/extras/Makefile.am @@ -0,0 +1,13 @@ + +docdir = $(datadir)/doc/glusterfs/ +EmacsModedir = $(docdir)/ +EmacsMode_DATA = glusterfs-mode.el + +SUBDIRS = init.d benchmarking + +EXTRA_DIST = specgen.scm glusterfs.vim glusterfs-mode.el Portfile \ + test/Makefile.am test/Makefile.in test/rdd.c \ + benchmarking/Makefile.am benchmarking/Makefile.in + +CLEANFILES = + diff --git a/extras/Portfile b/extras/Portfile new file mode 100644 index 00000000000..4732c38ee34 --- /dev/null +++ b/extras/Portfile @@ -0,0 +1,26 @@ +# $Id$ + +PortSystem 1.0 + +name glusterfs +version 2.0.0rc1 +categories fuse +maintainers amar@zresearch.com +description GlusterFS +long_description GlusterFS is a cluster file system, flexible to tune it for your needs. +homepage http://www.gluster.org/ +platforms darwin +master_sites http://ftp.zresearch.com/pub/gluster/glusterfs/2.0/2.0.0 + +configure.args --disable-bdb +checksums md5 33c2d02344d4fab422e80cfb637e0b48 + +post-destroot { + file mkdir ${destroot}/Library/LaunchDaemons/ + file copy ${worksrcpath}/extras/glusterfs-server.plist \ + ${destroot}/Library/LaunchDaemons/com.zresearch.glusterfs.plist + + file mkdir ${destroot}/sbin/ + file copy ${worksrcpath}/xlators/mount/fuse/utils/mount_glusterfs \ + ${destroot}/sbin/ +} \ No newline at end of file diff --git a/extras/benchmarking/Makefile.am b/extras/benchmarking/Makefile.am new file mode 100644 index 00000000000..16f73cbaa6b --- /dev/null +++ b/extras/benchmarking/Makefile.am @@ -0,0 +1,7 @@ + +docdir = $(datadir)/doc/$(PACKAGE_NAME)/benchmarking + +EXTRA_DIST = glfs-bm.c README launch-script.sh local-script.sh + +CLEANFILES = + diff --git a/extras/benchmarking/README b/extras/benchmarking/README new file mode 100644 index 00000000000..e83dd882235 --- /dev/null +++ b/extras/benchmarking/README @@ -0,0 +1,18 @@ + +-------------- +Parallel DD performance: + +* Copy the local-script.sh in ${mountpoint}/benchmark/ directory +* Edit it so the blocksize and count are as per the requirements + +* Edit the launch-script.sh script to make sure paths, mountpoints etc are alright. + +* run 'lauch-script.sh' + +* after the run, you can get the aggregated result by adding all the 3rd entry in output.$(hostname) entries in 'output/' directory. + +-------------- + +iozone: + +bash# iozone - +m iozone_cluster.config - t 62 - r ${block_size} - s ${file_size} - +n - i 0 - i 1 \ No newline at end of file diff --git a/extras/benchmarking/glfs-bm.c b/extras/benchmarking/glfs-bm.c new file mode 100644 index 00000000000..f5e63ae8014 --- /dev/null +++ b/extras/benchmarking/glfs-bm.c @@ -0,0 +1,619 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. + This file is part of GlusterFS. + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will 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, see + . +*/ + +#define _GNU_SOURCE +#define __USE_FILE_OFFSET64 +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct state { + char need_op_write:1; + char need_op_read:1; + + char need_iface_fileio:1; + char need_iface_xattr:1; + + char need_mode_posix:1; + char need_mode_libglusterfsclient:1; + + char prefix[512]; + long int count; + + size_t block_size; + + char *specfile; + void *libglusterfsclient_context; + + long int io_size; +}; + + +#define MEASURE(func, arg) measure (func, #func, arg) + + +void +tv_difference (struct timeval *tv_stop, + struct timeval *tv_start, + struct timeval *tv_diff) +{ + if (tv_stop->tv_usec < tv_start->tv_usec) { + tv_diff->tv_usec = (tv_stop->tv_usec + 1000000) - tv_start->tv_usec; + tv_diff->tv_sec = (tv_stop->tv_sec - 1 - tv_start->tv_sec); + } else { + tv_diff->tv_usec = tv_stop->tv_usec - tv_start->tv_usec; + tv_diff->tv_sec = tv_stop->tv_sec - tv_start->tv_sec; + } +} + + +void +measure (int (*func)(struct state *state), + char *func_name, struct state *state) +{ + struct timeval tv_start, tv_stop, tv_diff; + state->io_size = 0; + long int count; + + gettimeofday (&tv_start, NULL); + count = func (state); + gettimeofday (&tv_stop, NULL); + + tv_difference (&tv_stop, &tv_start, &tv_diff); + + fprintf (stdout, "%s: count=%ld, size=%ld, time=%ld:%ld\n", + func_name, count, state->io_size, + tv_diff.tv_sec, tv_diff.tv_usec); +} + + +static error_t +parse_opts (int key, char *arg, + struct argp_state *_state) +{ + struct state *state = _state->input; + + switch (key) + { + case 'o': + if (strcasecmp (arg, "read") == 0) { + state->need_op_write = 0; + state->need_op_read = 1; + } else if (strcasecmp (arg, "write") == 0) { + state->need_op_write = 1; + state->need_op_read = 0; + } else if (strcasecmp (arg, "both") == 0) { + state->need_op_write = 1; + state->need_op_read = 1; + } else { + fprintf (stderr, "unknown op: %s\n", arg); + return -1; + } + break; + case 'i': + if (strcasecmp (arg, "fileio") == 0) { + state->need_iface_fileio = 1; + state->need_iface_xattr = 0; + } else if (strcasecmp (arg, "xattr") == 0) { + state->need_iface_fileio = 0; + state->need_iface_xattr = 1; + } else if (strcasecmp (arg, "both") == 0) { + state->need_iface_fileio = 1; + state->need_iface_xattr = 1; + } else { + fprintf (stderr, "unknown interface: %s\n", arg); + return -1; + } + break; + case 'm': + if (strcasecmp (arg, "posix") == 0) { + state->need_mode_posix = 1; + state->need_mode_libglusterfsclient = 0; + } else if (strcasecmp (arg, "libglusterfsclient") == 0) { + state->need_mode_posix = 0; + state->need_mode_libglusterfsclient = 1; + } else if (strcasecmp (arg, "both") == 0) { + state->need_mode_posix = 1; + state->need_mode_libglusterfsclient = 1; + } else { + fprintf (stderr, "unknown mode: %s\n", arg); + return -1; + } + break; + case 'b': + { + size_t block_size = atoi (arg); + if (!block_size) { + fprintf (stderr, "incorrect size: %s\n", arg); + return -1; + } + state->block_size = block_size; + } + break; + case 's': + state->specfile = strdup (arg); + break; + case 'p': + fprintf (stderr, "using prefix: %s\n", arg); + strncpy (state->prefix, arg, 512); + break; + case 'c': + { + long count = atol (arg); + if (!count) { + fprintf (stderr, "incorrect count: %s\n", arg); + return -1; + } + state->count = count; + } + break; + case ARGP_KEY_NO_ARGS: + break; + case ARGP_KEY_ARG: + break; + } + + return 0; +} + +int +do_mode_posix_iface_fileio_write (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + + for (i=0; icount; i++) { + int fd = -1; + char filename[512]; + + sprintf (filename, "%s.%06ld", state->prefix, i); + + fd = open (filename, O_CREAT|O_WRONLY, 00600); + if (fd == -1) { + fprintf (stderr, "open(%s) => %s\n", filename, strerror (errno)); + break; + } + ret = write (fd, block, state->block_size); + if (ret != state->block_size) { + fprintf (stderr, "write (%s) => %d/%s\n", filename, ret, + strerror (errno)); + close (fd); + break; + } + close (fd); + state->io_size += ret; + } + + return i; +} + + +int +do_mode_posix_iface_fileio_read (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + + for (i=0; icount; i++) { + int fd = -1; + char filename[512]; + + sprintf (filename, "%s.%06ld", state->prefix, i); + + fd = open (filename, O_RDONLY); + if (fd == -1) { + fprintf (stderr, "open(%s) => %s\n", filename, strerror (errno)); + break; + } + ret = read (fd, block, state->block_size); + if (ret == -1) { + fprintf (stderr, "read(%s) => %d/%s\n", filename, ret, strerror (errno)); + close (fd); + break; + } + close (fd); + state->io_size += ret; + } + + return i; +} + + +int +do_mode_posix_iface_fileio (struct state *state) +{ + if (state->need_op_write) + MEASURE (do_mode_posix_iface_fileio_write, state); + + if (state->need_op_read) + MEASURE (do_mode_posix_iface_fileio_read, state); + + return 0; +} + + +int +do_mode_posix_iface_xattr_write (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + char *dname = NULL, *dirc = NULL; + char *bname = NULL, *basec = NULL; + + dirc = strdup (state->prefix); + basec = strdup (state->prefix); + dname = dirname (dirc); + bname = basename (basec); + + for (i=0; icount; i++) { + char key[512]; + + sprintf (key, "glusterfs.file.%s.%06ld", bname, i); + + ret = lsetxattr (dname, key, block, state->block_size, 0); + + if (ret != 0) { + fprintf (stderr, "lsetxattr (%s, %s, %p) => %s\n", + dname, key, block, strerror (errno)); + break; + } + state->io_size += state->block_size; + } + + free (dirc); + free (basec); + + return i; +} + + +int +do_mode_posix_iface_xattr_read (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + char *dname = NULL, *dirc = NULL; + char *bname = NULL, *basec = NULL; + + dirc = strdup (state->prefix); + basec = strdup (state->prefix); + dname = dirname (dirc); + bname = basename (basec); + + for (i=0; icount; i++) { + char key[512]; + + sprintf (key, "glusterfs.file.%s.%06ld", bname, i); + + ret = lgetxattr (dname, key, block, state->block_size); + + if (ret < 0) { + fprintf (stderr, "lgetxattr (%s, %s, %p) => %s\n", + dname, key, block, strerror (errno)); + break; + } + state->io_size += ret; + } + + return i; +} + + +int +do_mode_posix_iface_xattr (struct state *state) +{ + if (state->need_op_write) + MEASURE (do_mode_posix_iface_xattr_write, state); + + if (state->need_op_read) + MEASURE (do_mode_posix_iface_xattr_read, state); + + return 0; +} + + +int +do_mode_libglusterfsclient_iface_fileio_write (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + + for (i=0; icount; i++) { + long fd = 0; + char filename[512]; + + sprintf (filename, "/%s.%06ld", state->prefix, i); + + fd = glusterfs_open (state->libglusterfsclient_context, + filename, O_CREAT|O_WRONLY, 0); + + if (fd == 0) { + fprintf (stderr, "open(%s) => %s\n", filename, strerror (errno)); + break; + } + ret = glusterfs_write (fd, block, state->block_size); + if (ret == -1) { + fprintf (stderr, "glusterfs_write(%s) => %s\n", filename, strerror (errno)); + glusterfs_close (fd); + break; + } + glusterfs_close (fd); + state->io_size += ret; + } + + return i; +} + + +int +do_mode_libglusterfsclient_iface_fileio_read (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + + for (i=0; icount; i++) { + long fd = 0; + char filename[512]; + + sprintf (filename, "/%s.%06ld", state->prefix, i); + + fd = glusterfs_open (state->libglusterfsclient_context, + filename, O_RDONLY, 0); + + if (fd == 0) { + fprintf (stderr, "glusterfs_open(%s) => %s\n", filename, strerror (errno)); + break; + } + ret = glusterfs_read (fd, block, state->block_size); + if (ret == -1) { + fprintf (stderr, "glusterfs_read(%s) => %s\n", filename, strerror (errno)); + glusterfs_close (fd); + break; + } + glusterfs_close (fd); + state->io_size += ret; + } + + return i; +} + + +int +do_mode_libglusterfsclient_iface_fileio (struct state *state) +{ + if (state->need_op_write) + MEASURE (do_mode_libglusterfsclient_iface_fileio_write, state); + + if (state->need_op_read) + MEASURE (do_mode_libglusterfsclient_iface_fileio_read, state); + + return 0; +} + + +int +do_mode_libglusterfsclient_iface_xattr_write (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + char *dname = NULL, *dirc = NULL; + char *bname = NULL, *basec = NULL; + + asprintf (&dirc, "/%s", state->prefix); + asprintf (&basec, "/%s", state->prefix); + dname = dirname (dirc); + bname = basename (basec); + + for (i=0; icount; i++) { + char key[512]; + + sprintf (key, "glusterfs.file.%s.%06ld", bname, i); + + ret = glusterfs_setxattr (state->libglusterfsclient_context, + dname, key, block, state->block_size, 0); + + if (ret < 0) { + fprintf (stderr, "glusterfs_setxattr (%s, %s, %p) => %s\n", + dname, key, block, strerror (errno)); + break; + } + state->io_size += state->block_size; + } + + return i; + +} + + +int +do_mode_libglusterfsclient_iface_xattr_read (struct state *state) +{ + long int i; + int ret = -1; + char block[state->block_size]; + char *dname = NULL, *dirc = NULL; + char *bname = NULL, *basec = NULL; + + dirc = strdup (state->prefix); + basec = strdup (state->prefix); + dname = dirname (dirc); + bname = basename (basec); + + for (i=0; icount; i++) { + char key[512]; + + sprintf (key, "glusterfs.file.%s.%06ld", bname, i); + + ret = glusterfs_getxattr (state->libglusterfsclient_context, + dname, key, block, state->block_size); + + if (ret < 0) { + fprintf (stderr, "glusterfs_getxattr (%s, %s, %p) => %s\n", + dname, key, block, strerror (errno)); + break; + } + state->io_size += ret; + } + + return i; +} + + +int +do_mode_libglusterfsclient_iface_xattr (struct state *state) +{ + if (state->need_op_write) + MEASURE (do_mode_libglusterfsclient_iface_xattr_write, state); + + if (state->need_op_read) + MEASURE (do_mode_libglusterfsclient_iface_xattr_read, state); + + return 0; +} + + +int +do_mode_posix (struct state *state) +{ + if (state->need_iface_fileio) + do_mode_posix_iface_fileio (state); + + if (state->need_iface_xattr) + do_mode_posix_iface_xattr (state); + + return 0; +} + + +int +do_mode_libglusterfsclient (struct state *state) +{ + glusterfs_init_ctx_t ctx = { + .logfile = "/dev/stderr", + .loglevel = "error", + .lookup_timeout = 60, + .stat_timeout = 60, + }; + + ctx.specfile = state->specfile; + if (state->specfile) { + state->libglusterfsclient_context = glusterfs_init (&ctx); + + if (!state->libglusterfsclient_context) { + fprintf (stdout, "Unable to initialize glusterfs context, skipping libglusterfsclient mode\n"); + return -1; + } + } else { + fprintf (stdout, "glusterfs volume specification file not provided, skipping libglusterfsclient mode\n"); + return -1; + } + + if (state->need_iface_fileio) + do_mode_libglusterfsclient_iface_fileio (state); + + if (state->need_iface_xattr) + do_mode_libglusterfsclient_iface_xattr (state); + + return 0; +} + + +int +do_actions (struct state *state) +{ + if (state->need_mode_libglusterfsclient) + do_mode_libglusterfsclient (state); + + if (state->need_mode_posix) + do_mode_posix (state); + + return 0; +} + +static struct argp_option options[] = { + {"op", 'o', "OPERATIONS", 0, + "WRITE|READ|BOTH - defaults to BOTH"}, + {"iface", 'i', "INTERFACE", 0, + "FILEIO|XATTR|BOTH - defaults to FILEIO"}, + {"mode", 'm', "MODE", 0, + "POSIX|LIBGLUSTERFSCLIENT|BOTH - defaults to POSIX"}, + {"block", 'b', "BLOCKSIZE", 0, + " - defaults to 4096"}, + {"specfile", 's', "SPECFILE", 0, + "absolute path to specfile"}, + {"prefix", 'p', "PREFIX", 0, + "filename prefix"}, + {"count", 'c', "COUNT", 0, + "number of files"}, + {0, 0, 0, 0, 0} +}; + +static struct argp argp = { + options, + parse_opts, + "tool", + "tool to benchmark small file performance" +}; + +int +main (int argc, char *argv[]) +{ + struct state state = {0, }; + + state.need_op_write = 1; + state.need_op_read = 1; + + state.need_iface_fileio = 1; + state.need_iface_xattr = 0; + + state.need_mode_posix = 1; + state.need_mode_libglusterfsclient = 0; + + state.block_size = 4096; + + strcpy (state.prefix, "tmpfile"); + state.count = 1048576; + + if (argp_parse (&argp, argc, argv, 0, 0, &state) != 0) { + fprintf (stderr, "argp_parse() failed\n"); + return 1; + } + + do_actions (&state); + + return 0; +} diff --git a/extras/benchmarking/launch-script.sh b/extras/benchmarking/launch-script.sh new file mode 100755 index 00000000000..5d5050d4146 --- /dev/null +++ b/extras/benchmarking/launch-script.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# This script is to launch the script in parallel across all the nodes. + +mount_point="/mnt/glusterfs" +path_to_script="$mount_point}/benchmark/local-script.sh" + +num_hosts=8 + +for i in $(seq 1 $num_hosts); do + ssh node$i path_to_script & +done + +sleep 3; + +touch ${mount_point}/benchmark/start-test + + diff --git a/extras/benchmarking/local-script.sh b/extras/benchmarking/local-script.sh new file mode 100755 index 00000000000..80a7fafe816 --- /dev/null +++ b/extras/benchmarking/local-script.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# This script needs to be present on glusterfs mount, (ie, on every node which wants to run benchmark) + +ifilename="/dev/zero" +ofilename="testdir/testfile.$(hostname)" +result="output/output.$(hostname)" +blocksize=128k +count=8 + +mkdir -p testdir; +mkdir -p output; +echo > ${result} +while [ ! -e start-test ]; do + sleep 1; +done; + + +for i in $(seq 1 5); do + # write + dd if=${ifilename} of=${ofilename} bs=${blocksize} count=${count} 2>&1 | tail -n 1 | cut -f 8,9 -d ' ' >> ${result} ; + # read + #dd if=${ofilename} of=/dev/null bs=${blocksize} count=${count} 2>&1 | tail -n 1 | cut -f 8,9 -d ' ' >> ${result} ; +done + +rm -f start-test diff --git a/extras/glusterfs-mode.el b/extras/glusterfs-mode.el new file mode 100644 index 00000000000..e65fbf4604a --- /dev/null +++ b/extras/glusterfs-mode.el @@ -0,0 +1,112 @@ +;;; Copyright (C) 2007, 2008 Z RESEARCH Inc. +;;; +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 2 of the License, or +;;; (at your option) any later version. +;;; +;;; This program is distributed in the hope that it will 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 to the Free Software +;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +;;; + +(defvar glusterfs-mode-hook nil) + +;; (defvar glusterfs-mode-map +;; (let ((glusterfs-mode-map (make-keymap))) +;; (define-key glusterfs-mode-map "\C-j" 'newline-and-indent) +;; glusterfs-mode-map) +;; "Keymap for WPDL major mode") + +(add-to-list 'auto-mode-alist '("\\.vol\\'" . glusterfs-mode)) + +(defconst glusterfs-font-lock-keywords-1 + (list + ; "cluster/{unify,afr,stripe}" + ; "performance/{io-cache,io-threads,write-behind,read-ahead,stat-prefetch}" + ; "protocol/{client/server}" + ; "features/{trash,posix-locks,fixed-id,filter}" + ; "stroage/posix" + ; "encryption/rot-13" + ; "debug/trace" + '("\\<\\(cluster/\\(unify\\|afr\\|replicate\\|stripe\\|ha\\|dht\\|distribute\\)\\|\\performance/\\(io-\\(cache\\|threads\\)\\|write-behind\\|read-ahead\\|symlink-cache\\)\\|protocol/\\(server\\|client\\)\\|features/\\(trash\\|posix-locks\\|locks\\|path-converter\\|filter\\)\\|storage/\\(posix\\|bdb\\)\\|encryption/rot-13\\|debug/trace\\)\\>" . font-lock-keyword-face)) +"Additional Keywords to highlight in GlusterFS mode.") + +(defconst glusterfs-font-lock-keywords-2 + (append glusterfs-font-lock-keywords-1 + (list + ; "replicate" "namespace" "scheduler" "remote-subvolume" "remote-host" + ; "auth.addr" "block-size" "remote-port" "listen-port" "transport-type" + ; "limits.min-free-disk" "directory" + ; TODO: add all the keys here. + '("\\<\\(inode-lru-limit\\|replicate\\|namespace\\|scheduler\\|username\\|password\\|allow\\|reject\\|block-size\\|listen-port\\|transport-type\\|transport-timeout\\|directory\\|page-size\\|page-count\\|aggregate-size\\|non-blocking-io\\|client-volume-filename\\|bind-address\\|self-heal\\|read-only-subvolumes\\|read-subvolume\\|thread-count\\|cache-size\\|window-size\\|force-revalidate-timeout\\|priority\\|include\\|exclude\\|remote-\\(host\\|subvolume\\|port\\)\\|auth.\\(addr\\|login\\)\\|limits.\\(min-disk-free\\|transaction-size\\|ib-verbs-\\(work-request-\\(send-\\|recv-\\(count\\|size\\)\\)\\|port\\|mtu\\|device-name\\)\\)\\)\ \\>" . font-lock-constant-face))) + "option keys in GlusterFS mode.") + +(defconst glusterfs-font-lock-keywords-3 + (append glusterfs-font-lock-keywords-2 + (list + ; "option" "volume" "end-volume" "subvolumes" "type" + '("\\<\\(option\ \\|volume\ \\|subvolumes\ \\|type\ \\|end-volume\\)\\>" . font-lock-builtin-face))) + ;'((regexp-opt (" option " "^volume " "^end-volume" "subvolumes " " type ") t) . font-lock-builtin-face)) + "Minimal highlighting expressions for GlusterFS mode.") + + +(defvar glusterfs-font-lock-keywords glusterfs-font-lock-keywords-3 + "Default highlighting expressions for GlusterFS mode.") + +(defvar glusterfs-mode-syntax-table + (let ((glusterfs-mode-syntax-table (make-syntax-table))) + (modify-syntax-entry ?\# "<" glusterfs-mode-syntax-table) + (modify-syntax-entry ?* ". 23" glusterfs-mode-syntax-table) + (modify-syntax-entry ?\n ">#" glusterfs-mode-syntax-table) + glusterfs-mode-syntax-table) + "Syntax table for glusterfs-mode") + +;; TODO: add an indentation table + +(defun glusterfs-indent-line () + "Indent current line as GlusterFS code" + (interactive) + (beginning-of-line) + (if (bobp) + (indent-line-to 0) ; First line is always non-indented + (let ((not-indented t) cur-indent) + (if (looking-at "^[ \t]*volume\ ") + (progn + (save-excursion + (forward-line -1) + (setq not-indented nil) + (setq cur-indent 0)))) + (if (looking-at "^[ \t]*end-volume") + (progn + (save-excursion + (forward-line -1) + (setq cur-indent 0)) + (if (< cur-indent 0) ; We can't indent past the left margin + (setq cur-indent 0))) + (save-excursion + (while not-indented ; Iterate backwards until we find an indentation hint + (progn + (setq cur-indent 2) ; Do the actual indenting + (setq not-indented nil))))) + (if cur-indent + (indent-line-to cur-indent) + (indent-line-to 0))))) + +(defun glusterfs-mode () + (interactive) + (kill-all-local-variables) + ;; (use-local-map glusterfs-mode-map) + (set-syntax-table glusterfs-mode-syntax-table) + (set (make-local-variable 'indent-line-function) 'glusterfs-indent-line) + (set (make-local-variable 'font-lock-defaults) '(glusterfs-font-lock-keywords)) + (setq major-mode 'glusterfs-mode) + (setq mode-name "GlusterFS") + (run-hooks 'glusterfs-mode-hook)) + +(provide 'glusterfs-mode) diff --git a/extras/glusterfs.vim b/extras/glusterfs.vim new file mode 100644 index 00000000000..0de6b5b2f1f --- /dev/null +++ b/extras/glusterfs.vim @@ -0,0 +1,211 @@ +" glusterfs.vim: GNU Vim Syntax file for GlusterFS .vol specification +" Copyright (C) 2007 Z RESEARCH, Inc. +" This file is part of GlusterFS. +" +" GlusterFS is free software; you can redistribute it and/or modify +" it under the terms of the GNU General Public License as published +" by the Free Software Foundation; either version 3 of the License, +" or (at your option) any later version. +" +" GlusterFS is distributed in the hope that it will 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, see +" . +" +" Last Modified: Wed Aug 1 00:47:10 IST 2007 +" Version: 0.8 + +syntax clear +syntax case match + +setlocal iskeyword+=- +setlocal iskeyword+=% +setlocal iskeyword+=. +setlocal iskeyword+=* +setlocal iskeyword+=: +setlocal iskeyword+=, + + +"************************************************************************ +" Initially, consider everything an error. Then start eliminating one +" field after the other. Whatever is not eliminated (due to defined +" properties) is an error - Multiples Values for a key +"************************************************************************ +syn match glusterfsError /[^ ]\+/ skipwhite +syn match glusterfsComment "#.*" contains=glusterfsTodo + +syn keyword glusterfsTodo contained TODO FIXME NOTE + +"------------------------------------------------------------------------ +" 'Type' Begin +"------------------------------------------------------------------------ +" Handle all the 'Type' keys and values. Here, a '/' is used to separate +" the key-value pair, they are clubbed together for convenience +syn match glusterfsType "^\s*type\s\+" skipwhite nextgroup=glusterfsTypeKeyVal + +syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +"syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +syn match glusterfsTypeKeyVal contained "\" +"------------------------------------------------------------------------ +" 'Type' End +"------------------------------------------------------------------------ + + +"************************************************************************ + +"------------------------------------------------------------------------ +" 'Volume' Begin +"------------------------------------------------------------------------ +" NOTE 1: Only one volume name allowed after 'volume' keyword +" NOTE 2: Multiple volumes allowed after 'subvolumes' +" NOTE 3: Some other options (like remote-subvolume, namespace etc) use +" volume name (single) +syn match glusterfsVol "^\s*volume\s\+" nextgroup=glusterfsVolName +syn match glusterfsVolName "\<\k\+" contained + +syn match glusterfsVol "^\s*subvolumes\s\+" skipwhite nextgroup=glusterfsSubVolName +syn match glusterfsSubVolName "\<\k\+\>" skipwhite contained nextgroup=glusterfsSubVolName + +syn match glusterfsVol "^\s*end-volume\>" +"------------------------------------------------------------------------ +" 'Volume' End +"------------------------------------------------------------------------ + + + + + +"------------------------------------------------------------------------ +" 'Options' Begin +"------------------------------------------------------------------------ +syn match glusterfsOpt "^\s*option\s\+" nextgroup=glusterfsOptKey + + +syn keyword glusterfsOptKey contained transport-type skipwhite nextgroup=glusterfsOptValTransportType +syn match glusterfsOptValTransportType contained "\<\(tcp\|ib\-verbs\|ib-sdp\)/\(client\|server\)\>" + +syn keyword glusterfsOptKey contained remote-subvolume skipwhite nextgroup=glusterfsVolName + +syn keyword glusterfsOptKey contained auth.addr.ra8.allow auth.addr.ra7.allow auth.addr.ra6.allow auth.addr.ra5.allow auth.addr.ra4.allow auth.addr.ra3.allow auth.addr.ra2.allow auth.addr.ra1.allow auth.addr.brick-ns.allow skipwhite nextgroup=glusterfsOptVal + +syn keyword glusterfsOptKey contained client-volume-filename directory trash-dir skipwhite nextgroup=glusterfsOpt_Path +syn match glusterfsOpt_Path contained "\s\+\f\+\>" + +syn keyword glusterfsOptKey contained debug self-heal encrypt-write decrypt-read mandatory nextgroup=glusterfsOpt_OnOff +syn match glusterfsOpt_OnOff contained "\s\+\(on\|off\)\>" + +syn keyword glusterfsOptKey contained flush-behind non-blocking-connect nextgroup=glusterfsOpt_OnOffNoYes +syn keyword glusterfsOpt_OnOffNoYes contained on off no yes + +syn keyword glusterfsOptKey contained page-size cache-size nextgroup=glusterfsOpt_Size + +syn keyword glusterfsOptKey contained fixed-gid fixed-uid cache-seconds page-count thread-count aggregate-size listen-port remote-port transport-timeout inode-lru-limit nextgroup=glusterfsOpt_Number + +syn keyword glusterfsOptKey contained alu.disk-usage.entry-threshold alu.disk-usage.exit-threshold nextgroup=glusterfsOpt_Size + +syn keyword glusterfsOptKey contained alu.order skipwhite nextgroup=glusterfsOptValAluOrder +syn match glusterfsOptValAluOrder contained "\s\+\(\(disk-usage\|write-usage\|read-usage\|open-files-usage\|disk-speed\):\)*\(disk-usage\|write-usage\|read-usage\|open-files-usage\|disk-speed\)\>" + +syn keyword glusterfsOptKey contained alu.open-files-usage.entry-threshold alu.open-files-usage.exit-threshold alu.limits.max-open-files rr.refresh-interval random.refresh-interval nufa.refresh-interval nextgroup=glusterfsOpt_Number + +syn keyword glusterfsOptKey contained nufa.local-volume-name skipwhite nextgroup=glusterfsVolName + +syn keyword glusterfsOptKey contained ib-verbs-work-request-send-size ib-verbs-work-request-recv-size nextgroup=glusterfsOpt_Size +syn match glusterfsOpt_Size contained "\s\+\d\+\([gGmMkK][bB]\)\=\>" + +syn keyword glusterfsOptKey contained ib-verbs-work-request-send-count ib-verbs-work-request-recv-count ib-verbs-port nextgroup=glusterfsOpt_Number + +syn keyword glusterfsOptKey contained ib-verbs-mtu nextgroup=glusterfsOptValIBVerbsMtu +syn match glusterfsOptValIBVerbsMtu "\s\+\(256\|512\|1024\|2048\|4096\)\>" contained + +syn keyword glusterfsOptKey contained ib-verbs-device-name nextgroup=glusterfsOptVal + +syn match glusterfsOpt_Number contained "\s\+\d\+\>" + +syn keyword glusterfsOptKey contained scheduler skipwhite nextgroup=glusterfsOptValScheduler +syn keyword glusterfsOptValScheduler contained rr alu random nufa + +syn keyword glusterfsOptKey contained namespace skipwhite nextgroup=glusterfsVolName + +syn keyword glusterfsOptKey contained lock-node skipwhite nextgroup=glusterfsVolName + + + +syn keyword glusterfsOptKey contained alu.write-usage.entry-threshold alu.write-usage.exit-threshold alu.read-usage.entry-threshold alu.read-usage.exit-threshold alu.limits.min-free-disk nextgroup=glusterfsOpt_Percentage + +syn keyword glusterfsOptKey contained random.limits.min-free-disk nextgroup=glusterfsOpt_Percentage +syn keyword glusterfsOptKey contained rr.limits.min-disk-free nextgroup=glusterfsOpt_Size + +syn keyword glusterfsOptKey contained nufa.limits.min-free-disk nextgroup=glusterfsOpt_Percentage + +syn match glusterfsOpt_Percentage contained "\s\+\d\+%\=\>" + + + + + + + + + +syn keyword glusterfsOptKey contained remote-host bind-address nextgroup=glusterfsOpt_IP,glusterfsOpt_Domain +syn match glusterfsOpt_IP contained "\s\+\d\d\=\d\=\.\d\d\=\d\=\.\d\d\=\d\=\.\d\d\=\d\=\>" +syn match glusterfsOpt_Domain contained "\s\+\a[a-zA-Z0-9_-]*\(\.\a\+\)*\>" + +syn match glusterfsVolNames "\s*\<\S\+\>" contained skipwhite nextgroup=glusterfsVolNames + +syn keyword glusterfsOptKey contained block-size replicate skipwhite nextgroup=glusterfsOpt_Pattern + +syn match glusterfsOpt_Pattern contained "\s\+\k\+\>" +syn match glusterfsOptVal contained "\s\+\S\+\>" + + + + + +hi link glusterfsError Error +hi link glusterfsComment Comment + +hi link glusterfsVol keyword + +hi link glusterfsVolName function +hi link glusterfsSubVolName function + +hi link glusterfsType Keyword +hi link glusterfsTypeKeyVal String + +hi link glusterfsOpt Keyword + +hi link glusterfsOptKey Special +hi link glusterfsOptVal Normal + +hi link glusterfsOptValTransportType String +hi link glusterfsOptValScheduler String +hi link glusterfsOptValAluOrder String +hi link glusterfsOptValIBVerbsMtu String + +hi link glusterfsOpt_OnOff String +hi link glusterfsOpt_OnOffNoYes String + + +" Options that require +hi link glusterfsOpt_Size PreProc +hi link glusterfsOpt_Domain PreProc +hi link glusterfsOpt_Percentage PreProc +hi link glusterfsOpt_IP PreProc +hi link glusterfsOpt_Pattern PreProc +hi link glusterfsOpt_Number Preproc +hi link glusterfsOpt_Path Preproc + + + +let b:current_syntax = "glusterfs" diff --git a/extras/init.d/Makefile.am b/extras/init.d/Makefile.am new file mode 100644 index 00000000000..608b5bb2d4d --- /dev/null +++ b/extras/init.d/Makefile.am @@ -0,0 +1,9 @@ + +EXTRA_DIST = glusterfsd glusterfs-server glusterfs-server.plist + +CLEANFILES = + +install-data-am: +if GF_DARWIN_HOST_OS + cp glusterfs-server.plist /Library/LaunchDaemons/com.zresearch.glusterfs.plist +endif diff --git a/extras/init.d/glusterfs-server b/extras/init.d/glusterfs-server new file mode 100755 index 00000000000..975283982b2 --- /dev/null +++ b/extras/init.d/glusterfs-server @@ -0,0 +1,100 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: glusterfsd +# Required-Start: $local_fs $network +# Required-Stop: $local_fs $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: gluster server +# Description: This file starts / stops the gluster server +### END INIT INFO + +# Author: Chris AtLee +# Patched by: Matthias Albert < matthias@linux4experts.de> + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +NAME=glusterfsd +SCRIPTNAME=/etc/init.d/$NAME +DAEMON=/usr/sbin/$NAME +PIDFILE=/var/run/$NAME.pid +CONFIGFILE=/etc/glusterfs/server.vol +GLUSTERFS_OPTS="-f $CONFIGFILE" +PID=`test -f $PIDFILE && cat $PIDFILE` + + +# Gracefully exit if the package has been removed. +test -x $DAEMON || exit 0 + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +. /lib/lsb/init-functions + +check_config() +{ + if [ ! -f "$CONFIGFILE" ]; then + echo "Config file $CONFIGFILE is missing...exiting!" + exit 0 + fi +} + +do_start() +{ + check_config; + pidofproc -p $PIDFILE $DAEMON >/dev/null + status=$? + if [ $status -eq 0 ]; then + log_success_msg "glusterfs server is already running with pid $PID" + else + log_daemon_msg "Starting glusterfs server" "glusterfsd" + start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $GLUSTERFS_OPTS + log_end_msg $? + start_daemon -p $PIDFILE $DAEMON -f $CONFIGFILE + return $? + fi +} + +do_stop() +{ + log_daemon_msg "Stopping glusterfs server" "glusterfsd" + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE + log_end_msg $? + rm -f $PIDFILE + killproc -p $PIDFILE $DAEMON + return $? +} + +do_status() +{ + pidofproc -p $PIDFILE $DAEMON >/dev/null + status=$? + if [ $status -eq 0 ]; then + log_success_msg "glusterfs server is running with pid $PID" + else + log_failure_msg "glusterfs server is not running." + fi + exit $status +} + +case "$1" in + start) + do_start + ;; + stop) + do_stop + ;; + status) + do_status; + ;; + restart|force-reload) + do_stop + sleep 2 + do_start + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + diff --git a/extras/init.d/glusterfs-server.plist.in b/extras/init.d/glusterfs-server.plist.in new file mode 100644 index 00000000000..4d2287c5759 --- /dev/null +++ b/extras/init.d/glusterfs-server.plist.in @@ -0,0 +1,15 @@ + + + + + Label + com.zresearch.glusterfs + ProgramArguments + + @prefix@/sbin/glusterfsd + -N + -f + @prefix@/etc/glusterfs/server.vol + + + diff --git a/extras/init.d/glusterfsd b/extras/init.d/glusterfsd new file mode 100755 index 00000000000..866a0010e9a --- /dev/null +++ b/extras/init.d/glusterfsd @@ -0,0 +1,110 @@ +#!/bin/bash +# +# chkconfig: 35 90 12 +# description: Glusterfsd server +# + +# Get function from functions library +# . /etc/rc.d/init.d/functions + +BASE=glusterfsd +GSERVER="/sbin/$BASE -f /etc/glusterfs/glusterfs-server.vol" + +# A function to stop gluster +killgluster() +{ + killlevel="-9" + # Find pid. + pid= + if [ -f /var/run/$BASE.pid ]; then + local line p + read line < /var/run/$BASE.pid + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid +$p" + done + fi + if [ -z "$pid" ]; then + pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \ + pidof -o $$ -o $PPID -o %PPID -x $BASE` + fi + # Kill it. + kill $killlevel $pid + if [ "$?" = 0 ] + then + echo "Gluster process $pid has been killed" + initlog -n "Kill gluster" -e 1 + else + echo "Failed: Gluster process $pid has not been killed" + initlog -n "Kill gluster" -e 2 + fi + + # Remove pid and lock file if any. + if [ -f /var/run/$BASE.pid ] + then + rm -f /var/run/$BASE.pid && initlog -n "Remove $BASE.pid:" -e +1 + else echo "$BASE.pid not found" && initlog -n "Remove +$BASE.pid:" -e 2 + fi + + if [ -f /var/lock/subsys/$BASE ] + then + rm -f /var/lock/subsys/$BASE && initlog -n "Remove $BASE lock +file:" -e 1 + else echo "$BASE lock file not found" && initlog -n "Remove +$BASE lock file:" -e 2 + fi +} + +# Start the service $BASE +start() +{ + initlog -c "echo -n Starting $BASE:" + $GSERVER + if [ $? = 0 ] + then + touch /var/lock/subsys/$BASE + initlog -n "Starting $BASE" -e 1 + echo " [OK]" + else + echo "$BASE start failed." + initlog -n "$BASE start" -e 2 + fi +} + +# Stop the service $BASE +stop() +{ + echo "Stopping $BASE:" + killgluster +} +status() +{ + if test "`lsof |grep -c /sbin/$BASE`" = "0" + then echo "$BASE is stopped." + else echo "$BASE is running..." + fi +} + +### service arguments ### +case $1 in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart|reload|condrestart) + stop + start + ;; + *) + echo $.Usage: $0 {start|stop|restart|reload|status}. + exit 1 +esac + +exit 0 diff --git a/extras/specgen.scm b/extras/specgen.scm new file mode 100755 index 00000000000..279afe896ca --- /dev/null +++ b/extras/specgen.scm @@ -0,0 +1,98 @@ +#!/usr/bin/guile -s +!# + +;;; Copyright (C) 2007 Z RESEARCH Inc. +;;; +;;; This program is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 2 of the License, or +;;; (at your option) any later version. +;;; +;;; This program is distributed in the hope that it will 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 to the Free Software +;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +;;; + +;;; This script lets you specify the xlator graph as a Scheme list +;;; and provides a function to generate the spec file for the graph. + + +(define (volume args) + (apply + (lambda (name type options) + (lambda args + (display "volume ") (display name) (newline) + (display " type ") (display type) (newline) + (map (lambda (key-value-cons) + (let ((key (car key-value-cons)) + (value (cdr key-value-cons))) + (display " option ") (display key) (display " ") + (display value) (newline))) + options) + (if (> (length args) 0) + (begin + (display " subvolumes ") + (map (lambda (subvol) + (display subvol) (display " ")) + args) + (newline))) + (display "end-volume") (newline) (newline) + name)) + args)) + +;; define volumes with names/type/options and bind to a symbol +;; relate them seperately (see below) +;; more convinient to seperate volume definition and relation + +(define wb (volume '(wb0 + performance/write-behind + ((aggregate-size . 0) + (flush-behind . off) + )))) + +(define ra (volume '(ra0 + performance/read-ahead + ((page-size . 128KB) + (page-count . 1) + )))) + +(define ioc (volume '(ioc0 + performance/io-cache + ((page-size . 128KB) + (cache-size . 64MB) + )))) + +(define iot (volume '(iot0 + performance/io-threads + () + ))) + +(define client1 (volume '(client1 + protocol/client + ((transport-type . tcp/client) + (remote-host . localhost) + (remote-subvolume . brick1) + )))) + +(define client2 (volume '(client2 + protocol/client + ((transport-type . tcp/client) + (remote-host . localhost) + (remote-subvolume . brick2) + )))) + +(define unify (volume '(unify0 + cluster/unify + ((scheduler . rr) + )))) + +;; relate the symbols to output a spec file +;; note: relating with symbols lets you change volume name in one place + +(wb (ra (ioc (iot (unify (client1) + (client2)))))) diff --git a/extras/stripe-merge.c b/extras/stripe-merge.c new file mode 100644 index 00000000000..3f8e4b1244d --- /dev/null +++ b/extras/stripe-merge.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + int fds[argc-1]; + char buf[argc-1][4096]; + int i; + int max_ret, ret; + + if (argc < 2) { + printf ("Usage: %s file1 file2 ... >file\n", argv[0]); + return 1; + } + + for (i=0; i max_ret) + max_ret = ret; + } + for (i=0; i + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will 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, see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TWO_POWER(power) (2UL << (power)) + +#define RDD_INTEGER_VALUE ((TWO_POWER ((sizeof (int) * 8))) - 1) + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +struct rdd_file { + char path[UNIX_PATH_MAX]; + struct stat st; + int fd; +}; + +struct rdd_config { + long iters; + long max_ops_per_seq; + size_t max_bs; + size_t min_bs; + int thread_count; + pthread_t *threads; + pthread_barrier_t barrier; + pthread_mutex_t lock; + struct rdd_file in_file; + struct rdd_file out_file; +}; +static struct rdd_config rdd_config; + +enum rdd_keys { + RDD_MIN_BS_KEY = 1, + RDD_MAX_BS_KEY, +}; + +static error_t +rdd_parse_opts (int key, char *arg, + struct argp_state *_state) +{ + switch (key) { + case 'o': + { + int len = 0; + len = strlen (arg); + if (len > UNIX_PATH_MAX) { + fprintf (stderr, "output file name too long (%s)\n", arg); + return -1; + } + + strncpy (rdd_config.out_file.path, arg, len); + } + break; + + case 'i': + { + int len = 0; + len = strlen (arg); + if (len > UNIX_PATH_MAX) { + fprintf (stderr, "input file name too long (%s)\n", arg); + return -1; + } + + strncpy (rdd_config.in_file.path, arg, len); + } + break; + + case RDD_MIN_BS_KEY: + { + char *tmp = NULL; + long bs = 0; + bs = strtol (arg, &tmp, 10); + if ((bs == LONG_MAX) || (bs == LONG_MIN) || (tmp && *tmp)) { + fprintf (stderr, "invalid argument for minimum block size (%s)\n", arg); + return -1; + } + + rdd_config.min_bs = bs; + } + break; + + case RDD_MAX_BS_KEY: + { + char *tmp = NULL; + long bs = 0; + bs = strtol (arg, &tmp, 10); + if ((bs == LONG_MAX) || (bs == LONG_MIN) || (tmp && *tmp)) { + fprintf (stderr, "invalid argument for maximum block size (%s)\n", arg); + return -1; + } + + rdd_config.max_bs = bs; + } + break; + + case 'r': + { + char *tmp = NULL; + long iters = 0; + iters = strtol (arg, &tmp, 10); + if ((iters == LONG_MAX) || (iters == LONG_MIN) || (tmp && *tmp)) { + fprintf (stderr, "invalid argument for iterations (%s)\n", arg); + return -1; + } + + rdd_config.iters = iters; + } + break; + + case 'm': + { + char *tmp = NULL; + long max_ops = 0; + max_ops = strtol (arg, &tmp, 10); + if ((max_ops == LONG_MAX) || (max_ops == LONG_MIN) || (tmp && *tmp)) { + fprintf (stderr, "invalid argument for max-ops (%s)\n", arg); + return -1; + } + + rdd_config.max_ops_per_seq = max_ops; + } + break; + + case 't': + { + char *tmp = NULL; + long threads = 0; + threads = strtol (arg, &tmp, 10); + if ((threads == LONG_MAX) || (threads == LONG_MIN) || (tmp && *tmp)) { + fprintf (stderr, "invalid argument for thread count (%s)\n", arg); + return -1; + } + + rdd_config.thread_count = threads; + } + break; + + case ARGP_KEY_NO_ARGS: + break; + case ARGP_KEY_ARG: + break; + case ARGP_KEY_END: + if (_state->argc == 1) { + argp_usage (_state); + } + + } + + return 0; +} + +static struct argp_option rdd_options[] = { + {"if", 'i', "INPUT_FILE", 0, "input-file"}, + {"of", 'o', "OUTPUT_FILE", 0, "output-file"}, + {"threads", 't', "COUNT", 0, "number of threads to spawn (defaults to 2)"}, + {"min-bs", RDD_MIN_BS_KEY, "MIN_BLOCK_SIZE", 0, + "Minimum block size in bytes (defaults to 1024)"}, + {"max-bs", RDD_MAX_BS_KEY, "MAX_BLOCK_SIZE", 0, + "Maximum block size in bytes (defaults to 4096)"}, + {"iters", 'r', "ITERS", 0, + "Number of read-write sequences (defaults to 1000000)"}, + {"max-ops", 'm', "MAXOPS", 0, + "maximum number of read-writes to be performed in a sequence (defaults to 1)"}, + {0, 0, 0, 0, 0} +}; + +static struct argp argp = { + rdd_options, + rdd_parse_opts, + "", + "random dd - tool to do a sequence of random block-sized continuous read writes starting at a random offset" +}; + + +static void +rdd_default_config (void) +{ + rdd_config.thread_count = 2; + rdd_config.iters = 1000000; + rdd_config.max_bs = 4096; + rdd_config.min_bs = 1024; + rdd_config.in_file.fd = rdd_config.out_file.fd = -1; + rdd_config.max_ops_per_seq = 1; + + return; +} + + +static char +rdd_valid_config (void) +{ + char ret = 1; + int fd = -1; + + fd = open (rdd_config.in_file.path, O_RDONLY); + if (fd == -1) { + ret = 0; + goto out; + } + close (fd); + + if (rdd_config.min_bs > rdd_config.max_bs) { + ret = 0; + goto out; + } + + if (strlen (rdd_config.out_file.path) == 0) { + sprintf (rdd_config.out_file.path, "%s.rddout", rdd_config.in_file.path); + } + +out: + return ret; +} + + +static void * +rdd_read_write (void *arg) +{ + int i = 0, ret = 0; + size_t bs = 0; + off_t offset = 0; + long rand = 0; + long max_ops = 0; + char *buf = NULL; + + buf = CALLOC (1, rdd_config.max_bs); + if (!buf) { + fprintf (stderr, "calloc failed (%s)\n", strerror (errno)); + ret = -1; + goto out; + } + + for (i = 0; i < rdd_config.iters; i++) + { + pthread_mutex_lock (&rdd_config.lock); + { + int bytes = 0; + rand = random (); + + if (rdd_config.min_bs == rdd_config.max_bs) { + bs = rdd_config.max_bs; + } else { + bs = rdd_config.min_bs + (rand % (rdd_config.max_bs - rdd_config.min_bs)); + } + + offset = rand % rdd_config.in_file.st.st_size; + max_ops = rand % rdd_config.max_ops_per_seq; + if (!max_ops) { + max_ops ++; + } + + ret = lseek (rdd_config.in_file.fd, offset, SEEK_SET); + if (ret != offset) { + fprintf (stderr, "lseek failed (%s)\n", strerror (errno)); + ret = -1; + goto unlock; + } + + ret = lseek (rdd_config.out_file.fd, offset, SEEK_SET); + if (ret != offset) { + fprintf (stderr, "lseek failed (%s)\n", strerror (errno)); + ret = -1; + goto unlock; + } + + while (max_ops--) + { + bytes = read (rdd_config.in_file.fd, buf, bs); + if (!bytes) { + break; + } + + if (bytes == -1) { + fprintf (stderr, "read failed (%s)\n", strerror (errno)); + ret = -1; + goto unlock; + } + + if (write (rdd_config.out_file.fd, buf, bytes) != bytes) { + fprintf (stderr, "write failed (%s)\n", strerror (errno)); + ret = -1; + goto unlock; + } + } + } + unlock: + pthread_mutex_unlock (&rdd_config.lock); + if (ret == -1) { + goto out; + } + ret = 0; + } +out: + free (buf); + pthread_barrier_wait (&rdd_config.barrier); + + return NULL; +} + + +static int +rdd_spawn_threads (void) +{ + int i = 0, ret = -1, fd = -1; + char buf[4096]; + + fd = open (rdd_config.in_file.path, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "cannot open %s (%s)\n", rdd_config.in_file.path, strerror (errno)); + ret = -1; + goto out; + } + ret = fstat (fd, &rdd_config.in_file.st); + if (ret != 0) { + close (fd); + fprintf (stderr, "cannot stat %s (%s)\n", rdd_config.in_file.path, strerror (errno)); + ret = -1; + goto out; + } + rdd_config.in_file.fd = fd; + + fd = open (rdd_config.out_file.path, O_WRONLY | O_CREAT, S_IRWXU | S_IROTH); + if (fd < 0) { + close (rdd_config.in_file.fd); + rdd_config.in_file.fd = -1; + fprintf (stderr, "cannot open %s (%s)\n", rdd_config.out_file.path, strerror (errno)); + ret = -1; + goto out; + } + rdd_config.out_file.fd = fd; + + while ((ret = read (rdd_config.in_file.fd, buf, 4096)) > 0) { + if (write (rdd_config.out_file.fd, buf, ret) != ret) { + fprintf (stderr, "write failed (%s)\n", strerror (errno)); + close (rdd_config.in_file.fd); + close (rdd_config.out_file.fd); + rdd_config.in_file.fd = rdd_config.out_file.fd = -1; + ret = -1; + goto out; + } + } + + rdd_config.threads = CALLOC (rdd_config.thread_count, sizeof (pthread_t)); + if (rdd_config.threads == NULL) { + fprintf (stderr, "calloc() failed (%s)\n", strerror (errno)); + + ret = -1; + close (rdd_config.in_file.fd); + close (rdd_config.out_file.fd); + rdd_config.in_file.fd = rdd_config.out_file.fd = -1; + goto out; + } + + ret = pthread_barrier_init (&rdd_config.barrier, NULL, rdd_config.thread_count + 1); + if (ret != 0) { + fprintf (stderr, "pthread_barrier_init() failed (%s)\n", strerror (ret)); + + free (rdd_config.threads); + close (rdd_config.in_file.fd); + close (rdd_config.out_file.fd); + rdd_config.in_file.fd = rdd_config.out_file.fd = -1; + ret = -1; + goto out; + } + + ret = pthread_mutex_init (&rdd_config.lock, NULL); + if (ret != 0) { + fprintf (stderr, "pthread_mutex_init() failed (%s)\n", strerror (ret)); + + free (rdd_config.threads); + pthread_barrier_destroy (&rdd_config.barrier); + close (rdd_config.in_file.fd); + close (rdd_config.out_file.fd); + rdd_config.in_file.fd = rdd_config.out_file.fd = -1; + ret = -1; + goto out; + } + + for (i = 0; i < rdd_config.thread_count; i++) + { + ret = pthread_create (&rdd_config.threads[i], NULL, rdd_read_write, NULL); + if (ret != 0) { + fprintf (stderr, "pthread_create failed (%s)\n", strerror (errno)); + exit (1); + } + } + +out: + return ret; +} + + +static void +rdd_wait_for_completion (void) +{ + pthread_barrier_wait (&rdd_config.barrier); +} + + +int +main (int argc, char *argv[]) +{ + int ret = -1; + + rdd_default_config (); + + ret = argp_parse (&argp, argc, argv, 0, 0, NULL); + if (ret != 0) { + ret = -1; + fprintf (stderr, "%s: argp_parse() failed\n", argv[0]); + goto err; + } + + if (!rdd_valid_config ()) { + ret = -1; + fprintf (stderr, "%s: configuration validation failed\n", argv[0]); + goto err; + } + + ret = rdd_spawn_threads (); + if (ret != 0) { + fprintf (stderr, "%s: spawning threads failed\n", argv[0]); + goto err; + } + + rdd_wait_for_completion (); + +err: + return ret; +} -- cgit