summaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
Diffstat (limited to 'extras')
-rw-r--r--extras/FreeBSD/Makefile6
-rw-r--r--extras/LinuxRPM/Makefile.am57
-rw-r--r--extras/MacOSX/Portfile6
-rw-r--r--extras/MacOSX/README.MacOSX10
-rw-r--r--extras/Makefile.am19
-rw-r--r--extras/Solaris/Prototype3
-rw-r--r--extras/Solaris/README.solaris2
-rw-r--r--extras/Solaris/pkginfo4
-rw-r--r--extras/Ubuntu/README.Ubuntu24
-rw-r--r--extras/Ubuntu/glusterd.conf10
-rw-r--r--extras/Ubuntu/mounting-glusterfs.conf7
-rw-r--r--extras/backend-cleanup.sh28
-rw-r--r--extras/benchmarking/Makefile.am4
-rw-r--r--extras/benchmarking/glfs-bm.c246
-rw-r--r--extras/benchmarking/rdd.c882
-rwxr-xr-xextras/clear_xattrs.sh53
-rwxr-xr-xextras/contri-add.sh73
-rwxr-xr-xextras/disk_usage_sync.sh86
-rwxr-xr-xextras/file_size_contri.sh17
-rwxr-xr-xextras/generate-xdr-files.sh98
-rw-r--r--extras/geo-rep/Makefile.am2
-rw-r--r--extras/geo-rep/generate-gfid-file.sh53
-rwxr-xr-xextras/geo-rep/get-gfid.sh7
-rw-r--r--extras/geo-rep/gsync-sync-gfid.c106
-rw-r--r--extras/geo-rep/gsync-upgrade.sh123
-rw-r--r--extras/geo-rep/slave-upgrade.sh102
-rw-r--r--extras/gluster-rsyslog-5.8.conf51
-rw-r--r--extras/gluster-rsyslog-7.2.conf76
-rw-r--r--extras/glusterd-sysconfig6
-rw-r--r--extras/glusterd.vol9
-rw-r--r--extras/glusterfs-georep-logrotate18
-rw-r--r--extras/glusterfs-logrotate27
-rw-r--r--extras/glusterfs-mode.el2
-rw-r--r--extras/glusterfs.vim21
-rw-r--r--extras/gnfs-loganalyse.py260
-rw-r--r--extras/group-virt.example6
-rw-r--r--extras/hook-scripts/Makefile.am1
-rw-r--r--extras/hook-scripts/S29CTDBsetup.sh69
-rwxr-xr-xextras/hook-scripts/S30samba-set.sh109
-rwxr-xr-xextras/hook-scripts/S30samba-start.sh110
-rwxr-xr-xextras/hook-scripts/S30samba-stop.sh71
-rwxr-xr-xextras/hook-scripts/S40ufo-stop.py24
-rwxr-xr-xextras/hook-scripts/S56glusterd-geo-rep-create-post.sh42
-rw-r--r--extras/init.d/Makefile.am15
-rwxr-xr-xextras/init.d/glusterd-Debian.in (renamed from extras/init.d/glusterfsd-Debian)33
-rwxr-xr-xextras/init.d/glusterd-Redhat.in142
-rwxr-xr-xextras/init.d/glusterd-SuSE.in (renamed from extras/init.d/glusterfsd-SuSE)28
-rw-r--r--extras/init.d/glusterd.plist.in (renamed from extras/init.d/glusterfs-server.plist.in)6
-rwxr-xr-xextras/init.d/glusterfsd-Redhat51
-rwxr-xr-xextras/init.d/rhel5-load-fuse.modules7
-rw-r--r--extras/logger.conf.example13
-rw-r--r--extras/ocf/Makefile.am11
-rwxr-xr-xextras/ocf/glusterd.in212
-rwxr-xr-xextras/ocf/volume.in246
-rwxr-xr-xextras/profiler/glusterfs-profiler817
-rwxr-xr-xextras/prot_filter.py144
-rwxr-xr-xextras/quota-metadata-cleanup.sh24
-rwxr-xr-xextras/quota-remove-xattr.sh24
-rwxr-xr-xextras/rebalance.py299
-rwxr-xr-xextras/rpc-coverage.sh480
-rwxr-xr-xextras/specgen.scm2
-rw-r--r--extras/stripe-merge.c492
-rw-r--r--extras/systemd/Makefile.am11
-rw-r--r--extras/systemd/glusterd.service.in14
-rwxr-xr-xextras/test/bug-920583.t50
-rwxr-xr-xextras/test/gluster_commands.sh265
-rw-r--r--extras/test/ld-preload-test/Makefile28
-rw-r--r--extras/test/ld-preload-test/README40
-rw-r--r--extras/test/ld-preload-test/ld-preload-lib.c627
-rw-r--r--extras/test/ld-preload-test/ld-preload-test.c367
-rwxr-xr-xextras/test/ld-preload-test/test-preload.sh7
-rw-r--r--extras/test/open-fd-tests.c64
-rwxr-xr-xextras/test/run.sh22
-rwxr-xr-xextras/test/stop_glusterd.sh19
-rw-r--r--extras/test/test-ffop.c870
-rw-r--r--extras/volfilter.py167
-rw-r--r--extras/who-wrote-glusterfs/gitdm.aliases48
-rw-r--r--extras/who-wrote-glusterfs/gitdm.config8
-rw-r--r--extras/who-wrote-glusterfs/gitdm.domain-map15
-rwxr-xr-xextras/who-wrote-glusterfs/who-wrote-glusterfs.sh50
80 files changed, 7895 insertions, 753 deletions
diff --git a/extras/FreeBSD/Makefile b/extras/FreeBSD/Makefile
index c662b9c65..26fe85c88 100644
--- a/extras/FreeBSD/Makefile
+++ b/extras/FreeBSD/Makefile
@@ -10,17 +10,17 @@ DISTVERSION= 2.0.0rc1
PORTVERSION= 2.0.0rc1
PORTREVISION= 1
CATEGORIES= sysutils
-MASTER_SITES= ftp://ftp.zresearch.com/pub/gluster/glusterfs/2.0/2.0.0/ \
+MASTER_SITES= ftp://ftp.gluster.com/pub/gluster/glusterfs/2.0/2.0.0/ \
http://europe.gluster.org/glusterfs/2.0/2.0.0/
-MAINTAINER= harsha@zresearch.com
+MAINTAINER= harsha@gluster.com
COMMENT= GlusterFS is a clustered file-system
BUILD_DEPENDS= fusefs-libs>2.6.3:${PORTSDIR}/sysutils/fusefs-libs
LIB_DEPENDS= fuse.2:${PORTSDIR}/sysutils/fusefs-libs
RUN_DEPENDS= ${LOCALBASE}/modules/fuse.ko:${PORTSDIR}/sysutils/fusefs-kmod
-MAN8= glusterfs.8
+MAN8= glusterfs.8 gluster.8 glusterd.8 glusterfs-volgen.8
GNU_CONFIGURE= yes
USE_LDCONFIG= yes
USE_AUTOTOOLS= libtool:15
diff --git a/extras/LinuxRPM/Makefile.am b/extras/LinuxRPM/Makefile.am
new file mode 100644
index 000000000..1dafa982b
--- /dev/null
+++ b/extras/LinuxRPM/Makefile.am
@@ -0,0 +1,57 @@
+
+GFS_TAR = ../../glusterfs-$(VERSION).tar.gz
+
+.PHONY: all
+
+all:
+ @echo "To build RPMS run 'make glusterrpms'"
+
+.PHONY: glusterrpms prep srcrpm testsrpm clean
+
+glusterrpms: prep srcrpm rpms
+ -rm -rf rpmbuild
+
+prep:
+ if [ ! -e $(GFS_TAR) ]; then \
+ $(MAKE) -C ../.. dist; \
+ fi
+ -mkdir -p rpmbuild/SPECS
+ -mkdir -p rpmbuild/RPMS
+ -mkdir -p rpmbuild/SRPMS
+ -rm -rf rpmbuild/SOURCES
+ @if [ -d /d/cache/glusterfs -a -e /d/cache/glusterfs/sources ]; then \
+ echo "copying glusterfs rpm files from local cache..." ; \
+ mkdir -p ./rpmbuild/SOURCES; \
+ cp /d/cache/glusterfs/* ./rpmbuild/SOURCES/ ; \
+ elif [ -x /usr/bin/git ]; then \
+ echo "fetching glusterfs rpm files from fedora git repo..."; \
+ cd ./rpmbuild && git clone git://pkgs.fedoraproject.org/glusterfs.git > /dev/null && mv glusterfs SOURCES; \
+ else \
+ echo "glusterfs rpm files not fetched, you don't have git installed!" ; \
+ exit 1 ; \
+ fi
+ cp ../../*.tar.gz ./rpmbuild/SOURCES
+ cp ../../glusterfs.spec ./rpmbuild/SPECS
+
+srcrpm:
+ rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bs rpmbuild/SPECS/glusterfs.spec
+ mv rpmbuild/SRPMS/* .
+
+rpms:
+ rpmbuild --define '_topdir $(shell pwd)/rpmbuild' -bb rpmbuild/SPECS/glusterfs.spec
+ mv rpmbuild/RPMS/*/* .
+
+# EPEL-5 does not like new versions of rpmbuild and requires some
+# _source_* defines
+
+testsrpm: prep
+ rpmbuild --define '_topdir $(shell pwd)/rpmbuild' \
+ --define '_source_payload w9.gzdio' \
+ --define '_source_filedigest_algorithm 1' \
+ -bs rpmbuild/SPECS/glusterfs.spec
+ mv rpmbuild/SRPMS/* ../..
+ -rm -rf rpmbuild
+
+clean:
+ -rm -rf rpmbuild
+ -rm -f *.rpm
diff --git a/extras/MacOSX/Portfile b/extras/MacOSX/Portfile
index 0094ee4c4..1262a44da 100644
--- a/extras/MacOSX/Portfile
+++ b/extras/MacOSX/Portfile
@@ -5,12 +5,12 @@ PortSystem 1.0
name glusterfs
version 2.0.0rc8
categories fuse
-maintainers amar@zresearch.com
+maintainers amar@gluster.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
+master_sites http://ftp.gluster.com/pub/gluster/glusterfs/2.0/2.0.0
configure.args --disable-bdb
checksums md5 33c2d02344d4fab422e80cfb637e0b48
@@ -18,7 +18,7 @@ checksums md5 33c2d02344d4fab422e80cfb637e0b48
post-destroot {
file mkdir ${destroot}/Library/LaunchDaemons/
file copy ${worksrcpath}/extras/glusterfs-server.plist \
- ${destroot}/Library/LaunchDaemons/com.zresearch.glusterfs.plist
+ ${destroot}/Library/LaunchDaemons/com.gluster.glusterfs.plist
file mkdir ${destroot}/sbin/
file copy ${worksrcpath}/xlators/mount/fuse/utils/mount_glusterfs \
diff --git a/extras/MacOSX/README.MacOSX b/extras/MacOSX/README.MacOSX
index cc38958d8..ec7abc2cc 100644
--- a/extras/MacOSX/README.MacOSX
+++ b/extras/MacOSX/README.MacOSX
@@ -24,7 +24,7 @@ system. Run,
bash# sudo /Library/Filesystems/fusefs.fs/Support/uninstall-macfuse-core.sh
After this, install MacFUSE (mostly through .dmg available in macfuse homepage
-or if Z Research Inc provides any custom built .dmg)
+or if Gluster Inc provides any custom built .dmg)
Make sure the .dmg of glusterfs is built against the installed MacFUSE version
(if not, any operations over mountpoint gives EIO ie, Input/Output Error). If
@@ -40,7 +40,7 @@ after the entry is added in /etc/fstab, it can be mounted by 'mount' command.
To start the server process one can use the 'launchd' mechanism. Follow below
steps after installation
- bash# launchctl load /Library/LaunchDaemons/com.zresearch.glusterfs.plist
+ bash# launchctl load /Library/LaunchDaemons/com.gluster.glusterfs.plist
No need to run the command if the machine reboots, as it will be loaded
automatically by launchd process.
@@ -51,17 +51,17 @@ Now copy the server volume file in the proper path
NOTE: (If glusterfs is installed in different path other than '/opt/local'
update the volume file at the corresponding path, and also need to
- update the /Library/LaunchDaemons/com.zresearch.glusterfs.plist with
+ update the /Library/LaunchDaemons/com.gluster.glusterfs.plist with
the proper path)
Once the volume file is updated, administrator can start the server process by
running,
- bash# launchctl start com.zresearch.glusterfs
+ bash# launchctl start com.gluster.glusterfs
and stop like
- bash# launchctl stop com.zresearch.glusterfs
+ bash# launchctl stop com.gluster.glusterfs
NOTE: To start the process by default when the loaded, one need to add the
following lines to .plist file
diff --git a/extras/Makefile.am b/extras/Makefile.am
index 9be397300..cf619329b 100644
--- a/extras/Makefile.am
+++ b/extras/Makefile.am
@@ -1,11 +1,20 @@
-docdir = $(datadir)/doc/glusterfs/
-EditorModedir = $(docdir)/
+EditorModedir = $(docdir)
EditorMode_DATA = glusterfs-mode.el glusterfs.vim
-SUBDIRS = init.d benchmarking
+SUBDIRS = init.d systemd benchmarking hook-scripts $(OCF_SUBDIR) LinuxRPM geo-rep
-EXTRA_DIST = specgen.scm MacOSX/Portfile glusterfs-mode.el glusterfs.vim migrate-unify-to-distribute.sh backend-xattr-sanitize.sh
+confdir = $(sysconfdir)/glusterfs
+conf_DATA = glusterfs-logrotate gluster-rsyslog-7.2.conf gluster-rsyslog-5.8.conf \
+ logger.conf.example glusterfs-georep-logrotate
-CLEANFILES =
+voldir = $(sysconfdir)/glusterfs
+vol_DATA = glusterd.vol
+EXTRA_DIST = specgen.scm MacOSX/Portfile glusterfs-mode.el glusterfs.vim \
+ migrate-unify-to-distribute.sh backend-xattr-sanitize.sh \
+ backend-cleanup.sh disk_usage_sync.sh quota-remove-xattr.sh \
+ quota-metadata-cleanup.sh glusterfs-logrotate clear_xattrs.sh \
+ group-virt.example glusterd-sysconfig gluster-rsyslog-7.2.conf \
+ gluster-rsyslog-5.8.conf logger.conf.example glusterd.vol \
+ glusterfs-georep-logrotate
diff --git a/extras/Solaris/Prototype b/extras/Solaris/Prototype
index 369234210..cb2d99d8c 100644
--- a/extras/Solaris/Prototype
+++ b/extras/Solaris/Prototype
@@ -9,6 +9,9 @@ d none /usr/sfw/share 0755 root bin
d none /usr/sfw/share/man 0755 root bin
d none /usr/sfw/share/man/man8 0755 root bin
f none /usr/sfw/share/man/man8/glusterfs.8 0644 root root
+f none /usr/sfw/share/man/man8/gluster.8 0644 root root
+f none /usr/sfw/share/man/man8/glusterd.8 0644 root root
+f none /usr/sfw/share/man/man8/glusterfs-volgen.8 0644 root root
d none /usr/sfw/share/doc 0755 root bin
d none /usr/sfw/share/doc/glusterfs 0755 root root
d none /usr/sfw/share/doc/glusterfs/examples 0755 root root
diff --git a/extras/Solaris/README.solaris b/extras/Solaris/README.solaris
index 0cea45bdc..5a4e4336d 100644
--- a/extras/Solaris/README.solaris
+++ b/extras/Solaris/README.solaris
@@ -10,7 +10,7 @@ $ which glusterfs
$ glusterfs --version
glusterfs 2.0.0rc1 built on Jan 16 2009 03:36:59
Repository revision: glusterfs--mainline--3.0--patch-844
-Copyright (c) 2006, 2007, 2008 Z RESEARCH Inc. <http://www.zresearch.com>
+Copyright (c) 2006-2011 Gluster Inc. <http://www.gluster.com>
GlusterFS comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GlusterFS under the terms of the GNU General Public License.
diff --git a/extras/Solaris/pkginfo b/extras/Solaris/pkginfo
index ffa1f2d9a..0da4907d8 100644
--- a/extras/Solaris/pkginfo
+++ b/extras/Solaris/pkginfo
@@ -4,9 +4,9 @@ VERSION="2.0.0rc1"
ARCH="i386"
CLASSES="none"
CATEGORY="system"
-VENDOR="ZResearch Inc"
+VENDOR="Gluster Inc"
PSTAMP="16thJan08"
-EMAIL="harsha@zresearch.com"
+EMAIL="harsha@gluster.com"
ISTATES="S s 1 2 3"
RSTATES="S s 1 2 3"
BASEDIR="/"
diff --git a/extras/Ubuntu/README.Ubuntu b/extras/Ubuntu/README.Ubuntu
new file mode 100644
index 000000000..0c5b7828d
--- /dev/null
+++ b/extras/Ubuntu/README.Ubuntu
@@ -0,0 +1,24 @@
+Bug 765014 - Mounting from localhost in fstab fails at boot on ubuntu
+(https://bugzilla.redhat.com/show_bug.cgi?id=765014)
+(https://bugs.launchpad.net/ubuntu/+source/glusterfs/+bug/876648)
+
+Ubuntu uses upstart instead of init to bootstrap the system and it has a unique
+way of handling fstab, using a program called mountall(8). As a result of using
+a debian initscript to start glusterd, glusterfs mounts in fstab are tried before
+the glusterd service is running. In the case where the client is also a server
+and the volume is mounted from localhost, the mount fails at boot time. To
+correct this we need to launch glusterd using upstart and block the glusterfs
+mounting event until glusterd is started.
+
+The glusterd.conf file contains the necessary configuration for upstart to
+manage the glusterd service. It should be placed in /etc/init/glusterd.conf
+on Ubuntu systems, and then the old initscript /etc/init.d/glusterd can be
+removed. An additional upstart job, mounting-glusterfs.conf, is also required
+to block mounting glusterfs volumes until the glusterd service is available.
+Both of these upstart jobs need to be placed in /etc/init to resolve the issue.
+
+Starting with Ubuntu 12.04, Precise Pangolin, these upstart jobs will be
+included with the glusterfs-server package in the Ubuntu repository.
+
+This affects all versions of glusterfs on the Ubuntu platform since at least
+10.04, Lucid Lynx.
diff --git a/extras/Ubuntu/glusterd.conf b/extras/Ubuntu/glusterd.conf
new file mode 100644
index 000000000..aa99502b0
--- /dev/null
+++ b/extras/Ubuntu/glusterd.conf
@@ -0,0 +1,10 @@
+author "Louis Zuckerman <me@louiszuckerman.com>"
+description "GlusterFS Management Daemon"
+
+start on runlevel [2345]
+stop on runlevel [016]
+
+expect fork
+
+exec /usr/sbin/glusterd -p /var/run/glusterd.pid
+
diff --git a/extras/Ubuntu/mounting-glusterfs.conf b/extras/Ubuntu/mounting-glusterfs.conf
new file mode 100644
index 000000000..3c59c0f63
--- /dev/null
+++ b/extras/Ubuntu/mounting-glusterfs.conf
@@ -0,0 +1,7 @@
+author "Louis Zuckerman <me@louiszuckerman.com>"
+description "Block the mounting event for glusterfs filesystems until glusterd is running"
+
+start on mounting TYPE=glusterfs
+task
+exec start wait-for-state WAIT_FOR=glusterd WAITER=mounting-glusterfs
+
diff --git a/extras/backend-cleanup.sh b/extras/backend-cleanup.sh
new file mode 100644
index 000000000..dc504860b
--- /dev/null
+++ b/extras/backend-cleanup.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# This script can be used to cleanup the 'cluster/distribute' translator's
+# stale link files. One may choose to run this only when number of subvolumes
+# to distribute volume gets increased (or decreased)
+#
+# This script has to be run on the servers, which are exporting the data to
+# GlusterFS
+#
+# (c) 2010 Gluster Inc <http://www.gluster.com/>
+
+set -e
+
+# Change the below variable as per the setup.
+export_directory="/export/glusterfs"
+
+clean_dir()
+{
+ # Clean the 'link' files on backend
+ find "${export_directory}" -type f -perm +01000 -exec rm -v '{}' \;
+}
+
+main()
+{
+ clean_dir ;
+}
+
+main "$@"
diff --git a/extras/benchmarking/Makefile.am b/extras/benchmarking/Makefile.am
index 04cc06182..bfcc59277 100644
--- a/extras/benchmarking/Makefile.am
+++ b/extras/benchmarking/Makefile.am
@@ -1,7 +1,5 @@
-docdir = $(datadir)/doc/$(PACKAGE_NAME)/benchmarking
-
-benchmarkingdir = $(docdir)
+benchmarkingdir = $(docdir)/benchmarking
benchmarking_DATA = rdd.c glfs-bm.c README launch-script.sh local-script.sh
diff --git a/extras/benchmarking/glfs-bm.c b/extras/benchmarking/glfs-bm.c
index 66b32b3f0..dc717f33c 100644
--- a/extras/benchmarking/glfs-bm.c
+++ b/extras/benchmarking/glfs-bm.c
@@ -1,28 +1,18 @@
-/*
- Copyright (c) 2008-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
- 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
- <http://www.gnu.org/licenses/>.
+/*
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
*/
-
#define _GNU_SOURCE
#define __USE_FILE_OFFSET64
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <argp.h>
-#include <libglusterfsclient.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
@@ -42,7 +32,6 @@ struct state {
char need_iface_xattr:1;
char need_mode_posix:1;
- char need_mode_libglusterfsclient:1;
char prefix[512];
long int count;
@@ -50,7 +39,6 @@ struct state {
size_t block_size;
char *specfile;
- void *libglusterfsclient_context;
long int io_size;
};
@@ -132,21 +120,6 @@ parse_opts (int key, char *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);
@@ -342,170 +315,6 @@ do_mode_posix_iface_xattr (struct state *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; i<state->count; 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; i<state->count; 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; i<state->count; 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; i<state->count; 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)
{
@@ -520,44 +329,8 @@ do_mode_posix (struct state *state)
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);
@@ -569,8 +342,6 @@ static struct argp_option options[] = {
"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,
"<NUM> - defaults to 4096"},
{"specfile", 's', "SPECFILE", 0,
@@ -601,7 +372,6 @@ main (int argc, char *argv[])
state.need_iface_xattr = 0;
state.need_mode_posix = 1;
- state.need_mode_libglusterfsclient = 0;
state.block_size = 4096;
diff --git a/extras/benchmarking/rdd.c b/extras/benchmarking/rdd.c
index d30660b50..a667c6a1d 100644
--- a/extras/benchmarking/rdd.c
+++ b/extras/benchmarking/rdd.c
@@ -1,22 +1,12 @@
/*
- Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.com>
- 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
- <http://www.gnu.org/licenses/>.
-*/
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -36,172 +26,278 @@
#define UNIX_PATH_MAX 108
#endif
+#define UNIT_KB 1024ULL
+#define UNIT_MB UNIT_KB*1024ULL
+#define UNIT_GB UNIT_MB*1024ULL
+#define UNIT_TB UNIT_GB*1024ULL
+#define UNIT_PB UNIT_TB*1024ULL
+
+#define UNIT_KB_STRING "KB"
+#define UNIT_MB_STRING "MB"
+#define UNIT_GB_STRING "GB"
+#define UNIT_TB_STRING "TB"
+#define UNIT_PB_STRING "PB"
+
struct rdd_file {
- char path[UNIX_PATH_MAX];
- struct stat st;
- int fd;
+ 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;
+ 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;
+ ssize_t file_size;
};
static struct rdd_config rdd_config;
enum rdd_keys {
- RDD_MIN_BS_KEY = 1,
- RDD_MAX_BS_KEY,
+ RDD_MIN_BS_KEY = 1,
+ RDD_MAX_BS_KEY,
};
-
+
static error_t
rdd_parse_opts (int key, char *arg,
- struct argp_state *_state)
+ 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",
+ 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",
+ 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"
+ return -1;
+ }
+
+ strncpy (rdd_config.in_file.path, arg, len);
+ rdd_config.in_file.path[len] = '\0';
+ }
+ break;
+
+ case 'f':
+ {
+ char *tmp = NULL;
+ unsigned long long fs = 0;
+ if (string2bytesize (arg, &fs) == -1) {
+ fprintf (stderr, "invalid argument for file size "
+ "(%s)\n", arg);
+ return -1;
+ }
+
+ rdd_config.file_size = fs;
+ }
+ 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"
+ 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) ||
+ 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"
+ 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) ||
+ 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"
+ 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) ||
+ 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"
+ fprintf (stderr, "invalid argument for thread count"
"(%s)\n", arg);
- return -1;
- }
+ return -1;
+ }
- rdd_config.thread_count = threads;
- }
- break;
+ 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);
- }
+ case ARGP_KEY_NO_ARGS:
+ break;
+ case ARGP_KEY_ARG:
+ break;
+ case ARGP_KEY_END:
+ if (_state->argc == 1) {
+ argp_usage (_state);
+ }
- }
+ }
- return 0;
+ return 0;
+}
+
+int
+string2bytesize (const char *str, unsigned long long *n)
+{
+ unsigned long long value = 0ULL;
+ char *tail = NULL;
+ int old_errno = 0;
+ const char *s = NULL;
+
+ if (str == NULL || n == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ for (s = str; *s != '\0'; s++)
+ {
+ if (isspace (*s))
+ {
+ continue;
+ }
+ if (*s == '-')
+ {
+ return -1;
+ }
+ break;
+ }
+
+ old_errno = errno;
+ errno = 0;
+ value = strtoull (str, &tail, 10);
+
+ if (errno == ERANGE || errno == EINVAL)
+ {
+ return -1;
+ }
+
+ if (errno == 0)
+ {
+ errno = old_errno;
+ }
+
+ if (tail[0] != '\0')
+ {
+ if (strcasecmp (tail, UNIT_KB_STRING) == 0)
+ {
+ value *= UNIT_KB;
+ }
+ else if (strcasecmp (tail, UNIT_MB_STRING) == 0)
+ {
+ value *= UNIT_MB;
+ }
+ else if (strcasecmp (tail, UNIT_GB_STRING) == 0)
+ {
+ value *= UNIT_GB;
+ }
+ else if (strcasecmp (tail, UNIT_TB_STRING) == 0)
+ {
+ value *= UNIT_TB;
+ }
+ else if (strcasecmp (tail, UNIT_PB_STRING) == 0)
+ {
+ value *= UNIT_PB;
+ }
+
+ else
+ {
+ return -1;
+ }
+ }
+
+ *n = value;
+
+ 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}
+ {"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)"},
+ {"file-size", 'f', "FILESIZE", 0,
+ "the size of the file which will be created and upon it I/O will be done"
+ " (defaults to 100MB"},
+ {0, 0, 0, 0, 0}
};
static struct argp argp = {
@@ -216,277 +312,341 @@ static struct argp argp = {
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;
+ char *tmp_path = "rdd.in";
+
+ 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;
+ strncpy (rdd_config.in_file.path, tmp_path, strlen (tmp_path));
+ rdd_config.file_size = 104857600;
+
+ 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",
+ char ret = 1;
+ int fd = -1;
+
+ fd = open (rdd_config.in_file.path, O_RDONLY);
+ if (fd == -1 && (errno != ENOENT)) {
+ fprintf (stderr, "open: (%s)", strerror (errno));
+ ret = 0;
+ goto out;
+ }
+ close (fd);
+
+ if (rdd_config.min_bs > rdd_config.max_bs) {
+ fprintf (stderr, "minimum blocksize %ld is greater than the "
+ "maximum blocksize %ld", 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;
+ 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 -
+ 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",
+ }
+
+ 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 = -1;
+ goto unlock;
+ }
- ret = lseek (rdd_config.out_file.fd, offset, SEEK_SET);
- if (ret != offset) {
- fprintf (stderr, "lseek failed (%s)\n",
+ 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",
+ 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;
- }
+ ret = -1;
+ goto unlock;
+ }
- if (write (rdd_config.out_file.fd, buf, bytes)
+ if (write (rdd_config.out_file.fd, buf, bytes)
!= bytes) {
- fprintf (stderr, "write failed (%s)\n",
+ 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;
- }
+ 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);
+ free (buf);
+ pthread_barrier_wait (&rdd_config.barrier);
- return NULL;
+ return NULL;
}
+static void
+cleanup (void)
+{
+ close (rdd_config.in_file.fd);
+ close (rdd_config.out_file.fd);
+ rdd_config.in_file.fd = rdd_config.out_file.fd = -1;
+}
+
+static int
+check_and_create (void)
+{
+ int ret = -1;
+ char buf[4096] = {0,};
+ struct stat stbuf = {0,};
+ int fd[2] = {-1,};
+ size_t total_size = -1;
+
+ total_size = rdd_config.file_size;
+
+ ret = stat (rdd_config.in_file.path, &stbuf);
+ if (ret == -1 && (errno != ENOENT))
+ goto out;
+
+ fd[1] = open (rdd_config.in_file.path, O_CREAT | O_WRONLY | O_TRUNC);
+ if (fd[1] == -1)
+ goto out;
+
+ fd[0] = open ("/dev/urandom", O_RDONLY);
+ if (fd[0] == -1)
+ goto out;
+
+ while (total_size > 0) {
+ if (total_size >= 4096) {
+ ret = read (fd[0], buf, 4096);
+ if (ret == -1)
+ goto out;
+ ret = write (fd[1], buf, 4096);
+ if (ret == -1)
+ goto out;
+ total_size = total_size - 4096;
+ } else {
+ ret = read (fd[0], buf, total_size);
+ if (ret == -1)
+ goto out;
+ ret = write (fd[1], buf, total_size);
+ if (ret == -1)
+ goto out;
+ total_size = total_size - total_size;
+ }
+
+ }
+
+ ret = 0;
+
+out:
+ if (fd[0] > 0)
+ close (fd[0]);
+ if (fd[1] > 0)
+ close (fd[1]);
+ return ret;
+}
static int
rdd_spawn_threads (void)
{
- int i = 0, ret = -1, fd = -1;
- char buf[4096];
+ 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",
+ ret = check_and_create ();
+ if (ret == -1)
+ goto out;
+
+ 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",
+ 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;
+ ret = -1;
+ goto out;
+ }
+ rdd_config.in_file.fd = fd;
- fd = open (rdd_config.out_file.path, O_WRONLY | O_CREAT,
+ fd = open (rdd_config.out_file.path, O_WRONLY | O_CREAT | O_TRUNC,
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",
+ 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",
+ 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,
+ cleanup ();
+ 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));
+ 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 = -1;
+ cleanup ();
+ goto out;
+ }
- ret = pthread_barrier_init (&rdd_config.barrier, NULL,
+ ret = pthread_barrier_init (&rdd_config.barrier, NULL,
rdd_config.thread_count + 1);
- if (ret != 0) {
- fprintf (stderr, "pthread_barrier_init() failed (%s)\n",
+ 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",
+ free (rdd_config.threads);
+ cleanup ();
+ 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,
+ free (rdd_config.threads);
+ pthread_barrier_destroy (&rdd_config.barrier);
+ cleanup ();
+ 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",
+ if (ret != 0) {
+ fprintf (stderr, "pthread_create failed (%s)\n",
strerror (errno));
- exit (1);
- }
- }
+ exit (1);
+ }
+ }
out:
- return ret;
+ return ret;
}
-
static void
rdd_wait_for_completion (void)
{
- pthread_barrier_wait (&rdd_config.barrier);
+ pthread_barrier_wait (&rdd_config.barrier);
}
-int
+int
main (int argc, char *argv[])
{
- int ret = -1;
+ int ret = -1;
- rdd_default_config ();
+ 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;
- }
+ 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",
+ if (!rdd_valid_config ()) {
+ ret = -1;
+ fprintf (stderr, "%s: configuration validation failed\n",
argv[0]);
- goto err;
- }
+ goto err;
+ }
- ret = rdd_spawn_threads ();
- if (ret != 0) {
- fprintf (stderr, "%s: spawning threads 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 ();
+ rdd_wait_for_completion ();
err:
- return ret;
-}
+ return ret;
+}
diff --git a/extras/clear_xattrs.sh b/extras/clear_xattrs.sh
new file mode 100755
index 000000000..dd04731e8
--- /dev/null
+++ b/extras/clear_xattrs.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# Clear the trusted.gfid xattr in the brick tree
+
+# This script must be run only on a stopped brick/volume
+# Stop the volume to make sure no rebalance/replace-brick
+# operations are on-going
+
+# Not much error checking
+remove_xattrs ()
+{
+ find "$1" -exec setfattr -h -x "trusted.gfid" '{}' \; > /dev/null 2>&1;
+ find "$1" -exec setfattr -h -x "trusted.glusterfs.volume-id" '{}' \; > /dev/null 2>&1;
+}
+
+main ()
+{
+ if [ -z "$1" ]; then
+ echo "Usage: $0 <brick_path(s)>";
+ exit 1;
+ fi
+
+ export PATH;
+ which getfattr > /dev/null 2>&1;
+ if [ $? -ne 0 ]; then
+ echo "attr package missing";
+ exit 2;
+ fi
+
+ which setfattr > /dev/null 2>&1;
+ if [ $? -ne 0 ]; then
+ echo "attr package missing";
+ exit 2;
+ fi
+
+ for brick in "$@";
+ do
+ stat "$brick" > /dev/null 2>&1;
+ if [ $? -ne 0 ]; then
+ echo "brick: $brick does not exist";
+ exit 3;
+ fi
+ if [ ! -d "$brick" ]; then
+ echo "$brick: not a directory";
+ exit 4;
+ fi
+ echo "xattr clean-up in progress: $brick";
+ remove_xattrs "$brick";
+ echo "$brick ready to be used as a glusterfs brick";
+ done;
+}
+
+main "$@"; \ No newline at end of file
diff --git a/extras/contri-add.sh b/extras/contri-add.sh
new file mode 100755
index 000000000..7db5edd5d
--- /dev/null
+++ b/extras/contri-add.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+# This script adds contributions of files/directories in backend to volume
+# size.
+# It can also be used to debug by passing dir as first argument, in which case
+# it will just add contributions from immediate children of a directory and
+# displays only if added contributions from immediate children is different
+# from size stored in directory.
+# For Eg., find <backend-directory> -type d -exec ./contri-add.sh dir \{} \;
+# will list all the directories which have descrepancies in their
+# size/contributions.
+
+usage ()
+{
+ echo >&2 "usage: $0 <file|dir> <list-of-backend-directories>"
+}
+
+add_contributions ()
+{
+ local var=0
+ local count=0
+
+ SIZE=`getfattr -h -e hex -n trusted.glusterfs.quota.size $2 2>&1 | sed -e '/^#/d' | sed -e '/^getfattr/d' | sed -e '/^$/d' | cut -d'=' -f 2`
+ CONTRI=`getfattr -h -e hex -d -m trusted.glusterfs.quota.*.contri $2 2>&1 | sed -e '/^#/d' | sed -e '/^getfattr/d' | sed -e '/^$/d' | cut -d'=' -f 2`
+
+ if [ $1 == "file" ]; then
+ PATHS=`find $2 ! -type d | sed -e "\|^$2$|d" | sed -e '/^[ \t]*$/d'`
+ else
+ PATHS=`find $2 -maxdepth 1 | sed -e "\|^$2$|d" | sed -e '/^[ \t]*$/d'`
+ fi
+
+ if [ -z "$PATHS" ]; then
+ return 0
+ fi
+
+ CONTRIBUTIONS=`echo $PATHS | xargs getfattr -h -e hex -d -m trusted.glusterfs.quota.*.contri 2>&1 | sed -e '/^#/d' | sed -e '/^getfattr/d' | sed -e '/^$/d' | cut -d'=' -f 2 | sed -e 's/^[ \t]*\([^ \t]*\)/\1/g'`
+
+ if [ -n "$CONTRIBUTIONS" ]; then
+ for i in $CONTRIBUTIONS; do
+ count=$(($count + 1))
+ var=$(($var + $i))
+ done
+ fi
+
+ if [ $1 == "file" ] || [ $var -ne $(($SIZE)) ] || [ $(($SIZE)) -ne $(($CONTRI)) ]; then
+ if [ $1 == "dir" ]; then
+ TMP_PATH=`echo $2 | sed -e "s/\/home\/export\/[0-9]*/\/mnt\/raghu/g"`
+ stat $TMP_PATH > /dev/null
+ fi
+
+ echo "file count $count"
+ echo "added contribution of $2=$var"
+ echo "size stored in xattrs on $2=$(($SIZE))"
+ echo "contribution of $2 to its parent directory=$(($CONTRI))"
+ echo "=============================================================="
+ fi
+}
+
+
+main ()
+{
+ [ $# -lt 1 ] && usage
+
+ TYPE=$1
+
+ shift 1
+
+ for i in $@; do
+ add_contributions $TYPE $i
+ done
+}
+
+main $@ \ No newline at end of file
diff --git a/extras/disk_usage_sync.sh b/extras/disk_usage_sync.sh
new file mode 100755
index 000000000..85ee158f8
--- /dev/null
+++ b/extras/disk_usage_sync.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+# This script can be used to sync disk usage before activating quotas on GlusterFS.
+# There are two scenarios where quotas are used and this script has to be used accordingly -
+#
+# 1. Server side
+# The script needs to be run with backend export directory as the argument. This script updates
+# the current disk usage of the backend directory in a way that is intelligible to the GlusterFS quota
+# translator. Make sure you run this script before starting glusterfsd (GlusterFS server process):
+# * for the first time
+# * after any server outage (reboot, etc.)
+
+# 2. Client side
+# The script needs to be run with the client mount point as the argument. It updates the current disk
+# of the GlusterFS volume is a way that is intelligible to the GlusterFS quota translator. Make sure
+# you run this script after a fresh mount of the GlusterFS volume on the client:
+# * For the first time
+# * After any client outage (reboot, remount, etc.)
+
+# Please note that this script is dependent on the 'attr' package, more specifically 'setfattr' to set
+# extended attributes of files.
+# GlusterFS
+#
+# (c) 2010 Gluster Inc <http://www.gluster.com/>
+
+PROGRAM_NAME="disk_usage_sync.sh"
+
+#check if setfattr is available
+check_for_attr ()
+{
+ `command -v setfattr >/dev/null`
+ if [ "${?}" -gt 0 ]; then
+ echo >&2 "This script requires the 'attr' package to run. Either it has not been installed or is not present currently in the system path."
+ exit 1
+ fi
+
+}
+
+usage () {
+ echo >&2 "$PROGRAM_NAME - Command used to sync disk usage information before activating quotas on GlusterFS.
+
+usage: $PROGRAM_NAME <target-directory>"
+
+exit 1
+}
+
+TARGET_DIR=$1
+EXT_ATTR_NAME="trusted.glusterfs-quota-du"
+
+#output of du in number of bytes
+get_disk_usage ()
+{
+ if [ ! -d $TARGET_DIR ]; then
+ echo >&2 "Error: $TARGET_DIR does not exist."
+ exit 1
+ fi
+
+ DISK_USAGE=`du -bc $TARGET_DIR | grep 'total' | cut -f1`
+ if [ "${?}" -gt 0 ]; then
+ exit 1
+ fi
+
+}
+
+#set the extended attribute of the root directory with du size in bytes
+set_disk_usage ()
+{
+ ` setfattr -n $EXT_ATTR_NAME -v $DISK_USAGE $TARGET_DIR`
+ if [ "${?}" -gt 0 ]; then
+ exit 1
+ fi
+}
+
+main ()
+{
+ [ $# -lt 1 ] && usage
+
+ check_for_attr
+
+ get_disk_usage
+ set_disk_usage
+
+ printf "Disk Usage information has been sync'd successfully.\n"
+}
+
+main "$@"
diff --git a/extras/file_size_contri.sh b/extras/file_size_contri.sh
new file mode 100755
index 000000000..4f52a9a89
--- /dev/null
+++ b/extras/file_size_contri.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# This script checks whether the contribution and disk-usage of a file is same.
+
+CONTRIBUTION_HEX=`getfattr -h -e hex -d -m trusted.glusterfs.quota.*.contri $1 2>&1 | sed -e '/^#/d' | sed -e '/^getfattr/d' | sed -e '/^$/d' | cut -d'=' -f 2`
+
+BLOCKS=`stat -c %b $1`
+SIZE=$(($BLOCKS * 512))
+
+CONTRIBUTION=`printf "%d" $CONTRIBUTION_HEX`
+
+if [ $CONTRIBUTION -ne $SIZE ]; then
+ printf "contribution of %s:%d\n" $1 $CONTRIBUTION
+ echo "size of $1: $SIZE"
+ echo "==================================================="
+fi
+
diff --git a/extras/generate-xdr-files.sh b/extras/generate-xdr-files.sh
new file mode 100755
index 000000000..bc02f77c9
--- /dev/null
+++ b/extras/generate-xdr-files.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+_init ()
+{
+ xfile="$1";
+ # TODO: check the validity of .x file
+
+ cfile="${1%.x}.c";
+ hfile="${1%.x}.h";
+
+ tmp_cfile="$1.c";
+
+ tmp1_hfile="$1.h.tmp";
+ tmp1_cfile="$1.c.tmp";
+
+}
+
+append_licence_header ()
+{
+ src_file=$1;
+ dst_file=$2;
+
+ cat >$dst_file <<EOF
+/*
+ Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#include "xdr-common.h"
+#include "compat.h"
+
+#if defined(__GNUC__)
+#if __GNUC__ >= 4
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+#endif
+
+EOF
+
+ cat $src_file >> $dst_file;
+
+}
+
+main ()
+{
+ if [ $# -ne 1 ]; then
+ echo "wrong number of arguments given"
+ echo " $0 <XDR-definition-file>.x"
+ exit 1;
+ fi
+
+
+ echo -n "writing the XDR routine file ($tmp_cfile) ... ";
+ rm -f $tmp_cfile;
+ rpcgen -c -o $tmp_cfile $xfile;
+
+ # get rid of warnings in xdr .c file due to "unused variable 'buf'"
+ sed -i -e 's:buf;$:buf;\
+ buf = NULL;:' $tmp_cfile;
+
+ sed -i '/int i;/d' $tmp_cfile;
+
+ echo "OK";
+
+ # no need for a temporary file here as there are no changes from glusterfs
+ echo -n "writing the XDR header file ($hfile) ... ";
+ rm -f $hfile;
+ rpcgen -h -o $hfile $xfile;
+
+ # the '#ifdef' part of file should be fixed
+ sed -i -e 's/-/_/g' $hfile;
+
+ echo "OK";
+
+ echo -n "writing licence header to the generated files ... ";
+ # Write header to temp file and append generated file
+ append_licence_header $hfile $tmp1_hfile;
+ append_licence_header $tmp_cfile $tmp1_cfile;
+ echo "OK"
+
+ # now move the destination file to actual original file
+ echo -n "updating existing files ... ";
+ mv $tmp1_hfile $hfile;
+ mv $tmp1_cfile $cfile;
+
+ # remove unwanted temporary files (if any)
+ rm -f $tmp_cfile $tmp1_cfile $tmp1_hfile
+
+ echo "OK"
+
+}
+
+_init "$@" && main "$@";
diff --git a/extras/geo-rep/Makefile.am b/extras/geo-rep/Makefile.am
new file mode 100644
index 000000000..fc5f56d54
--- /dev/null
+++ b/extras/geo-rep/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = gsync-sync-gfid.c gsync-upgrade.sh generate-gfid-file.sh \
+ get-gfid.sh slave-upgrade.sh
diff --git a/extras/geo-rep/generate-gfid-file.sh b/extras/geo-rep/generate-gfid-file.sh
new file mode 100644
index 000000000..c6739fbf1
--- /dev/null
+++ b/extras/geo-rep/generate-gfid-file.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+#Usage: generate-gfid-file.sh <master-volfile-server:master-volume> <path-to-get-gfid.sh> <output-file>
+
+function get_gfids()
+{
+ GET_GFID_CMD=$1
+ OUTPUT_FILE=$2
+ find . -exec $GET_GFID_CMD {} \; > $OUTPUT_FILE
+}
+
+function mount_client()
+{
+ local T; # temporary mount
+ local i; # inode number
+
+ VOLFILE_SERVER=$1;
+ VOLUME=$2;
+ GFID_CMD=$3;
+ OUTPUT=$4;
+
+ T=$(mktemp -d);
+
+ glusterfs -s $VOLFILE_SERVER --volfile-id $VOLUME $T;
+
+ i=$(stat -c '%i' $T);
+
+ [ "x$i" = "x1" ] || fatal "could not mount volume $MASTER on $T";
+
+ cd $T;
+
+ get_gfids $GFID_CMD $OUTPUT
+
+ cd -;
+
+ umount $T || fatal "could not umount $MASTER from $T";
+
+ rmdir $T || warn "rmdir of $T failed";
+}
+
+
+function main()
+{
+ SLAVE=$1
+ GET_GFID_CMD=$2
+ OUTPUT=$3
+
+ VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'`
+ VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'`
+
+ mount_client $VOLFILE_SERVER $VOLUME_NAME $GET_GFID_CMD $OUTPUT
+}
+
+main "$@";
diff --git a/extras/geo-rep/get-gfid.sh b/extras/geo-rep/get-gfid.sh
new file mode 100755
index 000000000..a4d609b0b
--- /dev/null
+++ b/extras/geo-rep/get-gfid.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+ATTR_STR=`getfattr -h $1 -n glusterfs.gfid.string`
+GLFS_PATH=`echo $ATTR_STR | sed -e 's/# file: \(.*\) glusterfs.gfid.string*/\1/g'`
+GFID=`echo $ATTR_STR | sed -e 's/.*glusterfs.gfid.string="\(.*\)"/\1/g'`
+
+echo "$GFID $GLFS_PATH"
diff --git a/extras/geo-rep/gsync-sync-gfid.c b/extras/geo-rep/gsync-sync-gfid.c
new file mode 100644
index 000000000..601f4720e
--- /dev/null
+++ b/extras/geo-rep/gsync-sync-gfid.c
@@ -0,0 +1,106 @@
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <attr/xattr.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#ifndef UUID_CANONICAL_FORM_LEN
+#define UUID_CANONICAL_FORM_LEN 36
+#endif
+
+#ifndef GF_FUSE_AUX_GFID_HEAL
+#define GF_FUSE_AUX_GFID_HEAL "glusterfs.gfid.heal"
+#endif
+
+#define GLFS_LINE_MAX (PATH_MAX + (2 * UUID_CANONICAL_FORM_LEN))
+
+int
+main (int argc, char *argv[])
+{
+ char *file = NULL;
+ char *tmp = NULL;
+ char *tmp1 = NULL;
+ char *parent_dir = NULL;
+ char *gfid = NULL;
+ char *bname = NULL;
+ int ret = -1;
+ int len = 0;
+ FILE *fp = NULL;
+ char line[GLFS_LINE_MAX] = {0,};
+ char *path = NULL;
+ void *blob = NULL;
+ void *tmp_blob = NULL;
+
+ if (argc != 2) {
+ /* each line in the file has the following format
+ * uuid-in-canonical-form path-relative-to-gluster-mount.
+ * Both uuid and relative path are from master mount.
+ */
+ fprintf (stderr, "usage: %s <file-of-paths-to-be-synced>\n",
+ argv[0]);
+ goto out;
+ }
+
+ file = argv[1];
+
+ fp = fopen (file, "r");
+ if (fp == NULL) {
+ fprintf (stderr, "cannot open %s for reading (%s)\n",
+ file, strerror (errno));
+ goto out;
+ }
+
+ while (fgets (line, GLFS_LINE_MAX, fp) != NULL) {
+ tmp = line;
+ path = gfid = line;
+
+ path += UUID_CANONICAL_FORM_LEN + 1;
+
+ while(isspace (*path))
+ path++;
+
+ if ((strlen (line) < GLFS_LINE_MAX) &&
+ (line[strlen (line) - 1] == '\n'))
+ line[strlen (line) - 1] = '\0';
+
+ line[UUID_CANONICAL_FORM_LEN] = '\0';
+
+ tmp = strdup (path);
+ tmp1 = strdup (path);
+ parent_dir = dirname (tmp);
+ bname = basename (tmp1);
+
+ /* gfid + '\0' + bname + '\0' */
+ len = UUID_CANONICAL_FORM_LEN + 1 + strlen (bname) + 1;
+
+ blob = calloc (1, len);
+
+ memcpy (blob, gfid, UUID_CANONICAL_FORM_LEN);
+
+ tmp_blob = blob + UUID_CANONICAL_FORM_LEN + 1;
+
+ memcpy (tmp_blob, bname, strlen (bname));
+
+ ret = setxattr (parent_dir, GF_FUSE_AUX_GFID_HEAL, blob, len,
+ 0);
+ if (ret < 0) {
+ fprintf (stderr, "setxattr on %s/%s failed (%s)\n",
+ parent_dir, bname, strerror (errno));
+ }
+ memset (line, 0, GLFS_LINE_MAX);
+
+ free (blob);
+ free (tmp); free (tmp1);
+ blob = NULL;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
diff --git a/extras/geo-rep/gsync-upgrade.sh b/extras/geo-rep/gsync-upgrade.sh
new file mode 100644
index 000000000..b17948736
--- /dev/null
+++ b/extras/geo-rep/gsync-upgrade.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+#usage: gsync-upgrade.sh <slave-volfile-server:slave-volume> <gfid-file>
+# <path-to-gsync-sync-gfid> <ssh-identity-file>
+#<slave-volfile-server>: a machine on which gluster cli can fetch slave volume info.
+# slave-volfile-server defaults to localhost.
+#
+#<gfid-file>: a file containing paths and their associated gfids
+# on master. The paths are relative to master mount point
+# (not absolute). An example extract of <gfid-file> can be,
+#
+# <extract>
+# 22114455-57c5-46e9-a783-c40f83a72b09 /dir
+# 25772386-3eb8-4550-a802-c3fdc938ca80 /dir/file
+# </extract>
+#
+#<ssh-identity-file>: file from which the identity (private key) for public key authentication is read.
+
+SLAVE_MOUNT='/tmp/glfs_slave'
+
+function SSH()
+{
+ HOST=$1
+ SSHKEY=$2
+
+ shift 2
+
+ ssh -qi $SSHKEY \
+ -oPasswordAuthentication=no \
+ -oStrictHostKeyChecking=no \
+ "$HOST" "$@";
+}
+
+function get_bricks()
+{
+ SSHKEY=$3
+
+ SSH $1 $SSHKEY "gluster volume info $2" | grep -E 'Brick[0-9]+' | sed -e 's/[^:]*:\(.*\)/\1/g'
+}
+
+function cleanup_brick()
+{
+ HOST=$1
+ BRICK=$2
+ SSHKEY=$3
+
+ # TODO: write a C program to receive a list of files and does cleanup on
+ # them instead of spawning a new setfattr process for each file if
+ # performance is bad.
+ SSH -i $SSHKEY $HOST "rm -rf $BRICK/.glusterfs/* && find $BRICK -exec setfattr -x trusted.gfid {} \;"
+}
+
+function cleanup_slave()
+{
+ SSHKEY=$2
+
+ VOLFILE_SERVER=`echo $1 | sed -e 's/\(.*\):.*/\1/'`
+ VOLUME_NAME=`echo $1 | sed -e 's/.*:\(.*\)/\1/'`
+
+ BRICKS=`get_bricks $VOLFILE_SERVER $VOLUME_NAME $SSHKEY`
+
+ for i in $BRICKS; do
+ HOST=`echo $i | sed -e 's/\(.*\):.*/\1/'`
+ BRICK=`echo $i | sed -e 's/.*:\(.*\)/\1/'`
+ cleanup_brick $HOST $BRICK $SSHKEY
+ done
+
+ SSH -i $SSHKEY $VOLFILE_SERVER "gluster --mode=script volume stop $VOLUME_NAME; gluster volume start $VOLUME_NAME";
+
+}
+
+function mount_client()
+{
+ local T; # temporary mount
+ local i; # inode number
+ GFID_FILE=$3
+ SYNC_CMD=$4
+
+ T=$(mktemp -d);
+
+ glusterfs --aux-gfid-mount -s $1 --volfile-id $2 $T;
+
+ i=$(stat -c '%i' $T);
+
+ [ "x$i" = "x1" ] || fatal "could not mount volume $MASTER on $T";
+
+ cd $T;
+
+ $SYNC_CMD $GFID_FILE
+
+ cd -;
+
+ umount -l $T || fatal "could not umount $MASTER from $T";
+
+ rmdir $T || warn "rmdir of $T failed";
+}
+
+function sync_gfids()
+{
+ SLAVE=$1
+ GFID_FILE=$2
+
+ SLAVE_VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'`
+ SLAVE_VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'`
+
+ if [ "x$SLAVE_VOLFILE_SERVER" = "x" ]; then
+ SLAVE_VOLFILE_SERVER="localhost"
+ fi
+
+ mount_client $SLAVE_VOLFILE_SERVER $SLAVE_VOLUME_NAME $GFID_FILE $3
+}
+
+function upgrade()
+{
+ SLAVE=$1
+ GFID_FILE=$2
+ SYNC_CMD=$3
+ SSHKEY=$4
+
+ cleanup_slave $SLAVE $SSHKEY
+ sync_gfids $SLAVE $GFID_FILE $SYNC_CMD
+}
+
+upgrade "$@"
diff --git a/extras/geo-rep/slave-upgrade.sh b/extras/geo-rep/slave-upgrade.sh
new file mode 100644
index 000000000..6198f408a
--- /dev/null
+++ b/extras/geo-rep/slave-upgrade.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+#usage: slave-upgrade.sh <volfile-server:volname> <gfid-file>
+# <path-to-gsync-sync-gfid>
+#<slave-volfile-server>: a machine on which gluster cli can fetch slave volume info.
+# slave-volfile-server defaults to localhost.
+#
+#<gfid-file>: a file containing paths and their associated gfids
+# on master. The paths are relative to master mount point
+# (not absolute). An example extract of <gfid-file> can be,
+#
+# <extract>
+# 22114455-57c5-46e9-a783-c40f83a72b09 /dir
+# 25772386-3eb8-4550-a802-c3fdc938ca80 /dir/file
+# </extract>
+
+function get_bricks()
+{
+ gluster volume info $1 | grep -E 'Brick[0-9]+' | sed -e 's/[^:]*:\(.*\)/\1/g'
+}
+
+function cleanup_brick()
+{
+ HOST=$1
+ BRICK=$2
+
+ # TODO: write a C program to receive a list of files and does cleanup on
+ # them instead of spawning a new setfattr process for each file if
+ # performance is bad.
+ ssh $HOST "rm -rf $BRICK/.glusterfs/* && find $BRICK -exec setfattr -x trusted.gfid {} \; 2>/dev/null"
+}
+
+function cleanup_slave()
+{
+ VOLUME_NAME=`echo $1 | sed -e 's/.*:\(.*\)/\1/'`
+
+ BRICKS=`get_bricks $VOLUME_NAME`
+
+ for i in $BRICKS; do
+ HOST=`echo $i | sed -e 's/\(.*\):.*/\1/'`
+ BRICK=`echo $i | sed -e 's/.*:\(.*\)/\1/'`
+ cleanup_brick $HOST $BRICK
+ done
+
+ # Now restart the volume
+ gluster --mode=script volume stop $VOLUME_NAME;
+ gluster volume start $VOLUME_NAME;
+}
+
+function mount_client()
+{
+ local T; # temporary mount
+ local i; # inode number
+
+ VOLUME_NAME=$2;
+ GFID_FILE=$3
+ SYNC_CMD=$4
+
+ T=$(mktemp -d);
+
+ glusterfs --aux-gfid-mount -s $1 --volfile-id $VOLUME_NAME $T;
+
+ i=$(stat -c '%i' $T);
+
+ cd $T;
+
+ $SYNC_CMD $GFID_FILE
+
+ cd -;
+
+ umount $T || fatal "could not umount $MASTER from $T";
+
+ rmdir $T || warn "rmdir of $T failed";
+}
+
+function sync_gfids()
+{
+ SLAVE=$1
+ GFID_FILE=$2
+ SYNC_CMD=$3
+
+ SLAVE_VOLFILE_SERVER=`echo $SLAVE | sed -e 's/\(.*\):.*/\1/'`
+ SLAVE_VOLUME_NAME=`echo $SLAVE | sed -e 's/.*:\(.*\)/\1/'`
+
+ if [ "x$SLAVE_VOLFILE_SERVER" = "x" ]; then
+ SLAVE_VOLFILE_SERVER="localhost"
+ fi
+
+ mount_client $SLAVE_VOLFILE_SERVER $SLAVE_VOLUME_NAME $GFID_FILE $SYNC_CMD
+}
+
+function upgrade()
+{
+ SLAVE=$1
+ GFID_FILE=$2
+ SYNC_CMD=$3
+
+ cleanup_slave $SLAVE
+
+ sync_gfids $SLAVE $GFID_FILE $SYNC_CMD
+}
+
+upgrade "$@"
diff --git a/extras/gluster-rsyslog-5.8.conf b/extras/gluster-rsyslog-5.8.conf
new file mode 100644
index 000000000..2519999bc
--- /dev/null
+++ b/extras/gluster-rsyslog-5.8.conf
@@ -0,0 +1,51 @@
+##### gluster.conf #####
+
+#
+## If you want to log every message to the log file instead of
+## intelligently suppressing repeated messages, set off to
+## RepeatedMsgReduction. This change requires rsyslog restart
+## (eg. run 'service rsyslog restart')
+#
+#$RepeatedMsgReduction off
+$RepeatedMsgReduction on
+
+#
+## The mmcount module provides the capability to count log messages by
+## severity or json property of given app-name. The count value is added
+## into the log message as json property named '$msgid'
+#
+$ModLoad mmcount
+$mmcountKey gf_code # start counting value of gf_code
+
+$template Glusterfsd_dynLogFile,"/var/log/glusterfs/bricks/%app-name%.log"
+$template Gluster_dynLogFile,"/var/log/glusterfs/%app-name%.log"
+
+$template GLFS_Template,"%msgid%/%syslogfacility-text:::uppercase%/%syslogseverity-text:::uppercase% [%TIMESTAMP:::date-rfc3339%] %msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
+
+#
+## Pass logs to mmcount if app-name is 'gluster'
+#
+if $app-name contains 'gluster' then :mmcount:
+
+if $app-name contains 'glusterfsd' then ?Glusterfsd_dynLogFile;GLFS_Template
+if $app-name contains 'gluster' and not ( $app-name contains 'glusterfsd' ) then ?Gluster_dynLogFile;GLFS_Template
+
+#
+## Sample configuration to send a email alert for every 50th mmcount
+#
+#$ModLoad ommail
+#$ActionMailSMTPServer smtp.example.com
+#$ActionMailFrom rsyslog@example.com
+#$ActionMailTo glusteradmin@example.com
+#$template mailSubject,"50th message of gf_code=9999 on %hostname%"
+#$template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'"
+#$ActionMailSubject mailSubject
+#$ActionExecOnlyOnceEveryInterval 30
+#if $app-name == 'glusterfsd' and $msgid != 0 and $msgid % 50 == 0 \
+#then :ommail:;RSYSLOG_SyslogProtocol23Format
+#
+
+#
+## discard logs where app-name is 'gluster' as we processed already
+#
+if $app-name contains 'gluster' then ~
diff --git a/extras/gluster-rsyslog-7.2.conf b/extras/gluster-rsyslog-7.2.conf
new file mode 100644
index 000000000..8b2841543
--- /dev/null
+++ b/extras/gluster-rsyslog-7.2.conf
@@ -0,0 +1,76 @@
+##### gluster.conf #####
+#
+## If you want to log every message to the log file instead of
+## intelligently suppressing repeated messages, set off to
+## RepeatedMsgReduction. This change requires rsyslog restart
+## (eg. run 'service rsyslog restart')
+#
+#$RepeatedMsgReduction off
+$RepeatedMsgReduction on
+
+$ModLoad mmjsonparse
+*.* :mmjsonparse:
+
+#
+## The mmcount module provides the capability to count log messages by
+## severity or json property of given app-name. The count value is added
+## into the log message as json property named 'mmcount'
+##
+## More info at http://www.rsyslog.com/doc/mmcount.html
+#
+#module(load="mmcount")
+#action(type="mmcount" appname="glusterd" key="!gf_code") # count each value of gf_code of appname glusterd
+#action(type="mmcount" appname="glusterfsd" key="!gf_code") # count each value of gf_code of appname glusterfsd
+#action(type="mmcount" appname="glusterfs" key="!gf_code") # count each value of gf_code of appname glusterfs
+
+template (name="Glusterfsd_dynLogFile" type="string" string="/var/log/glusterfs/bricks/%app-name%.log")
+template (name="Gluster_dynLogFile" type="string" string="/var/log/glusterfs/%app-name%.log")
+
+template(name="GLFS_template" type="list") {
+ property(name="$!mmcount")
+ constant(value="/")
+ property(name="syslogfacility-text" caseConversion="upper")
+ constant(value="/")
+ property(name="syslogseverity-text" caseConversion="upper")
+ constant(value=" ")
+ constant(value="[")
+ property(name="timereported" dateFormat="rfc3339")
+ constant(value="] ")
+ constant(value="[")
+ property(name="$!gf_code")
+ constant(value="] ")
+ constant(value="[")
+ property(name="$!gf_message")
+ constant(value="] ")
+ property(name="$!msg")
+ constant(value="\n")
+}
+
+if $app-name contains 'glusterfsd' then {
+ action(type="omfile"
+ DynaFile="Glusterfsd_dynLogFile"
+ Template="GLFS_template")
+ stop
+}
+
+if $app-name contains 'gluster' then {
+ action(type="omfile"
+ DynaFile="Gluster_dynLogFile"
+ Template="GLFS_template")
+ stop
+}
+
+#
+## send email for every 50th mmcount
+#$ModLoad ommail
+#if $app-name == 'glusterfsd' and $!mmcount <> 0 and $!mmcount % 50 == 0 then {
+# $ActionMailSMTPServer smtp.example.com
+# $ActionMailFrom rsyslog@example.com
+# $ActionMailTo glusteradmin@example.com
+# $template mailSubject,"50th message of gf_code=9999 on %hostname%"
+# $template mailBody,"RSYSLOG Alert\r\nmsg='%msg%'"
+# $ActionMailSubject mailSubject
+# $ActionExecOnlyOnceEveryInterval 30
+# :ommail:;RSYSLOG_SyslogProtocol23Format
+#}
+#
diff --git a/extras/glusterd-sysconfig b/extras/glusterd-sysconfig
new file mode 100644
index 000000000..8237c5711
--- /dev/null
+++ b/extras/glusterd-sysconfig
@@ -0,0 +1,6 @@
+## Set custom log file and log level (bellow are defaults)
+# LOG_FILE='/var/log/glusterfs/glusterd.log'
+# LOG_LEVEL='INFO'
+
+## Set custom options for glusterd
+# GLUSTERD_OPTIONS=''
diff --git a/extras/glusterd.vol b/extras/glusterd.vol
new file mode 100644
index 000000000..9bac52ab7
--- /dev/null
+++ b/extras/glusterd.vol
@@ -0,0 +1,9 @@
+volume management
+ type mgmt/glusterd
+ option working-directory /var/lib/glusterd
+ option transport-type socket,rdma
+ option transport.socket.keepalive-time 10
+ option transport.socket.keepalive-interval 2
+ option transport.socket.read-fail-log off
+# option base-port 49152
+end-volume
diff --git a/extras/glusterfs-georep-logrotate b/extras/glusterfs-georep-logrotate
new file mode 100644
index 000000000..6a69ab1e3
--- /dev/null
+++ b/extras/glusterfs-georep-logrotate
@@ -0,0 +1,18 @@
+
+rotate 52
+missingok
+
+compress
+delaycompress
+notifempty
+
+/var/log/glusterfs/geo-replication/*/*.log {
+}
+
+
+/var/log/glusterfs/geo-replication-slaves/*.log {
+}
+
+
+/var/log/glusterfs/geo-replication-slaves/*/*.log {
+}
diff --git a/extras/glusterfs-logrotate b/extras/glusterfs-logrotate
new file mode 100644
index 000000000..373ec2e0b
--- /dev/null
+++ b/extras/glusterfs-logrotate
@@ -0,0 +1,27 @@
+# perform the log rotate every week
+weekly
+# keep the backup of 52 weeks
+rotate 52
+missingok
+
+# compress the logs, but from the .2 onwards
+compress
+delaycompress
+notifempty
+
+# Rotate client logs
+/var/log/glusterfs/*.log {
+ sharedscripts
+ postrotate
+ /usr/bin/killall -HUP glusterfs > /dev/null 2>&1 || true
+ /usr/bin/killall -HUP glusterd > /dev/null 2>&1 || true
+ endscript
+}
+
+# Rotate server logs
+/var/log/glusterfs/bricks/*.log {
+ sharedscripts
+ postrotate
+ /usr/bin/killall -HUP glusterfsd > /dev/null 2>&1 || true
+ endscript
+}
diff --git a/extras/glusterfs-mode.el b/extras/glusterfs-mode.el
index e65fbf460..d4f6dc568 100644
--- a/extras/glusterfs-mode.el
+++ b/extras/glusterfs-mode.el
@@ -1,4 +1,4 @@
-;;; Copyright (C) 2007, 2008 Z RESEARCH Inc. <http://www.zresearch.com>
+;;; Copyright (C) 2007-2011 Gluster Inc. <http://www.gluster.com>
;;;
;;; 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
diff --git a/extras/glusterfs.vim b/extras/glusterfs.vim
index 42fa6b573..899cc6551 100644
--- a/extras/glusterfs.vim
+++ b/extras/glusterfs.vim
@@ -1,20 +1,11 @@
" glusterfs.vim: GNU Vim Syntax file for GlusterFS .vol specification
-" Copyright (C) 2007-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
-" This file is part of GlusterFS.
+" Copyright (c) 2007777777Red Hat, Inc. <http://www.redhat.com>
+" 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
-" <http://www.gnu.org/licenses/>.
+" This file is licensed to you under your choice of the GNU Lesser
+" General Public License, version 3 or any later version (LGPLv3 or
+" later), or the GNU General Public License, version 2 (GPLv2), in all
+" cases as published by the Free Software Foundation.
"
" Last Modified: Wed Aug 1 00:47:10 IST 2007
" Version: 0.8
diff --git a/extras/gnfs-loganalyse.py b/extras/gnfs-loganalyse.py
new file mode 100644
index 000000000..71e79b6be
--- /dev/null
+++ b/extras/gnfs-loganalyse.py
@@ -0,0 +1,260 @@
+#!/bin/python
+"""
+ Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+
+"""
+
+import os
+import string
+import sys
+
+
+class NFSRequest:
+ def requestIsEntryOp (self):
+ op = self.op
+ if op == "CREATE" or op == "LOOKUP" or op == "REMOVE" or op == "LINK" or op == "RENAME" or op == "MKDIR" or op == "RMDIR" or op == "SYMLINK" or op == "MKNOD":
+ return 1
+ else:
+ return 0
+
+ def __init__ (self, logline, linecount):
+ self.calllinecount = 0
+ self.xid = ""
+ self.op = ""
+ self.opdata = ""
+ self.replydata = ""
+ self.replylinecount = 0
+ self.timestamp = ""
+ self.entryname = ""
+ self.gfid = ""
+ self.replygfid = ""
+
+ tokens = logline.strip ().split (" ")
+ self.timestamp = tokens[0] + " " + tokens[1]
+ if "XID:" not in tokens:
+ return None
+
+ if "args:" not in tokens:
+ return None
+
+ self.calllinecount = linecount
+
+ xididx = tokens.index ("XID:")
+ self.xid = tokens [xididx+1].strip(",")
+
+ opidx = tokens.index ("args:")
+ self.op = tokens [opidx-1].strip (":")
+ self.opdata = " ".join(tokens [opidx+1:])
+ if self.requestIsEntryOp ():
+ nameidx = tokens.index ("name:")
+ self.entryname = tokens[nameidx + 1].strip (",")
+ gfididx = tokens.index ("gfid")
+ self.gfid = tokens[gfididx +1].strip(",")
+
+
+ def getXID (self):
+ return self.xid
+
+ def setReply (self, logline, linecount):
+ tokens = logline.strip ().split (" ")
+ timestamp = tokens[0] + " " + tokens[1]
+ statidx = tokens.index ("NFS:")
+ self.replydata = " TimeStamp: " + timestamp + " " + " ".join (tokens [statidx+1:])
+ self.replylinecount = linecount
+ if "gfid" in tokens:
+ gfididx = tokens.index ("gfid")
+ self.replygfid = tokens [gfididx + 1].strip(",")
+
+ def dump (self):
+ print "ReqLine: " + str(self.calllinecount) + " TimeStamp: " + self.timestamp + ", XID: " + self.xid + " " + self.op + " ARGS: " + self.opdata + " RepLine: " + str(self.replylinecount) + " " + self.replydata
+
+class NFSLogAnalyzer:
+
+ def __init__ (self, optn, trackfilename, tracknamefh, stats):
+ self.stats = stats
+ self.xid_request_map = {}
+ self.orphan_replies = {}
+ self.rqlist = []
+ self.CALL = 1
+ self.REPLY = 2
+ self.optn = optn
+ self.trackfilename = trackfilename
+ self.tracknamefh = tracknamefh
+ self.trackedfilehandles = []
+
+ def handle_call_line (self, logline, linecount):
+ newreq = NFSRequest (logline, linecount)
+ xid = newreq.getXID ()
+ if (self.optn == SYNTHESIZE):
+ self.xid_request_map [xid] = newreq
+ self.rqlist.append(newreq)
+ elif self.optn == TRACKFILENAME:
+ if newreq.requestIsEntryOp():
+ if newreq.entryname == self.trackfilename:
+ self.xid_request_map [xid] = newreq
+ self.rqlist.append(newreq)
+ else:
+ del newreq
+ elif self.tracknamefh == ENABLE_TRACKNAME_FH:
+ if len (self.trackedfilehandles) > 0:
+ if newreq.gfid in self.trackedfilehandles:
+ self.xid_request_map [xid] = newreq
+ self.rqlist.append(newreq)
+ else:
+ del newreq
+ else:
+ del newreq
+ else:
+ del newreq
+
+
+ def handle_reply_line (self, logline, linecount):
+ tokens = logline.strip ().split (" ")
+
+ xididx = tokens.index ("XID:")
+ xid = tokens [xididx + 1].strip(",")
+ if xid not in self.xid_request_map.keys ():
+ self.orphan_replies [xid] = logline
+ else:
+ rq = self.xid_request_map [xid]
+ rq.setReply (logline, linecount)
+ if rq.requestIsEntryOp() and rq.entryname == self.trackfilename:
+ self.trackedfilehandles.append (rq.replygfid)
+
+ def analyzeLine (self, logline, linecount):
+ tokens = logline.strip ().split (" ")
+ msgtype = 0
+
+ if "XID:" not in tokens:
+ return
+
+ if "args:" in tokens:
+ msgtype = self.CALL
+ elif "NFS:" in tokens:
+ msgtype = self.REPLY
+
+ if msgtype == self.CALL:
+ self.handle_call_line (logline, linecount)
+ elif msgtype == self.REPLY:
+ self.handle_reply_line (logline, linecount)
+
+ def getStats (self):
+ if self.stats == 0:
+ return
+ rcount = len (self.xid_request_map.keys ())
+ orphancount = len (self.orphan_replies.keys ())
+ print "Requests: " + str(rcount) + ", Orphans: " + str(orphancount)
+
+ def dump (self):
+ self.getStats ()
+ for rq in self.rqlist:
+ rq.dump ()
+ del rq
+
+ self.rqlist = []
+ self.orphan_replies = {}
+ self.xid_request_map = {}
+
+
+linecount = 0
+
+SYNTHESIZE = 1
+TRACKFILENAME = 2
+
+ENABLESTATS = 1
+DISABLESTATS = 0
+
+ENABLE_TRACKNAME_FH = 1
+DISABLE_TRACKNAME_FH = 0
+
+progmsgcount = 1000
+dumpinterval = 200000
+operation = SYNTHESIZE
+stats = ENABLESTATS
+tracknamefh = DISABLE_TRACKNAME_FH
+trackfilename = ""
+
+"""
+Print the progress of the analysing operations every X number of lines read from
+the logs, where X is the argument provided to this option.
+
+Use this to print a status message every say 10000 lines processed or 100000
+lines processed to know how much longer the processing will go on for.
+
+
+USAGE: --progress <NUMLINES>
+"""
+if "--progress" in sys.argv:
+ idx = sys.argv.index ("--progress")
+ progmsgcount = int(sys.argv[idx+1])
+
+"""
+The replies for a NFS request can be separated by hundreds and even thousands
+of other NFS requests and replies. These can be spread over many hundreds and
+thousands of log lines. This script maintains a memory dict to map each request
+to its reply using the XID. Because this is in-core, there is a limit to the
+number of entries in the dict. At regular intervals, it dumps the mapped
+requests and the replies into the stdout. The requests whose replies were not
+found at the point of dumping are left as orphans, i.e. without info about the
+replies. Use this option to tune the number of lines to maximize the number of
+requests whose replies are found while balancing the dict size with memory
+on the machine. The default works fine for most cases.
+
+USAGE: --dump <NUMLINES>
+"""
+if "--dump" in sys.argv:
+ idx = sys.argv.index ("--dump")
+ dumpinterval = int(sys.argv[idx+1])
+
+"""
+The default operation of the script is to output all the requests mapped to
+their replies in a single line. This operation mode can be changed by this
+argument. It is used to print only those operations that were performed on the
+filename given as the argument to this option. Only those entry operations are
+printed which contain this filename.
+
+USAGE: --trackfilename <filename>
+"""
+if "--trackfilename" in sys.argv:
+ idx = sys.argv.index ("--trackfilename")
+ trackfilename = sys.argv[idx + 1]
+ operation = TRACKFILENAME
+
+"""
+At every dump interval, some stats are printed about the dumped lines.
+Use this option to disable printing that to avoid cluttering the
+output.
+"""
+if "--nostats" in sys.argv:
+ stats = DISABLESTATS
+
+"""
+While tracking a file using --trackfilename, we're only given those
+operations which contain the filename. This excludes a large number
+of operations which operate on that file using its filehandle instead of
+the filename. This option enables outputting those operations also. It
+tracks every single file handle that was ever seen in the log for a given
+filename.
+
+USAGE: --trackfilename
+"""
+if "--tracknamefh" in sys.argv:
+ tracknamefh = ENABLE_TRACKNAME_FH
+
+la = NFSLogAnalyzer (operation, trackfilename, tracknamefh, stats)
+
+for line in sys.stdin:
+ linecount = linecount + 1
+ if linecount % dumpinterval == 0:
+ sys.stderr.write ("Dumping data..\n")
+ la.dump ()
+
+ if linecount % progmsgcount == 0:
+ sys.stderr.write ("Integrating line: "+ str(linecount) + "\n")
+ la.analyzeLine (line, linecount)
diff --git a/extras/group-virt.example b/extras/group-virt.example
new file mode 100644
index 000000000..7dc777f2d
--- /dev/null
+++ b/extras/group-virt.example
@@ -0,0 +1,6 @@
+quick-read=off
+read-ahead=off
+io-cache=off
+stat-prefetch=off
+eager-lock=enable
+remote-dio=enable
diff --git a/extras/hook-scripts/Makefile.am b/extras/hook-scripts/Makefile.am
new file mode 100644
index 000000000..f6bded20c
--- /dev/null
+++ b/extras/hook-scripts/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = S29CTDBsetup.sh S30samba-start.sh S30samba-stop.sh S30samba-set.sh S56glusterd-geo-rep-create-post.sh
diff --git a/extras/hook-scripts/S29CTDBsetup.sh b/extras/hook-scripts/S29CTDBsetup.sh
new file mode 100644
index 000000000..e256be1f3
--- /dev/null
+++ b/extras/hook-scripts/S29CTDBsetup.sh
@@ -0,0 +1,69 @@
+#! /bin/bash
+#non-portable - RHS-2.0 only
+# - The script mounts the 'meta-vol' on start 'event' on a known
+# directory (eg. /gluster/lock)
+# - Adds the necessary configuration changes for ctdb in smb.conf and
+# restarts smb service.
+# - P.S: There are other 'tasks' that need to be done outside this script
+# to get CTDB based failover up and running.
+
+SMB_CONF=/etc/samba/smb.conf
+
+CTDB_MNT=/gluster/lock
+PROGNAME="ctdb"
+OPTSPEC="volname:"
+VOL=
+# $META is the volume that will be used by CTDB as a shared filesystem.
+# It is not desirable to use this volume for storing 'data' as well.
+# META is set to 'all' (viz. a keyword and hence not a legal volume name)
+# to prevent the script from running for volumes it was not intended.
+# User needs to set META to the volume that serves CTDB lockfile.
+META="all"
+
+function sighup_samba () {
+ pid=`cat /var/run/smbd.pid`
+ if [ $pid != " " ]
+ then
+ kill -HUP $pid;
+ else
+ /etc/init.d/smb start
+ fi
+}
+
+function parse_args () {
+ ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@)
+ eval set -- "$ARGS"
+
+ while true; do
+ case $1 in
+ --volname)
+ shift
+ VOL=$1
+ ;;
+
+ *)
+ shift
+ break
+ ;;
+
+ esac
+
+ shift
+ done
+}
+
+function add_glusterfs_ctdb_options () {
+ PAT="Share Definitions"
+ GLUSTER_CTDB_CONFIG="# ctdb config for glusterfs\n\tclustering = yes\n\tidmap backend = tdb2\n\tprivate dir = "$CTDB_MNT"\n"
+
+ sed -i /"$PAT"/i\ "$GLUSTER_CTDB_CONFIG" $SMB_CONF
+}
+
+parse_args $@
+if [ "$META" = "$VOL" ]
+then
+ add_glusterfs_ctdb_options
+ sighup_samba
+ mount -t glusterfs `hostname`:$VOL "$CTDB_MNT" &
+fi
+
diff --git a/extras/hook-scripts/S30samba-set.sh b/extras/hook-scripts/S30samba-set.sh
new file mode 100755
index 000000000..6b11f5a4f
--- /dev/null
+++ b/extras/hook-scripts/S30samba-set.sh
@@ -0,0 +1,109 @@
+#!/bin/bash
+
+#Need to be copied to hooks/<HOOKS_VER>/set/post/
+
+#TODO: All gluster and samba paths are assumed for fedora like systems.
+#Some efforts are required to make it work on other distros.
+
+#The preferred way of creating a smb share of a gluster volume has changed.
+#The old method was to create a fuse mount of the volume and share the mount
+#point through samba.
+#
+#New method eliminates the requirement of fuse mount and changes in fstab.
+#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume.
+#
+#This hook script enables user to enable or disable smb share by volume set
+#option. Keys "user.cifs" and "user.smb" both are valid, but user.smb is
+#preferred.
+
+
+PROGNAME="Ssamba-set"
+OPTSPEC="volname:"
+VOL=
+
+enable_smb=""
+
+function parse_args () {
+ ARGS=$(getopt -l $OPTSPEC -o "o" -name $PROGNAME $@)
+ eval set -- "$ARGS"
+
+ while true; do
+ case $1 in
+ --volname)
+ shift
+ VOL=$1
+ ;;
+ *)
+ shift
+ for pair in $@; do
+ read key value < <(echo "$pair" | tr "=" " ")
+ case "$key" in
+ "user.cifs")
+ enable_smb=$value
+ ;;
+ "user.smb")
+ enable_smb=$value
+ ;;
+ *)
+ ;;
+ esac
+ done
+
+ shift
+ break
+ ;;
+ esac
+ shift
+ done
+}
+
+function add_samba_share () {
+ volname=$1
+ STRING="\n[gluster-$volname]\n"
+ STRING+="comment = For samba share of volume $volname\n"
+ STRING+="vfs objects = glusterfs\n"
+ STRING+="glusterfs:volume = $volname\n"
+ STRING+="glusterfs:logfile = /var/log/samba/glusterfs-$volname.%%M.log\n"
+ STRING+="glusterfs:loglevel = 7\n"
+ STRING+="path = /\n"
+ STRING+="read only = no\n"
+ STRING+="guest ok = yes\n"
+ printf "$STRING" >> /etc/samba/smb.conf
+}
+
+function sighup_samba () {
+ pid=`cat /var/run/smbd.pid`
+ if [ "x$pid" != "x" ]
+ then
+ kill -HUP "$pid";
+ else
+ /etc/init.d/smb start
+ fi
+}
+
+function del_samba_share () {
+ volname=$1
+ sed -i "/\[gluster-$volname\]/,/^$/d" /etc/samba/smb.conf
+}
+
+function is_volume_started () {
+ volname=$1
+ echo "$(grep status /var/lib/glusterd/vols/"$volname"/info |\
+ cut -d"=" -f2)"
+}
+
+parse_args $@
+if [ "0" = $(is_volume_started "$VOL") ]; then
+ exit 0
+fi
+
+if [ "$enable_smb" = "enable" ]; then
+ if ! grep --quiet "\[gluster-$VOL\]" /etc/samba/smb.conf ; then
+ add_samba_share $VOL
+ sighup_samba
+ fi
+
+elif [ "$enable_smb" = "disable" ]; then
+ del_samba_share $VOL
+ sighup_samba
+fi
diff --git a/extras/hook-scripts/S30samba-start.sh b/extras/hook-scripts/S30samba-start.sh
new file mode 100755
index 000000000..34fde0ef8
--- /dev/null
+++ b/extras/hook-scripts/S30samba-start.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+#Need to be copied to hooks/<HOOKS_VER>/start/post
+
+#TODO: All gluster and samba paths are assumed for fedora like systems.
+#Some efforts are required to make it work on other distros.
+
+#The preferred way of creating a smb share of a gluster volume has changed.
+#The old method was to create a fuse mount of the volume and share the mount
+#point through samba.
+#
+#New method eliminates the requirement of fuse mount and changes in fstab.
+#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume.
+#
+#This hook script automagically creates shares for volume on every volume start
+#event by adding the entries in smb.conf file and sending SIGHUP to samba.
+#
+#In smb.conf:
+#glusterfs vfs plugin has to be specified as required vfs object.
+#Path value is relative to the root of gluster volume;"/" signifies complete
+#volume.
+
+PROGNAME="Ssamba-start"
+OPTSPEC="volname:"
+VOL=
+CONFIGFILE=
+LOGFILEBASE=
+PIDDIR=
+
+function parse_args () {
+ ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@)
+ eval set -- "$ARGS"
+
+ while true; do
+ case $1 in
+ --volname)
+ shift
+ VOL=$1
+ ;;
+ *)
+ shift
+ break
+ ;;
+ esac
+ shift
+ done
+}
+
+function find_config_info () {
+ cmdout=`smbd -b | grep smb.conf`
+ if [ $? -ne 0 ];then
+ echo "Samba is not installed"
+ exit 1
+ fi
+ CONFIGFILE=`echo $cmdout | awk {'print $2'}`
+ PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}`
+ LOGFILEBASE=`smbd -b | grep 'LOGFILEBASE' | awk '{print $2}'`
+}
+
+function add_samba_share () {
+ volname=$1
+ STRING="\n[gluster-$volname]\n"
+ STRING+="comment = For samba share of volume $volname\n"
+ STRING+="vfs objects = glusterfs\n"
+ STRING+="glusterfs:volume = $volname\n"
+ STRING+="glusterfs:logfile = $LOGFILEBASE/glusterfs-$volname.%%M.log\n"
+ STRING+="glusterfs:loglevel = 7\n"
+ STRING+="path = /\n"
+ STRING+="read only = no\n"
+ STRING+="guest ok = yes\n"
+ printf "$STRING" >> ${CONFIGFILE}
+}
+
+function sighup_samba () {
+ pid=`cat ${PIDDIR}/smbd.pid`
+ if [ "x$pid" != "x" ]
+ then
+ kill -HUP "$pid";
+ else
+ /etc/init.d/smb condrestart
+ fi
+}
+
+function get_smb () {
+ volname=$1
+ uservalue=
+
+ usercifsvalue=$(grep user.cifs /var/lib/glusterd/vols/"$volname"/info |\
+ cut -d"=" -f2)
+ usersmbvalue=$(grep user.smb /var/lib/glusterd/vols/"$volname"/info |\
+ cut -d"=" -f2)
+
+ if [[ $usercifsvalue = "disable" || $usersmbvalue = "disable" ]]; then
+ uservalue="disable"
+ fi
+ echo "$uservalue"
+}
+
+parse_args $@
+if [ $(get_smb "$VOL") = "disable" ]; then
+ exit 0
+fi
+
+#Find smb.conf, smbd pid directory and smbd logfile path
+find_config_info
+
+if ! grep --quiet "\[gluster-$VOL\]" ${CONFIGFILE} ; then
+ add_samba_share $VOL
+ sighup_samba
+fi
diff --git a/extras/hook-scripts/S30samba-stop.sh b/extras/hook-scripts/S30samba-stop.sh
new file mode 100755
index 000000000..8950eea43
--- /dev/null
+++ b/extras/hook-scripts/S30samba-stop.sh
@@ -0,0 +1,71 @@
+#! /bin/bash
+
+#Need to be copied to hooks/<HOOKS_VER>/stop/pre
+
+#TODO: All gluster and samba paths are assumed for fedora like systems.
+#Some efforts are required to make it work on other distros.
+
+#The preferred way of creating a smb share of a gluster volume has changed.
+#The old method was to create a fuse mount of the volume and share the mount
+#point through samba.
+#
+#New method eliminates the requirement of fuse mount and changes in fstab.
+#glusterfs_vfs plugin for samba makes call to libgfapi to access the volume.
+#
+#This hook script automagically removes shares for volume on every volume stop
+#event by removing the volume related entries(if any) in smb.conf file.
+
+PROGNAME="Ssamba-stop"
+OPTSPEC="volname:"
+VOL=
+CONFIGFILE=
+PIDDIR=
+
+function parse_args () {
+ ARGS=$(getopt -l $OPTSPEC -name $PROGNAME $@)
+ eval set -- "$ARGS"
+
+ while true; do
+ case $1 in
+ --volname)
+ shift
+ VOL=$1
+ ;;
+ *)
+ shift
+ break
+ ;;
+ esac
+ shift
+ done
+}
+
+function find_config_info () {
+ cmdout=`smbd -b | grep smb.conf`
+ if [ $? -ne 0 ];then
+ echo "Samba is not installed"
+ exit 1
+ fi
+ CONFIGFILE=`echo $cmdout | awk {'print $2'}`
+ PIDDIR=`smbd -b | grep PIDDIR | awk {'print $2'}`
+}
+
+function del_samba_share () {
+ volname=$1
+ sed -i "/\[gluster-$volname\]/,/^$/d" ${CONFIGFILE}
+}
+
+function sighup_samba () {
+ pid=`cat ${PIDDIR}/smbd.pid`
+ if [ "x$pid" != "x" ]
+ then
+ kill -HUP $pid;
+ else
+ /etc/init.d/smb condrestart
+ fi
+}
+
+parse_args $@
+find_config_info
+del_samba_share $VOL
+sighup_samba
diff --git a/extras/hook-scripts/S40ufo-stop.py b/extras/hook-scripts/S40ufo-stop.py
new file mode 100755
index 000000000..107f19683
--- /dev/null
+++ b/extras/hook-scripts/S40ufo-stop.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import os
+from optparse import OptionParser
+
+if __name__ == '__main__':
+ # check if swift is installed
+ try:
+ from gluster.swift.common.Glusterfs import get_mnt_point, unmount
+ except ImportError:
+ import sys
+ sys.exit("Openstack Swift does not appear to be installed properly");
+
+ op = OptionParser(usage="%prog [options...]")
+ op.add_option('--volname', dest='vol', type=str)
+ op.add_option('--last', dest='last', type=str)
+ (opts, args) = op.parse_args()
+
+
+ mnt_point = get_mnt_point(opts.vol)
+ if mnt_point:
+ unmount(mnt_point)
+ else:
+ sys.exit("get_mnt_point returned none for mount point")
diff --git a/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh
new file mode 100755
index 000000000..1369c22fc
--- /dev/null
+++ b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+key_val_pair1=`echo $2 | cut -d ' ' -f 1`
+key_val_pair2=`echo $2 | cut -d ' ' -f 2`
+key_val_pair3=`echo $2 | cut -d ' ' -f 3`
+
+key=`echo $key_val_pair1 | cut -d '=' -f 1`
+val=`echo $key_val_pair1 | cut -d '=' -f 2`
+if [ "$key" != "is_push_pem" ]; then
+ exit;
+fi
+if [ "$val" != '1' ]; then
+ exit;
+fi
+
+key=`echo $key_val_pair2 | cut -d '=' -f 1`
+val=`echo $key_val_pair2 | cut -d '=' -f 2`
+if [ "$key" != "pub_file" ]; then
+ exit;
+fi
+if [ "$val" == "" ]; then
+ exit;
+fi
+pub_file=`echo $val`
+pub_file_tmp=`echo $val`_tmp
+
+key=`echo $key_val_pair3 | cut -d '=' -f 1`
+val=`echo $key_val_pair3 | cut -d '=' -f 2`
+if [ "$key" != "slave_ip" ]; then
+ exit;
+fi
+if [ "$val" == "" ]; then
+ exit;
+fi
+slave_ip=`echo $val`
+
+if [ -f $pub_file ]; then
+ scp $pub_file $slave_ip:$pub_file_tmp
+ ssh $slave_ip "mv $pub_file_tmp $pub_file"
+ ssh $slave_ip "gluster system:: copy file /geo-replication/common_secret.pem.pub > /dev/null"
+ ssh $slave_ip "gluster system:: execute add_secret_pub > /dev/null"
+fi
diff --git a/extras/init.d/Makefile.am b/extras/init.d/Makefile.am
index 7d8deb74f..38898fddd 100644
--- a/extras/init.d/Makefile.am
+++ b/extras/init.d/Makefile.am
@@ -1,17 +1,22 @@
-EXTRA_DIST = glusterfsd-Debian glusterfsd-Redhat glusterfsd-SuSE glusterfs-server.plist
+EXTRA_DIST = glusterd-Debian glusterd-Redhat glusterd-SuSE glusterd.plist rhel5-load-fuse.modules
CLEANFILES =
-initdir = /etc/init.d
+INIT_DIR = @initdir@
+SYSTEMD_DIR = @systemddir@
+LAUNCHD_DIR = @launchddir@
$(GF_DISTRIBUTION):
- $(mkdir_p) $(DESTDIR)$(initdir)
- $(INSTALL_PROGRAM) $(top_srcdir)/extras/init.d/glusterfsd-$(GF_DISTRIBUTION) $(DESTDIR)$(initdir)/glusterfsd
+ @if [ ! -d $(SYSTEMD_DIR) ]; then \
+ $(mkdir_p) $(DESTDIR)$(INIT_DIR); \
+ $(INSTALL_PROGRAM) glusterd-$(GF_DISTRIBUTION) $(DESTDIR)$(INIT_DIR)/glusterd; \
+ fi
install-exec-local: $(GF_DISTRIBUTION)
install-data-local:
if GF_DARWIN_HOST_OS
- cp glusterfs-server.plist /Library/LaunchDaemons/com.zresearch.glusterfs.plist
+ $(mkdir_p) $(DESTDIR)$(LAUNCHD_DIR)
+ $(INSTALL_PROGRAM) glusterd.plist $(DESTDIR)$(LAUNCHD_DIR)/com.gluster.glusterd.plist
endif
diff --git a/extras/init.d/glusterfsd-Debian b/extras/init.d/glusterd-Debian.in
index dcd3e0c50..918f8592c 100755
--- a/extras/init.d/glusterfsd-Debian
+++ b/extras/init.d/glusterd-Debian.in
@@ -1,24 +1,23 @@
#!/bin/sh
### BEGIN INIT INFO
-# Provides: glusterfsd
+# Provides: glusterd
# 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
+# Short-Description: Gluster File System service for volume management
+# Description: Gluster File System service for volume management
### END INIT INFO
# Author: Chris AtLee <chris@atlee.ca>
# Patched by: Matthias Albert < matthias@linux4experts.de>
PATH=/sbin:/usr/sbin:/bin:/usr/bin
-NAME=glusterfsd
+NAME=glusterd
SCRIPTNAME=/etc/init.d/$NAME
-DAEMON=/usr/sbin/$NAME
+DAEMON=@prefix@/sbin/$NAME
PIDFILE=/var/run/$NAME.pid
-CONFIGFILE=/etc/glusterfs/glusterfsd.vol
-GLUSTERFS_OPTS="-f $CONFIGFILE"
+GLUSTERD_OPTS=""
PID=`test -f $PIDFILE && cat $PIDFILE`
@@ -31,24 +30,16 @@ test -x $DAEMON || exit 0
# 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"
+ log_success_msg "glusterd service 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_daemon_msg "Starting glusterd service" "glusterd"
+ start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE $GLUSTERD_OPTS
log_end_msg $?
start_daemon -p $PIDFILE $DAEMON -f $CONFIGFILE
return $?
@@ -57,7 +48,7 @@ do_start()
do_stop()
{
- log_daemon_msg "Stopping glusterfs server" "glusterfsd"
+ log_daemon_msg "Stopping glusterd service" "glusterd"
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
log_end_msg $?
rm -f $PIDFILE
@@ -70,9 +61,9 @@ do_status()
pidofproc -p $PIDFILE $DAEMON >/dev/null
status=$?
if [ $status -eq 0 ]; then
- log_success_msg "glusterfs server is running with pid $PID"
+ log_success_msg "glusterd service is running with pid $PID"
else
- log_failure_msg "glusterfs server is not running."
+ log_failure_msg "glusterd service is not running."
fi
exit $status
}
diff --git a/extras/init.d/glusterd-Redhat.in b/extras/init.d/glusterd-Redhat.in
new file mode 100755
index 000000000..e320708ae
--- /dev/null
+++ b/extras/init.d/glusterd-Redhat.in
@@ -0,0 +1,142 @@
+#!/bin/bash
+#
+# glusterd Startup script for the glusterfs server
+#
+# chkconfig: - 20 80
+# description: Clustered file-system server
+
+### BEGIN INIT INFO
+# Provides: glusterd
+# Required-Start: $local_fs $network
+# Required-Stop: $local_fs $network
+# Should-Start:
+# Should-Stop:
+# Default-Start:
+# Default-Stop: 0 1 2 3 4 5 6
+# Short-Description: glusterfs server
+# Description: Clustered file-system server
+### END INIT INFO
+#
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+BASE=glusterd
+
+# Fedora File System Layout dictates /run
+[ -e /run ] && RUNDIR="/run"
+PIDFILE="${RUNDIR:-/var/run}/${BASE}.pid"
+
+PID=`test -f $PIDFILE && cat $PIDFILE`
+
+# Overwriteable from sysconfig
+LOG_LEVEL=''
+LOG_FILE=''
+GLUSTERD_OPTIONS=''
+GLUSTERD_NOFILE='65536'
+
+[ -f /etc/sysconfig/${BASE} ] && . /etc/sysconfig/${BASE}
+
+[ ! -z $LOG_LEVEL ] && GLUSTERD_OPTIONS="${GLUSTERD_OPTIONS} --log-level ${LOG_LEVEL}"
+[ ! -z $LOG_FILE ] && GLUSTERD_OPTIONS="${GLUSTERD_OPTIONS} --log-file ${LOG_FILE}"
+
+GLUSTERFSD=glusterfsd
+GLUSTERFS=glusterfs
+GLUSTERD_BIN=@prefix@/sbin/$BASE
+GLUSTERD_OPTS="--pid-file=$PIDFILE ${GLUSTERD_OPTIONS}"
+GLUSTERD="$GLUSTERD_BIN $GLUSTERD_OPTS"
+RETVAL=0
+
+LOCKFILE=/var/lock/subsys/${BASE}
+
+# Start the service $BASE
+start()
+{
+ if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then
+ echo "glusterd service is already running with pid $PID"
+ return 0
+ else
+ ulimit -n $GLUSTERD_NOFILE
+ echo -n $"Starting $BASE:"
+ daemon $GLUSTERD
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch $LOCKFILE
+ return $RETVAL
+ fi
+}
+
+# Stop the service $BASE
+stop()
+{
+ echo -n $"Stopping $BASE:"
+ if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then
+ killproc -p $PIDFILE $BASE
+ else
+ killproc $BASE
+ fi
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && rm -f $LOCKFILE
+ return $RETVAL
+}
+
+restart()
+{
+ stop
+ start
+}
+
+reload()
+{
+ restart
+}
+
+force_reload()
+{
+ restart
+}
+
+rh_status()
+{
+ status $BASE
+}
+
+rh_status_q()
+{
+ rh_status &>/dev/null
+}
+
+
+### service arguments ###
+case $1 in
+ start)
+ rh_status_q && exit 0
+ $1
+ ;;
+ stop)
+ rh_status_q || exit 0
+ $1
+ ;;
+ restart)
+ $1
+ ;;
+ reload)
+ rh_status_q || exit 7
+ $1
+ ;;
+ force-reload)
+ force_reload
+ ;;
+ status)
+ rh_status
+ ;;
+ condrestart|try-restart)
+ rh_status_q || exit 0
+ restart
+ ;;
+ *)
+ echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
+ exit 1
+esac
+
+exit $?
diff --git a/extras/init.d/glusterfsd-SuSE b/extras/init.d/glusterd-SuSE.in
index ede27b2b3..6259bab00 100755
--- a/extras/init.d/glusterfsd-SuSE
+++ b/extras/init.d/glusterd-SuSE.in
@@ -1,28 +1,30 @@
#!/bin/bash
#
### BEGIN INIT INFO
-# Provides: glusterfsd
-# Required-Start: $local_fs $network
-# Required-Stop:
+# Provides: glusterd
+# Required-Start: $remote_fs $network
+# Required-Stop: $remote_fs $network
# Default-Start: 3 5
# Default-Stop:
-# Short-Description: GlusterFS server daemon
-# Description: All necessary services for GlusterFS clients
+# Short-Description: Gluster File System service for volume management
+# Description: Gluster File System service for volume management
### END INIT INFO
# Get function from functions library
. /etc/rc.status
-BASE=glusterfsd
-GSERVER="/usr/sbin/$BASE -f /etc/glusterfs/glusterfsd.vol"
+BASE=glusterd
+GLUSTERD_BIN=@prefix@/sbin/$BASE
+GLUSTERD_OPTS=""
+GLUSTERD="$GLUSTERD_BIN $GLUSTERD_OPTS"
RETVAL=0
# Start the service $BASE
start()
{
echo -n $"Starting $BASE:"
- startproc $GSERVER
+ startproc $GLUSTERD
return $?
}
@@ -30,7 +32,7 @@ start()
stop()
{
echo $"Stopping $BASE:"
- killproc $BASE
+ killproc $BASE
return $?
}
@@ -52,20 +54,24 @@ case $1 in
rc_status -v
;;
status)
- echo -n " glusterfsd"
+ echo -n " glusterd"
if ! checkproc $BASE ;then
echo " not running"
rc_failed 3
fi
rc_status -v
;;
+ reload)
+ rc_failed 3
+ rc_status -v
+ ;;
restart)
$0 stop
$0 start
rc_status
;;
*)
- echo $"Usage: $0 {start|stop|status|restart}."
+ echo $"Usage: $0 {start|stop|status|reload|restart}."
exit 1
esac
diff --git a/extras/init.d/glusterfs-server.plist.in b/extras/init.d/glusterd.plist.in
index 4d2287c57..7385fa486 100644
--- a/extras/init.d/glusterfs-server.plist.in
+++ b/extras/init.d/glusterd.plist.in
@@ -3,13 +3,11 @@
<plist version="1.0">
<dict>
<key>Label</key>
- <string>com.zresearch.glusterfs</string>
+ <string>com.gluster.glusterd</string>
<key>ProgramArguments</key>
<array>
- <string>@prefix@/sbin/glusterfsd</string>
+ <string>@prefix@/sbin/glusterd</string>
<string>-N</string>
- <string>-f</string>
- <string>@prefix@/etc/glusterfs/server.vol</string>
</array>
</dict>
</plist>
diff --git a/extras/init.d/glusterfsd-Redhat b/extras/init.d/glusterfsd-Redhat
deleted file mode 100755
index 2577e9e76..000000000
--- a/extras/init.d/glusterfsd-Redhat
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-#
-# chkconfig: 35 90 12
-# description: Glusterfsd server
-#
-
-# Get function from functions library
-. /etc/rc.d/init.d/functions
-
-BASE=glusterfsd
-GSERVER="/usr/sbin/$BASE -f /etc/glusterfs/glusterfsd.vol"
-RETVAL=0
-
-# Start the service $BASE
-start()
-{
- echo $"Starting $BASE:"
- daemon $GSERVER
- RETVAL=$?
- [ $RETVAL -ne 0 ] && exit $RETVAL
-}
-
-# Stop the service $BASE
-stop()
-{
- echo $"Stopping $BASE:"
- killproc $BASE
-}
-
-
-### service arguments ###
-case $1 in
- start)
- start
- ;;
- stop)
- stop
- ;;
- status)
- status $BASE
- ;;
- restart)
- $0 stop
- $0 start
- ;;
- *)
- echo $"Usage: $0 {start|stop|status|restart}."
- exit 1
-esac
-
-exit 0
diff --git a/extras/init.d/rhel5-load-fuse.modules b/extras/init.d/rhel5-load-fuse.modules
new file mode 100755
index 000000000..ee194db99
--- /dev/null
+++ b/extras/init.d/rhel5-load-fuse.modules
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# fusermount-glusterfs requires the /dev/fuse character device. The fuse module
+# provides this and is loaded on demand in newer Linux distributions.
+#
+
+[ -c /dev/fuse ] || /sbin/modprobe fuse
diff --git a/extras/logger.conf.example b/extras/logger.conf.example
new file mode 100644
index 000000000..248be5bda
--- /dev/null
+++ b/extras/logger.conf.example
@@ -0,0 +1,13 @@
+#
+# Sample logger.conf file to configure enhanced Logging in GlusterFS
+#
+# To enable enhanced logging capabilities,
+#
+# 1. rename this file to /etc/glusterfs/logger.conf
+#
+# 2. rename /etc/rsyslog.d/gluster.conf.example to
+# /etc/rsyslog.d/gluster.conf
+#
+# This change requires restart of all gluster services/volumes and
+# rsyslog.
+#
diff --git a/extras/ocf/Makefile.am b/extras/ocf/Makefile.am
new file mode 100644
index 000000000..c49a835fb
--- /dev/null
+++ b/extras/ocf/Makefile.am
@@ -0,0 +1,11 @@
+EXTRA_DIST = glusterd.in volume.in
+
+# The root of the OCF resource agent hierarchy
+# Per the OCF standard, it's always "lib",
+# not "lib64" (even on 64-bit platforms).
+ocfdir = $(prefix)/lib/ocf
+
+# The ceph provider directory
+radir = $(ocfdir)/resource.d/$(PACKAGE_NAME)
+
+ra_SCRIPTS = glusterd volume
diff --git a/extras/ocf/glusterd.in b/extras/ocf/glusterd.in
new file mode 100755
index 000000000..c119a285d
--- /dev/null
+++ b/extras/ocf/glusterd.in
@@ -0,0 +1,212 @@
+#!/bin/sh
+#
+# glusterd
+#
+# Description: Manages a glusterd server as a (typically cloned)
+# HA resource
+#
+# Authors: Florian Haas (hastexo Professional Services GmbH)
+#
+# License: GNU General Public License (GPL)
+
+#######################################################################
+# Initialization:
+
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+# Convenience variables
+# When sysconfdir and localstatedir aren't passed in as
+# configure flags, they're defined in terms of prefix
+prefix=@prefix@
+#######################################################################
+
+
+OCF_RESKEY_binary_default="glusterd"
+OCF_RESKEY_pid_default="@localstatedir@/run/glusterd.pid"
+OCF_RESKEY_socket_default=""
+OCF_RESKEY_additional_parameters_default=""
+
+: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
+: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}}
+
+glusterd_meta_data() {
+ cat <<EOF
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="glusterd" version="0.1">
+ <version>0.1</version>
+ <longdesc lang="en">
+ </longdesc>
+ <shortdesc lang="en">Manages a Gluster server</shortdesc>
+ <parameters>
+ <parameter name="binary">
+ <longdesc lang="en">
+ Name of the glusterd executable. Specify a full absolute
+ path if the binary is not in your \$PATH.
+ </longdesc>
+ <shortdesc lang="en">glusterd executable</shortdesc>
+ <content type="string" default="$OCF_RESKEY_binary_default"/>
+ </parameter>
+ <parameter name="pid">
+ <longdesc lang="en">
+ Path to the glusterd PID file.
+ </longdesc>
+ <shortdesc lang="en">PID file</shortdesc>
+ <content type="string" default="$OCF_RESKEY_pid_default"/>
+ </parameter>
+ <parameter name="socket">
+ <longdesc lang="en">
+ Path to the glusterd UNIX socket file. If unspecified,
+ glusterd will not listen on any socket.
+ </longdesc>
+ <shortdesc lang="en">Socket file</shortdesc>
+ <content type="string"/>
+ </parameter>
+ </parameters>
+ <actions>
+ <action name="start" timeout="20" />
+ <action name="stop" timeout="20" />
+ <action name="monitor" timeout="20" interval="10" />
+ <action name="reload" timeout="20" />
+ <action name="meta-data" timeout="5" />
+ <action name="validate-all" timeout="20" />
+ </actions>
+</resource-agent>
+EOF
+
+}
+
+glusterd_start() {
+ local glusterd_options
+ # exit immediately if configuration is not valid
+ glusterd_validate_all || exit $?
+
+ # if resource is already running, bail out early
+ if glusterd_monitor; then
+ ocf_log info "Resource is already running"
+ return $OCF_SUCCESS
+ fi
+
+ # actually start up the resource here (make sure to immediately
+ # exit with an $OCF_ERR_ error code if anything goes seriously
+ # wrong)
+ glusterd_options="-p $OCF_RESKEY_pid"
+ if [ -n "$OCF_RESKEY_socket" ]; then
+ glusterd_options="$glusterd_options -S $OCF_RESKEY_socket"
+ fi
+ if [ -n "$OCF_RESKEY_additional_parameters" ]; then
+ glusterd_options="$glusterd_options $OCF_RESKEY_additional_parameters"
+ fi
+
+ ocf_run $OCF_RESKEY_binary $glusterd_options || exit $OCF_ERR_GENERIC
+
+ # After the resource has been started, check whether it started up
+ # correctly. If the resource starts asynchronously, the agent may
+ # spin on the monitor function here -- if the resource does not
+ # start up within the defined timeout, the cluster manager will
+ # consider the start action failed
+ while ! glusterd_monitor; do
+ ocf_log debug "Resource has not started yet, waiting"
+ sleep 1
+ done
+
+ # only return $OCF_SUCCESS if _everything_ succeeded as expected
+ return $OCF_SUCCESS
+}
+
+glusterd_stop() {
+ local rc
+ local pid
+
+ # exit immediately if configuration is not valid
+ glusterd_validate_all || exit $?
+
+ glusterd_monitor
+ rc=$?
+ case "$rc" in
+ "$OCF_SUCCESS")
+ # Currently running. Normal, expected behavior.
+ ocf_log debug "Resource is currently running"
+ ;;
+ "$OCF_NOT_RUNNING")
+ # Currently not running. Nothing to do.
+ ocf_log info "Resource is already stopped"
+ return $OCF_SUCCESS
+ ;;
+ esac
+
+ # actually shut down the resource here (make sure to immediately
+ # exit with an $OCF_ERR_ error code if anything goes seriously
+ # wrong)
+ pid=`cat $OCF_RESKEY_pid`
+ ocf_run kill -s TERM $pid || exit OCF_ERR_GENERIC
+
+ # After the resource has been stopped, check whether it shut down
+ # correctly. If the resource stops asynchronously, the agent may
+ # spin on the monitor function here -- if the resource does not
+ # shut down within the defined timeout, the cluster manager will
+ # consider the stop action failed
+ while glusterd_monitor; do
+ ocf_log debug "Resource has not stopped yet, waiting"
+ sleep 1
+ done
+
+ # only return $OCF_SUCCESS if _everything_ succeeded as expected
+ return $OCF_SUCCESS
+
+}
+
+glusterd_monitor() {
+ local pid
+
+ [ -e $OCF_RESKEY_pid ] || return $OCF_NOT_RUNNING
+
+ pid=`cat $OCF_RESKEY_pid`
+ ocf_run kill -s 0 $pid || return $OCF_NOT_RUNNING
+
+ ocf_log debug "$OCF_RESKEY_binary running with PID $pid"
+ return $OCF_SUCCESS
+}
+
+glusterd_validate_all() {
+ # Test for required binaries
+ check_binary $OCF_RESKEY_binary
+
+ return $OCF_SUCCESS
+}
+
+
+
+# Make sure meta-data and usage always succeed
+case $__OCF_ACTION in
+meta-data) glusterd_meta_data
+ exit $OCF_SUCCESS
+ ;;
+usage|help) glusterd_usage
+ exit $OCF_SUCCESS
+ ;;
+esac
+
+# Anything other than meta-data and usage must pass validation
+glusterd_validate_all || exit $?
+
+# Translate each action into the appropriate function call
+case $__OCF_ACTION in
+start) glusterd_start;;
+stop) glusterd_stop;;
+status|monitor) glusterd_monitor;;
+reload) ocf_log info "Reloading..."
+ glusterd_start
+ ;;
+validate-all) ;;
+notify) exit $OCF_SUCCESS;;
+*) glusterd_usage
+ exit $OCF_ERR_UNIMPLEMENTED
+ ;;
+esac
+rc=$?
+
+# The resource agent may optionally log a debug message
+ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc"
+exit $rc
diff --git a/extras/ocf/volume.in b/extras/ocf/volume.in
new file mode 100755
index 000000000..72fd1213a
--- /dev/null
+++ b/extras/ocf/volume.in
@@ -0,0 +1,246 @@
+#!/bin/sh
+#
+# glusterd
+#
+# Description: Manages a glusterd server as a (typically cloned)
+# HA resource
+#
+# Authors: Florian Haas (hastexo Professional Services GmbH)
+#
+# License: GNU General Public License (GPL)
+
+#######################################################################
+# Initialization:
+
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+# Convenience variables
+# When sysconfdir and localstatedir aren't passed in as
+# configure flags, they're defined in terms of prefix
+prefix=@prefix@
+SHORTHOSTNAME=`hostname -s`
+#######################################################################
+
+OCF_RESKEY_binary_default="gluster"
+
+: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}}
+
+volume_meta_data() {
+ cat <<EOF
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="volume" version="0.1">
+ <version>0.1</version>
+ <longdesc lang="en">
+Manages a GlusterFS volume and monitors its bricks. When a resource of
+this type is configured as a clone (as is commonly the case), then it
+must have clone ordering enabled.
+ </longdesc>
+ <shortdesc lang="en">Manages a GlusterFS volume</shortdesc>
+ <parameters>
+ <parameter name="volname" required="1">
+ <longdesc lang="en">
+ The name of the volume to manage.
+ </longdesc>
+ <shortdesc lang="en">volume name</shortdesc>
+ <content type="string"/>
+ </parameter>
+ <parameter name="binary">
+ <longdesc lang="en">
+ Name of the gluster executable. Specify a full absolute
+ path if the binary is not in your \$PATH.
+ </longdesc>
+ <shortdesc lang="en">gluster executable</shortdesc>
+ <content type="string" default="$OCF_RESKEY_binary_default"/>
+ </parameter>
+ </parameters>
+ <actions>
+ <action name="start" timeout="20" />
+ <action name="stop" timeout="20" />
+ <action name="monitor" timeout="20" interval="10" />
+ <action name="reload" timeout="20" />
+ <action name="meta-data" timeout="5" />
+ <action name="validate-all" timeout="20" />
+ </actions>
+</resource-agent>
+EOF
+
+}
+
+volume_getdir() {
+ local voldir
+ voldir="@sysconfdir@/glusterd/vols/${OCF_RESKEY_volname}"
+
+ [ -d ${voldir} ] || return 1
+
+ echo "${voldir}"
+ return 0
+}
+
+volume_getbricks() {
+ local infofile
+ local voldir
+ voldir=`volume_getdir`
+ infofile="${voldir}/info"
+
+ [ -e ${infofile} ] || return 1
+
+ echo "`sed -n -e "s/^brick-.\+=${SHORTHOSTNAME}://p" < ${infofile}`"
+ return 0
+}
+
+volume_getpids() {
+ local bricks
+ local piddir
+ local pidfile
+ local infofile
+ local voldir
+
+ voldir=`volume_getdir`
+ bricks=`volume_getbricks`
+ piddir="${voldir}/run"
+
+ for brick in ${bricks}; do
+ pidfile="${piddir}/${SHORTHOSTNAME}${brick}.pid"
+ [ -e $pidfile ] || return 1
+ cat $pidfile
+ done
+
+ return 0
+}
+
+volume_start() {
+ local volume_options
+
+ # exit immediately if configuration is not valid
+ volume_validate_all || exit $?
+
+ # if resource is already running, bail out early
+ if volume_monitor; then
+ ocf_log info "Resource is already running"
+ return $OCF_SUCCESS
+ fi
+
+ # actually start up the resource here
+ ocf_run "$OCF_RESKEY_binary" \
+ volume start "$OCF_RESKEY_volname" force || exit $OCF_ERR_GENERIC
+
+ # After the resource has been started, check whether it started up
+ # correctly. If the resource starts asynchronously, the agent may
+ # spin on the monitor function here -- if the resource does not
+ # start up within the defined timeout, the cluster manager will
+ # consider the start action failed
+ while ! volume_monitor; do
+ ocf_log debug "Resource has not started yet, waiting"
+ sleep 1
+ done
+
+ # only return $OCF_SUCCESS if _everything_ succeeded as expected
+ return $OCF_SUCCESS
+}
+
+volume_stop() {
+ local rc
+ local pid
+
+ # exit immediately if configuration is not valid
+ volume_validate_all || exit $?
+
+ volume_monitor
+ rc=$?
+ case "$rc" in
+ "$OCF_SUCCESS")
+ # Currently running. Normal, expected behavior.
+ ocf_log debug "Resource is currently running"
+ ;;
+ "$OCF_NOT_RUNNING")
+ # Currently not running. Nothing to do.
+ ocf_log info "Resource is already stopped"
+ return $OCF_SUCCESS
+ ;;
+ esac
+
+ # actually shut down the resource here (make sure to immediately
+ # exit with an $OCF_ERR_ error code if anything goes seriously
+ # wrong)
+ pids=`volume_getpids`
+ for pid in $pids; do
+ ocf_run kill -s TERM $pid
+ done
+
+ # After the resource has been stopped, check whether it shut down
+ # correctly. If the resource stops asynchronously, the agent may
+ # spin on the monitor function here -- if the resource does not
+ # shut down within the defined timeout, the cluster manager will
+ # consider the stop action failed
+ while volume_monitor; do
+ ocf_log debug "Resource has not stopped yet, waiting"
+ sleep 1
+ done
+
+ # only return $OCF_SUCCESS if _everything_ succeeded as expected
+ return $OCF_SUCCESS
+
+}
+
+volume_monitor() {
+ local pid
+
+ pids=`volume_getpids` || return $OCF_NOT_RUNNING
+
+ for pid in $pids; do
+ ocf_run kill -s 0 $pid || return $OCF_NOT_RUNNING
+ done
+
+ ocf_log debug "Local bricks for volume ${OCF_RESKEY_volname} running with PIDs $pids"
+ return $OCF_SUCCESS
+}
+
+volume_validate_all() {
+ # Test for configuration errors first
+ if [ -z "${OCF_RESKEY_volname}" ]; then
+ ocf_log err 'Missing required parameter "volname"'
+ return $OCF_ERR_CONFIGURED
+ fi
+
+ # Test for required binaries
+ check_binary $OCF_RESKEY_binary
+
+ return $OCF_SUCCESS
+}
+
+
+
+# Make sure meta-data and usage always succeed
+case $__OCF_ACTION in
+meta-data) volume_meta_data
+ exit $OCF_SUCCESS
+ ;;
+usage|help) volume_usage
+ exit $OCF_SUCCESS
+ ;;
+esac
+
+# Anything other than meta-data and usage must pass validation
+volume_validate_all || exit $?
+
+# Translate each action into the appropriate function call
+case $__OCF_ACTION in
+start) volume_start;;
+stop) volume_stop;;
+status|monitor) volume_monitor;;
+reload) ocf_log info "Reloading..."
+ volume_start
+ ;;
+validate-all) ;;
+notify) exit $OCF_SUCCESS;;
+*) volume_usage
+ exit $OCF_ERR_UNIMPLEMENTED
+ ;;
+esac
+rc=$?
+
+# The resource agent may optionally log a debug message
+ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc"
+exit $rc
diff --git a/extras/profiler/glusterfs-profiler b/extras/profiler/glusterfs-profiler
new file mode 100755
index 000000000..65d445864
--- /dev/null
+++ b/extras/profiler/glusterfs-profiler
@@ -0,0 +1,817 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+# This file is part of GlusterFS.
+#
+# This file is licensed to you under your choice of the GNU Lesser
+# General Public License, version 3 or any later version (LGPLv3 or
+# later), or the GNU General Public License, version 2 (GPLv2), in all
+# cases as published by the Free Software Foundation.
+
+
+# texttable - module for creating simple ASCII tables
+# Incorporated from texttable.py downloaded from
+# http://jefke.free.fr/stuff/python/texttable/texttable-0.7.0.tar.gz
+
+import sys
+import string
+
+try:
+ if sys.version >= '2.3':
+ import textwrap
+ elif sys.version >= '2.2':
+ from optparse import textwrap
+ else:
+ from optik import textwrap
+except ImportError:
+ sys.stderr.write("Can't import textwrap module!\n")
+ raise
+
+try:
+ True, False
+except NameError:
+ (True, False) = (1, 0)
+
+def len(iterable):
+ """Redefining len here so it will be able to work with non-ASCII characters
+ """
+ if not isinstance(iterable, str):
+ return iterable.__len__()
+
+ try:
+ return len(unicode(iterable, 'utf'))
+ except:
+ return iterable.__len__()
+
+class ArraySizeError(Exception):
+ """Exception raised when specified rows don't fit the required size
+ """
+
+ def __init__(self, msg):
+ self.msg = msg
+ Exception.__init__(self, msg, '')
+
+ def __str__(self):
+ return self.msg
+
+class Texttable:
+
+ BORDER = 1
+ HEADER = 1 << 1
+ HLINES = 1 << 2
+ VLINES = 1 << 3
+
+ def __init__(self, max_width=80):
+ """Constructor
+
+ - max_width is an integer, specifying the maximum width of the table
+ - if set to 0, size is unlimited, therefore cells won't be wrapped
+ """
+
+ if max_width <= 0:
+ max_width = False
+ self._max_width = max_width
+ self._deco = Texttable.VLINES | Texttable.HLINES | Texttable.BORDER | \
+ Texttable.HEADER
+ self.set_chars(['-', '|', '+', '='])
+ self.reset()
+
+ def reset(self):
+ """Reset the instance
+
+ - reset rows and header
+ """
+
+ self._hline_string = None
+ self._row_size = None
+ self._header = []
+ self._rows = []
+
+ def header(self, array):
+ """Specify the header of the table
+ """
+
+ self._check_row_size(array)
+ self._header = map(str, array)
+
+ def add_row(self, array):
+ """Add a row in the rows stack
+
+ - cells can contain newlines and tabs
+ """
+
+ self._check_row_size(array)
+ self._rows.append(map(str, array))
+
+ def add_rows(self, rows, header=True):
+ """Add several rows in the rows stack
+
+ - The 'rows' argument can be either an iterator returning arrays,
+ or a by-dimensional array
+ - 'header' specifies if the first row should be used as the header
+ of the table
+ """
+
+ # nb: don't use 'iter' on by-dimensional arrays, to get a
+ # usable code for python 2.1
+ if header:
+ if hasattr(rows, '__iter__') and hasattr(rows, 'next'):
+ self.header(rows.next())
+ else:
+ self.header(rows[0])
+ rows = rows[1:]
+ for row in rows:
+ self.add_row(row)
+
+ def set_chars(self, array):
+ """Set the characters used to draw lines between rows and columns
+
+ - the array should contain 4 fields:
+
+ [horizontal, vertical, corner, header]
+
+ - default is set to:
+
+ ['-', '|', '+', '=']
+ """
+
+ if len(array) != 4:
+ raise ArraySizeError, "array should contain 4 characters"
+ array = [ x[:1] for x in [ str(s) for s in array ] ]
+ (self._char_horiz, self._char_vert,
+ self._char_corner, self._char_header) = array
+
+ def set_deco(self, deco):
+ """Set the table decoration
+
+ - 'deco' can be a combinaison of:
+
+ Texttable.BORDER: Border around the table
+ Texttable.HEADER: Horizontal line below the header
+ Texttable.HLINES: Horizontal lines between rows
+ Texttable.VLINES: Vertical lines between columns
+
+ All of them are enabled by default
+
+ - example:
+
+ Texttable.BORDER | Texttable.HEADER
+ """
+
+ self._deco = deco
+
+ def set_cols_align(self, array):
+ """Set the desired columns alignment
+
+ - the elements of the array should be either "l", "c" or "r":
+
+ * "l": column flushed left
+ * "c": column centered
+ * "r": column flushed right
+ """
+
+ self._check_row_size(array)
+ self._align = array
+
+ def set_cols_valign(self, array):
+ """Set the desired columns vertical alignment
+
+ - the elements of the array should be either "t", "m" or "b":
+
+ * "t": column aligned on the top of the cell
+ * "m": column aligned on the middle of the cell
+ * "b": column aligned on the bottom of the cell
+ """
+
+ self._check_row_size(array)
+ self._valign = array
+
+ def set_cols_width(self, array):
+ """Set the desired columns width
+
+ - the elements of the array should be integers, specifying the
+ width of each column. For example:
+
+ [10, 20, 5]
+ """
+
+ self._check_row_size(array)
+ try:
+ array = map(int, array)
+ if reduce(min, array) <= 0:
+ raise ValueError
+ except ValueError:
+ sys.stderr.write("Wrong argument in column width specification\n")
+ raise
+ self._width = array
+
+ def draw(self):
+ """Draw the table
+
+ - the table is returned as a whole string
+ """
+
+ if not self._header and not self._rows:
+ return
+ self._compute_cols_width()
+ self._check_align()
+ out = ""
+ if self._has_border():
+ out += self._hline()
+ if self._header:
+ out += self._draw_line(self._header, isheader=True)
+ if self._has_header():
+ out += self._hline_header()
+ length = 0
+ for row in self._rows:
+ length += 1
+ out += self._draw_line(row)
+ if self._has_hlines() and length < len(self._rows):
+ out += self._hline()
+ if self._has_border():
+ out += self._hline()
+ return out[:-1]
+
+ def _check_row_size(self, array):
+ """Check that the specified array fits the previous rows size
+ """
+
+ if not self._row_size:
+ self._row_size = len(array)
+ elif self._row_size != len(array):
+ raise ArraySizeError, "array should contain %d elements" \
+ % self._row_size
+
+ def _has_vlines(self):
+ """Return a boolean, if vlines are required or not
+ """
+
+ return self._deco & Texttable.VLINES > 0
+
+ def _has_hlines(self):
+ """Return a boolean, if hlines are required or not
+ """
+
+ return self._deco & Texttable.HLINES > 0
+
+ def _has_border(self):
+ """Return a boolean, if border is required or not
+ """
+
+ return self._deco & Texttable.BORDER > 0
+
+ def _has_header(self):
+ """Return a boolean, if header line is required or not
+ """
+
+ return self._deco & Texttable.HEADER > 0
+
+ def _hline_header(self):
+ """Print header's horizontal line
+ """
+
+ return self._build_hline(True)
+
+ def _hline(self):
+ """Print an horizontal line
+ """
+
+ if not self._hline_string:
+ self._hline_string = self._build_hline()
+ return self._hline_string
+
+ def _build_hline(self, is_header=False):
+ """Return a string used to separated rows or separate header from
+ rows
+ """
+ horiz = self._char_horiz
+ if (is_header):
+ horiz = self._char_header
+ # compute cell separator
+ s = "%s%s%s" % (horiz, [horiz, self._char_corner][self._has_vlines()],
+ horiz)
+ # build the line
+ l = string.join([horiz*n for n in self._width], s)
+ # add border if needed
+ if self._has_border():
+ l = "%s%s%s%s%s\n" % (self._char_corner, horiz, l, horiz,
+ self._char_corner)
+ else:
+ l += "\n"
+ return l
+
+ def _len_cell(self, cell):
+ """Return the width of the cell
+
+ Special characters are taken into account to return the width of the
+ cell, such like newlines and tabs
+ """
+
+ cell_lines = cell.split('\n')
+ maxi = 0
+ for line in cell_lines:
+ length = 0
+ parts = line.split('\t')
+ for part, i in zip(parts, range(1, len(parts) + 1)):
+ length = length + len(part)
+ if i < len(parts):
+ length = (length/8 + 1)*8
+ maxi = max(maxi, length)
+ return maxi
+
+ def _compute_cols_width(self):
+ """Return an array with the width of each column
+
+ If a specific width has been specified, exit. If the total of the
+ columns width exceed the table desired width, another width will be
+ computed to fit, and cells will be wrapped.
+ """
+
+ if hasattr(self, "_width"):
+ return
+ maxi = []
+ if self._header:
+ maxi = [ self._len_cell(x) for x in self._header ]
+ for row in self._rows:
+ for cell,i in zip(row, range(len(row))):
+ try:
+ maxi[i] = max(maxi[i], self._len_cell(cell))
+ except (TypeError, IndexError):
+ maxi.append(self._len_cell(cell))
+ items = len(maxi)
+ length = reduce(lambda x,y: x+y, maxi)
+ if self._max_width and length + items*3 + 1 > self._max_width:
+ maxi = [(self._max_width - items*3 -1) / items \
+ for n in range(items)]
+ self._width = maxi
+
+ def _check_align(self):
+ """Check if alignment has been specified, set default one if not
+ """
+
+ if not hasattr(self, "_align"):
+ self._align = ["l"]*self._row_size
+ if not hasattr(self, "_valign"):
+ self._valign = ["t"]*self._row_size
+
+ def _draw_line(self, line, isheader=False):
+ """Draw a line
+
+ Loop over a single cell length, over all the cells
+ """
+
+ line = self._splitit(line, isheader)
+ space = " "
+ out = ""
+ for i in range(len(line[0])):
+ if self._has_border():
+ out += "%s " % self._char_vert
+ length = 0
+ for cell, width, align in zip(line, self._width, self._align):
+ length += 1
+ cell_line = cell[i]
+ fill = width - len(cell_line)
+ if isheader:
+ align = "c"
+ if align == "r":
+ out += "%s " % (fill * space + cell_line)
+ elif align == "c":
+ out += "%s " % (fill/2 * space + cell_line \
+ + (fill/2 + fill%2) * space)
+ else:
+ out += "%s " % (cell_line + fill * space)
+ if length < len(line):
+ out += "%s " % [space, self._char_vert][self._has_vlines()]
+ out += "%s\n" % ['', self._char_vert][self._has_border()]
+ return out
+
+ def _splitit(self, line, isheader):
+ """Split each element of line to fit the column width
+
+ Each element is turned into a list, result of the wrapping of the
+ string to the desired width
+ """
+
+ line_wrapped = []
+ for cell, width in zip(line, self._width):
+ array = []
+ for c in cell.split('\n'):
+ array.extend(textwrap.wrap(unicode(c, 'utf'), width))
+ line_wrapped.append(array)
+ max_cell_lines = reduce(max, map(len, line_wrapped))
+ for cell, valign in zip(line_wrapped, self._valign):
+ if isheader:
+ valign = "t"
+ if valign == "m":
+ missing = max_cell_lines - len(cell)
+ cell[:0] = [""] * (missing / 2)
+ cell.extend([""] * (missing / 2 + missing % 2))
+ elif valign == "b":
+ cell[:0] = [""] * (max_cell_lines - len(cell))
+ else:
+ cell.extend([""] * (max_cell_lines - len(cell)))
+ return line_wrapped
+
+
+# Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com>
+# 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
+# <http://www.gnu.org/licenses/>.
+
+graph_available = True
+
+try:
+ import numpy as np
+ import matplotlib.pyplot as plt
+except ImportError:
+ graph_available = False
+
+import re
+import sys
+
+from optparse import OptionParser
+
+# Global dict-of-dict holding the latency data
+# latency[xlator-name][op-name]
+
+latencies = {}
+counts = {}
+totals = {}
+
+def collect_data (f):
+ """Collect latency data from the file object f and store it in
+ the global variable @latencies"""
+
+ # example dump file line:
+ # fuse.latency.TRUNCATE=3147.000,4
+
+ for line in f:
+ m = re.search ("(\w+)\.\w+.(\w+)=(\w+\.\w+),(\w+),(\w+.\w+)", line)
+ if m and float(m.group(3)) != 0:
+ xlator = m.group(1)
+ op = m.group(2)
+ time = m.group(3)
+ count = m.group(4)
+ total = m.group(5)
+
+ if not xlator in latencies.keys():
+ latencies[xlator] = dict()
+
+ if not xlator in counts.keys():
+ counts[xlator] = dict()
+
+ if not xlator in totals.keys():
+ totals[xlator] = dict()
+
+ latencies[xlator][op] = time
+ counts[xlator][op] = count
+ totals[xlator][op] = total
+
+
+def calc_latency_heights (xlator_order):
+ heights = map (lambda x: [], xlator_order)
+
+ N = len (xlator_order)
+ for i in range (N):
+ xl = xlator_order[i]
+
+ k = latencies[xl].keys()
+ k.sort()
+
+ if i == len (xlator_order) - 1:
+ # bottom-most xlator
+ heights[i] = [float (latencies[xl][key]) for key in k]
+
+ else:
+ next_xl = xlator_order[i+1]
+ this_xl_time = [latencies[xl][key] for key in k]
+ next_xl_time = [latencies[next_xl][key] for key in k]
+
+ heights[i] = map (lambda x, y: float (x) - float (y),
+ this_xl_time, next_xl_time)
+ return heights
+
+# have sufficient number of colors
+colors = ["violet", "blue", "green", "yellow", "orange", "red"]
+
+def latency_profile (title, xlator_order, mode):
+ heights = calc_latency_heights (xlator_order)
+
+ N = len (latencies[xlator_order[0]].keys())
+ Nxl = len (xlator_order)
+ ind = np.arange (N)
+ width = 0.35
+
+ pieces = map (lambda x: [], xlator_order)
+ bottoms = map (lambda x: [], xlator_order)
+
+ bottoms[Nxl-1] = map (lambda x: 0, latencies[xlator_order[0]].keys())
+
+ k = latencies[xlator_order[0]].keys()
+ k.sort()
+
+ for i in range (Nxl-1):
+ xl = xlator_order[i+1]
+ bottoms[i] = [float(latencies[xl][key]) for key in k]
+
+ if mode == 'text':
+ print "\n%sLatency profile for %s\n" % (' '*20, title)
+ print "Average latency (microseconds):\n"
+
+ table = Texttable()
+
+ table.set_cols_align(["l", "r"] + ["r"] * len(xlator_order))
+ rows = []
+
+ header = ['OP', 'OP Average (us)'] + xlator_order
+ rows = []
+
+ for op in k:
+ sum = reduce (lambda x, y: x + y, [heights[xlator_order.index(xl)][k.index(op)] for xl in xlator_order],
+ 0)
+
+ row = [op]
+ row += ["%5.2f" % sum]
+
+ for xl in xlator_order:
+ op_index = k.index(op)
+ row += ["%5.2f" % (heights[xlator_order.index(xl)][op_index])]
+
+ rows.append(row)
+
+ def row_sort(r1, r2):
+ v1 = float(r1[1])
+ v2 = float(r2[1])
+
+ if v1 < v2:
+ return -1
+ elif v1 == v2:
+ return 0
+ else:
+ return 1
+
+ rows.sort(row_sort, reverse=True)
+ table.add_rows([header] + rows)
+ print table.draw()
+
+ elif mode == 'graph':
+ for i in range(Nxl):
+ pieces[i] = plt.bar (ind, heights[i], width, color=colors[i],
+ bottom=bottoms[i])
+
+ plt.ylabel ("Average Latency (microseconds)")
+ plt.title ("Latency Profile for '%s'" % title)
+ k = latencies[xlator_order[0]].keys()
+ k.sort ()
+ plt.xticks (ind+width/2., k)
+
+ m = round (max(map (float, latencies[xlator_order[0]].values())), -2)
+ plt.yticks (np.arange(0, m + m*0.1, m/10))
+ plt.legend (map (lambda p: p[0], pieces), xlator_order)
+
+ plt.show ()
+ else:
+ print "Unknown mode specified!"
+ sys.exit(1)
+
+
+def fop_distribution (title, xlator_order, mode):
+ plt.ylabel ("Percentage of calls")
+ plt.title ("FOP distribution for '%s'" % title)
+ k = counts[xlator_order[0]].keys()
+ k.sort ()
+
+ N = len (latencies[xlator_order[0]].keys())
+ ind = np.arange(N)
+ width = 0.35
+
+ total = 0
+ top_xl = xlator_order[0]
+ for op in k:
+ total += int(counts[top_xl][op])
+
+ heights = []
+
+ for op in k:
+ heights.append (float(counts[top_xl][op])/total * 100)
+
+ if mode == 'text':
+ print "\n%sFOP distribution for %s\n" % (' '*20, title)
+ print "Total number of calls: %d\n" % total
+
+ table = Texttable()
+
+ table.set_cols_align(["l", "r", "r"])
+
+ rows = []
+ header = ["OP", "% of Calls", "Count"]
+
+ for op in k:
+ row = [op, "%5.2f" % (float(counts[top_xl][op])/total * 100), counts[top_xl][op]]
+ rows.append(row)
+
+ def row_sort(r1, r2):
+ v1 = float(r1[1])
+ v2 = float(r2[1])
+
+ if v1 < v2:
+ return -1
+ elif v1 == v2:
+ return 0
+ else:
+ return 1
+
+ rows.sort(row_sort, reverse=True)
+ table.add_rows([header] + rows)
+ print table.draw()
+
+ elif mode == 'graph':
+ bars = plt.bar (ind, heights, width, color="red")
+
+ for bar in bars:
+ height = bar.get_height()
+ plt.text (bar.get_x()+bar.get_width()/2., 1.05*height,
+ "%d%%" % int(height))
+
+ plt.xticks(ind+width/2., k)
+ plt.yticks(np.arange (0, 110, 10))
+
+ plt.show()
+ else:
+ print "mode not specified!"
+ sys.exit(1)
+
+
+def calc_workload_heights (xlator_order, scaling):
+ workload_heights = map (lambda x: [], xlator_order)
+
+ top_xl = xlator_order[0]
+
+ N = len (xlator_order)
+ for i in range (N):
+ xl = xlator_order[i]
+
+ k = totals[xl].keys()
+ k.sort()
+
+ if i == len (xlator_order) - 1:
+ # bottom-most xlator
+ workload_heights[i] = [float (totals[xl][key]) / float(totals[top_xl][key]) * scaling[k.index(key)] for key in k]
+
+ else:
+ next_xl = xlator_order[i+1]
+ this_xl_time = [float(totals[xl][key]) / float(totals[top_xl][key]) * scaling[k.index(key)] for key in k]
+ next_xl_time = [float(totals[next_xl][key]) / float(totals[top_xl][key]) * scaling[k.index(key)] for key in k]
+
+ workload_heights[i] = map (lambda x, y: (float (x) - float (y)),
+ this_xl_time, next_xl_time)
+
+ return workload_heights
+
+def workload_profile(title, xlator_order, mode):
+ plt.ylabel ("Percentage of Total Time")
+ plt.title ("Workload Profile for '%s'" % title)
+ k = totals[xlator_order[0]].keys()
+ k.sort ()
+
+ N = len(totals[xlator_order[0]].keys())
+ Nxl = len(xlator_order)
+ ind = np.arange(N)
+ width = 0.35
+
+ total = 0
+ top_xl = xlator_order[0]
+ for op in k:
+ total += float(totals[top_xl][op])
+
+ p_heights = []
+
+ for op in k:
+ p_heights.append (float(totals[top_xl][op])/total * 100)
+
+ heights = calc_workload_heights (xlator_order, p_heights)
+
+ pieces = map (lambda x: [], xlator_order)
+ bottoms = map (lambda x: [], xlator_order)
+
+ bottoms[Nxl-1] = map (lambda x: 0, totals[xlator_order[0]].keys())
+
+ for i in range (Nxl-1):
+ xl = xlator_order[i+1]
+ k = totals[xl].keys()
+ k.sort()
+
+ bottoms[i] = [float(totals[xl][key]) / float(totals[top_xl][key]) * p_heights[k.index(key)] for key in k]
+
+ if mode == 'text':
+ print "\n%sWorkload profile for %s\n" % (' '*20, title)
+ print "Total Time: %d microseconds = %.1f seconds = %.1f minutes\n" % (total, total / 1000000.0, total / 6000000.0)
+
+ table = Texttable()
+ table.set_cols_align(["l", "r"] + ["r"] * len(xlator_order))
+ rows = []
+
+ header = ['OP', 'OP Total (%)'] + xlator_order
+ rows = []
+
+ for op in k:
+ sum = reduce (lambda x, y: x + y, [heights[xlator_order.index(xl)][k.index(op)] for xl in xlator_order],
+ 0)
+ row = [op]
+ row += ["%5.2f" % sum]
+
+ for xl in xlator_order:
+ op_index = k.index(op)
+ row += ["%5.2f" % heights[xlator_order.index(xl)][op_index]]
+
+ rows.append(row)
+
+ def row_sort(r1, r2):
+ v1 = float(r1[1])
+ v2 = float(r2[1])
+
+ if v1 < v2:
+ return -1
+ elif v1 == v2:
+ return 0
+ else:
+ return 1
+
+ rows.sort(row_sort, reverse=True)
+ table.add_rows([header] + rows)
+ print table.draw()
+
+ elif mode == 'graph':
+ for i in range(Nxl):
+ pieces[i] = plt.bar (ind, heights[i], width, color=colors[i],
+ bottom=bottoms[i])
+
+ for key in k:
+ bar = pieces[Nxl-1][k.index(key)]
+ plt.text (bar.get_x() + bar.get_width()/2., 1.05*p_heights[k.index(key)],
+ "%d%%" % int(p_heights[k.index(key)]))
+
+ plt.xticks(ind+width/2., k)
+ plt.yticks(np.arange (0, 110, 10))
+ plt.legend (map (lambda p: p[0], pieces), xlator_order)
+
+ plt.show()
+ else:
+ print "Unknown mode specified!"
+ sys.exit(1)
+
+
+def main ():
+ parser = OptionParser(usage="usage: %prog [-l | -d | -w] -x <xlator order> <state dump file>")
+ parser.add_option("-l", "--latency", dest="latency", action="store_true",
+ help="Produce latency profile")
+ parser.add_option("-d", "--distribution", dest="distribution", action="store_true",
+ help="Produce distribution of FOPs")
+ parser.add_option("-w", "--workload", dest="workload", action="store_true",
+ help="Produce workload profile")
+ parser.add_option("-t", "--title", dest="title", help="Set the title of the graph")
+ parser.add_option("-x", "--xlator-order", dest="xlator_order", help="Specify the order of xlators")
+ parser.add_option("-m", "--mode", dest="mode", help="Output format, can be text[default] or graph")
+
+ (options, args) = parser.parse_args()
+
+ if len(args) != 1:
+ parser.error("Incorrect number of arguments")
+
+ if (options.xlator_order):
+ xlator_order = options.xlator_order.split()
+ else:
+ print "xlator order must be specified"
+ sys.exit(1)
+
+ collect_data(file (args[0], 'r'))
+
+ mode = 'text'
+ if (options.mode):
+ mode = options.mode
+ if options.mode == 'graph' and graph_available == False:
+ print "matplotlib not available, falling back to text mode"
+ mode = 'text'
+
+ if (options.latency):
+ latency_profile (options.title, xlator_order, mode)
+
+ if (options.distribution):
+ fop_distribution(options.title, xlator_order, mode)
+
+ if (options.workload):
+ workload_profile(options.title, xlator_order, mode)
+
+main ()
diff --git a/extras/prot_filter.py b/extras/prot_filter.py
new file mode 100755
index 000000000..7dccacf15
--- /dev/null
+++ b/extras/prot_filter.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python
+
+"""
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+"""
+
+"""
+ INSTRUCTIONS
+ Put this in /usr/lib64/glusterfs/$version/filter to have it run automatically,
+ or else you'll have to run it by hand every time you change the volume
+ configuration. Give it a list of volume names on which to enable the
+ protection functionality; it will deliberately ignore client volfiles for
+ other volumes, and all server volfiles. It *will* include internal client
+ volfiles such as those used for NFS or rebalance/self-heal; this is a
+ deliberate choice so that it will catch deletions from those sources as well.
+"""
+
+volume_list = [ "jdtest" ]
+
+import copy
+import string
+import sys
+import types
+
+class Translator:
+ def __init__ (self, name):
+ self.name = name
+ self.xl_type = ""
+ self.opts = {}
+ self.subvols = []
+ self.dumped = False
+ def __repr__ (self):
+ return "<Translator %s>" % self.name
+
+def load (path):
+ # If it's a string, open it; otherwise, assume it's already a
+ # file-like object (most notably from urllib*).
+ if type(path) in types.StringTypes:
+ fp = file(path,"r")
+ else:
+ fp = path
+ all_xlators = {}
+ xlator = None
+ last_xlator = None
+ while True:
+ text = fp.readline()
+ if text == "":
+ break
+ text = text.split()
+ if not len(text):
+ continue
+ if text[0] == "volume":
+ if xlator:
+ raise RuntimeError, "nested volume definition"
+ xlator = Translator(text[1])
+ continue
+ if not xlator:
+ raise RuntimeError, "text outside volume definition"
+ if text[0] == "type":
+ xlator.xl_type = text[1]
+ continue
+ if text[0] == "option":
+ xlator.opts[text[1]] = string.join(text[2:])
+ continue
+ if text[0] == "subvolumes":
+ for sv in text[1:]:
+ xlator.subvols.append(all_xlators[sv])
+ continue
+ if text[0] == "end-volume":
+ all_xlators[xlator.name] = xlator
+ last_xlator = xlator
+ xlator = None
+ continue
+ raise RuntimeError, "unrecognized keyword %s" % text[0]
+ if xlator:
+ raise RuntimeError, "unclosed volume definition"
+ return all_xlators, last_xlator
+
+def generate (graph, last, stream=sys.stdout):
+ for sv in last.subvols:
+ if not sv.dumped:
+ generate(graph,sv,stream)
+ print >> stream, ""
+ sv.dumped = True
+ print >> stream, "volume %s" % last.name
+ print >> stream, " type %s" % last.xl_type
+ for k, v in last.opts.iteritems():
+ print >> stream, " option %s %s" % (k, v)
+ if last.subvols:
+ print >> stream, " subvolumes %s" % string.join(
+ [ sv.name for sv in last.subvols ])
+ print >> stream, "end-volume"
+
+def push_filter (graph, old_xl, filt_type, opts={}):
+ new_type = "-" + filt_type.split("/")[1]
+ old_type = "-" + old_xl.xl_type.split("/")[1]
+ pos = old_xl.name.find(old_type)
+ if pos >= 0:
+ new_name = old_xl.name
+ old_name = new_name[:pos] + new_type + new_name[len(old_type)+pos:]
+ else:
+ new_name = old_xl.name + old_type
+ old_name = old_xl.name + new_type
+ new_xl = Translator(new_name)
+ new_xl.xl_type = old_xl.xl_type
+ new_xl.opts = old_xl.opts
+ new_xl.subvols = old_xl.subvols
+ graph[new_xl.name] = new_xl
+ old_xl.name = old_name
+ old_xl.xl_type = filt_type
+ old_xl.opts = opts
+ old_xl.subvols = [new_xl]
+ graph[old_xl.name] = old_xl
+
+if __name__ == "__main__":
+ path = sys.argv[1]
+ # Alow an override for debugging.
+ for extra in sys.argv[2:]:
+ volume_list.append(extra)
+ graph, last = load(path)
+ for v in volume_list:
+ if graph.has_key(v):
+ break
+ else:
+ print "No configured volumes found - aborting."
+ sys.exit(0)
+ for v in graph.values():
+ if v.xl_type == "cluster/distribute":
+ push_filter(graph,v,"features/prot_dht")
+ elif v.xl_type == "protocol/client":
+ push_filter(graph,v,"features/prot_client")
+ # We push debug/trace so that every fop gets a real frame, because DHT
+ # gets confused if STACK_WIND_TAIL causes certain fops to be invoked
+ # from anything other than a direct child.
+ for v in graph.values():
+ if v.xl_type == "features/prot_client":
+ push_filter(graph,v,"debug/trace")
+ generate(graph,last,stream=open(path,"w"))
diff --git a/extras/quota-metadata-cleanup.sh b/extras/quota-metadata-cleanup.sh
new file mode 100755
index 000000000..37ad8bc31
--- /dev/null
+++ b/extras/quota-metadata-cleanup.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# This script is used to cleanup xattrs setup by quota-translator in (a)
+# backend directory(ies). It takes a single or list of backend directories
+# as argument(s).
+
+usage ()
+{
+ echo >&2 "usage: $0 <list-of-backend-directories>"
+}
+
+main ()
+{
+ [ $# -lt 1 ] && usage
+
+ INSTALL_DIR=`dirname $0`
+
+ for i in $@; do
+ find $i -exec $INSTALL_DIR/quota-remove-xattr.sh '{}' \;
+ done
+
+}
+
+main $@
diff --git a/extras/quota-remove-xattr.sh b/extras/quota-remove-xattr.sh
new file mode 100755
index 000000000..7191f9bd4
--- /dev/null
+++ b/extras/quota-remove-xattr.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# This script is used to remove xattrs set by quota translator on a path.
+# It is generally invoked from quota-metadata-cleanup.sh, but can
+# also be used stand-alone.
+
+usage ()
+{
+ echo >&2 "usage: $0 <path>"
+}
+
+main ()
+{
+ [ $# -ne 1 ] && usage $0
+
+ XATTR_KEY_VALUE_PAIRS=`getfattr -h -d -m 'trusted.glusterfs.quota' $1 2>/dev/null | sed -e '/^# file/d'`
+
+ for i in $XATTR_KEY_VALUE_PAIRS; do
+ XATTR_KEY=`echo $i | sed -e 's/\([^=]*\).*/\1/g'`
+ setfattr -h -x $XATTR_KEY $1
+ done
+}
+
+main $@
diff --git a/extras/rebalance.py b/extras/rebalance.py
new file mode 100755
index 000000000..80c614c5d
--- /dev/null
+++ b/extras/rebalance.py
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+
+import atexit
+import copy
+import optparse
+import os
+import pipes
+import shutil
+import string
+import subprocess
+import sys
+import tempfile
+import volfilter
+
+# It's just more convenient to have named fields.
+class Brick:
+ def __init__ (self, path, name):
+ self.path = path
+ self.sv_name = name
+ self.size = 0
+ self.curr_size = 0
+ self.good_size = 0
+ def set_size (self, size):
+ self.size = size
+ def set_range (self, rs, re):
+ self.r_start = rs
+ self.r_end = re
+ self.curr_size = self.r_end - self.r_start + 1
+ def __repr__ (self):
+ value = self.path[:]
+ value += "(%d," % self.size
+ if self.curr_size:
+ value += "0x%x,0x%x)" % (self.r_start, self.r_end)
+ else:
+ value += "-)"
+ return value
+
+def get_bricks (host, vol):
+ t = pipes.Template()
+ t.prepend("gluster --remote-host=%s system getspec %s"%(host,vol),".-")
+ return t.open(None,"r")
+
+def generate_stanza (vf, all_xlators, cur_subvol):
+ sv_list = []
+ for sv in cur_subvol.subvols:
+ generate_stanza(vf,all_xlators,sv)
+ sv_list.append(sv.name)
+ vf.write("volume %s\n"%cur_subvol.name)
+ vf.write(" type %s\n"%cur_subvol.type)
+ for kvpair in cur_subvol.opts.iteritems():
+ vf.write(" option %s %s\n"%kvpair)
+ if sv_list:
+ vf.write(" subvolumes %s\n"%string.join(sv_list))
+ vf.write("end-volume\n\n")
+
+
+def mount_brick (localpath, all_xlators, dht_subvol):
+
+ # Generate a volfile.
+ vf_name = localpath + ".vol"
+ vf = open(vf_name,"w")
+ generate_stanza(vf,all_xlators,dht_subvol)
+ vf.flush()
+ vf.close()
+
+ # Create a brick directory and mount the brick there.
+ os.mkdir(localpath)
+ subprocess.call(["glusterfs","-f",vf_name,localpath])
+
+# We use the command-line tools because there's no getxattr support in the
+# Python standard library (which is ridiculous IMO). Adding the xattr package
+# from PyPI would create a new and difficult dependency because the bits to
+# satisfy it don't seem to exist in Fedora. We already expect the command-line
+# tools to be there, so it's safer just to rely on them.
+#
+# We might have to revisit this if we get as far as actually issuing millions
+# of setxattr requests. Even then, it might be better to do that part with a C
+# program which has only a build-time dependency.
+def get_range (brick):
+ t = pipes.Template()
+ cmd = "getfattr -e hex -n trusted.glusterfs.dht %s 2> /dev/null"
+ t.prepend(cmd%brick,".-")
+ t.append("grep ^trusted.glusterfs.dht=","--")
+ f = t.open(None,"r")
+ try:
+ value = f.readline().rstrip().split('=')[1][2:]
+ except:
+ print "could not get layout for %s (might be OK)" % brick
+ return None
+ v_start = int("0x"+value[16:24],16)
+ v_end = int("0x"+value[24:32],16)
+ return (v_start, v_end)
+
+def calc_sizes (bricks, total):
+ leftover = 1 << 32
+ for b in bricks:
+ if b.size:
+ b.good_size = (b.size << 32) / total
+ leftover -= b.good_size
+ else:
+ b.good_size = 0
+ if leftover:
+ # Add the leftover to an old brick if we can.
+ for b in bricks:
+ if b.good_size:
+ b.good_size += leftover
+ break
+ else:
+ # Fine, just add it wherever.
+ bricks[0].good_size += leftover
+
+# Normalization means sorting the bricks by r_start and (b) ensuring that there
+# are no gaps.
+def normalize (in_bricks):
+ out_bricks = []
+ curr_hash = 0
+ used = 0
+ while curr_hash < (1<<32):
+ curr_best = None
+ for b in in_bricks:
+ if b.r_start == curr_hash:
+ used += 1
+ out_bricks.append(b)
+ in_bricks.remove(b)
+ curr_hash = b.r_end + 1
+ break
+ else:
+ print "gap found at 0x%08x" % curr_hash
+ sys.exit(1)
+ return out_bricks + in_bricks, used
+
+def get_score (bricks):
+ score = 0
+ curr_hash = 0
+ for b in bricks:
+ if not b.curr_size:
+ curr_hash += b.good_size
+ continue
+ new_start = curr_hash
+ curr_hash += b.good_size
+ new_end = curr_hash - 1
+ if new_start > b.r_start:
+ max_start = new_start
+ else:
+ max_start = b.r_start
+ if new_end < b.r_end:
+ min_end = new_end
+ else:
+ min_end = b.r_end
+ if max_start <= min_end:
+ score += (min_end - max_start + 1)
+ return score
+
+if __name__ == "__main__":
+
+ my_usage = "%prog [options] server volume [directory]"
+ parser = optparse.OptionParser(usage=my_usage)
+ parser.add_option("-f", "--free-space", dest="free_space",
+ default=False, action="store_true",
+ help="use free space instead of total space")
+ parser.add_option("-l", "--leave-mounted", dest="leave_mounted",
+ default=False, action="store_true",
+ help="leave subvolumes mounted")
+ parser.add_option("-v", "--verbose", dest="verbose",
+ default=False, action="store_true",
+ help="verbose output")
+ options, args = parser.parse_args()
+
+ if len(args) == 3:
+ fix_dir = args[2]
+ else:
+ if len(args) != 2:
+ parser.print_help()
+ sys.exit(1)
+ fix_dir = None
+ hostname, volname = args[:2]
+
+ # Make sure stuff gets cleaned up, even if there are exceptions.
+ orig_dir = os.getcwd()
+ work_dir = tempfile.mkdtemp()
+ bricks = []
+ def cleanup_workdir ():
+ os.chdir(orig_dir)
+ if options.verbose:
+ print "Cleaning up %s" % work_dir
+ for b in bricks:
+ subprocess.call(["umount",b.path])
+ shutil.rmtree(work_dir)
+ if not options.leave_mounted:
+ atexit.register(cleanup_workdir)
+ os.chdir(work_dir)
+
+ # Mount each brick individually, so we can issue brick-specific calls.
+ if options.verbose:
+ print "Mounting subvolumes..."
+ index = 0
+ volfile_pipe = get_bricks(hostname,volname)
+ all_xlators, last_xlator = volfilter.load(volfile_pipe)
+ for dht_vol in all_xlators.itervalues():
+ if dht_vol.type == "cluster/distribute":
+ break
+ else:
+ print "no DHT volume found"
+ sys.exit(1)
+ for sv in dht_vol.subvols:
+ #print "found subvol %s" % sv.name
+ lpath = "%s/brick%s" % (work_dir, index)
+ index += 1
+ mount_brick(lpath,all_xlators,sv)
+ bricks.append(Brick(lpath,sv.name))
+ if index == 0:
+ print "no bricks"
+ sys.exit(1)
+
+ # Collect all of the sizes.
+ if options.verbose:
+ print "Collecting information..."
+ total = 0
+ for b in bricks:
+ info = os.statvfs(b.path)
+ # We want a standard unit even if different bricks use
+ # different block sizes. The size is chosen to avoid overflows
+ # for very large bricks with very small block sizes, but also
+ # accommodate filesystems which use very large block sizes to
+ # cheat on benchmarks.
+ blocksper100mb = 104857600 / info[0]
+ if options.free_space:
+ size = info[3] / blocksper100mb
+ else:
+ size = info[2] / blocksper100mb
+ if size <= 0:
+ print "brick %s has invalid size %d" % (b.path, size)
+ sys.exit(1)
+ b.set_size(size)
+ total += size
+
+ # Collect all of the layout information.
+ for b in bricks:
+ hash_range = get_range(b.path)
+ if hash_range is not None:
+ rs, re = hash_range
+ if rs > re:
+ print "%s has backwards hash range" % b.path
+ sys.exit(1)
+ b.set_range(hash_range[0],hash_range[1])
+
+ if options.verbose:
+ print "Calculating new layouts..."
+ calc_sizes(bricks,total)
+ bricks, used = normalize(bricks)
+
+ # We can't afford O(n!) here, but O(n^2) should be OK and the result
+ # should be almost as good.
+ while used < len(bricks):
+ best_place = used
+ best_score = get_score(bricks)
+ for i in xrange(used):
+ new_bricks = bricks[:]
+ del new_bricks[used]
+ new_bricks.insert(i,bricks[used])
+ new_score = get_score(new_bricks)
+ if new_score > best_score:
+ best_place = i
+ best_score = new_score
+ if best_place != used:
+ nb = bricks[used]
+ del bricks[used]
+ bricks.insert(best_place,nb)
+ used += 1
+
+ # Finalize whatever we decided on.
+ curr_hash = 0
+ for b in bricks:
+ b.r_start = curr_hash
+ curr_hash += b.good_size
+ b.r_end = curr_hash - 1
+
+ print "Here are the xattr values for your size-weighted layout:"
+ for b in bricks:
+ print " %s: 0x0000000200000000%08x%08x" % (
+ b.sv_name, b.r_start, b.r_end)
+
+ if fix_dir:
+ if options.verbose:
+ print "Fixing layout for %s" % fix_dir
+ for b in bricks:
+ value = "0x0000000200000000%08x%08x" % (
+ b.r_start, b.r_end)
+ path = "%s/%s" % (b.path, fix_dir)
+ cmd = "setfattr -n trusted.glusterfs.dht -v %s %s" % (
+ value, path)
+ print cmd
+
+ if options.leave_mounted:
+ print "The following subvolumes are still mounted:"
+ for b in bricks:
+ print "%s on %s" % (b.sv_name, b.path)
+ print "Don't forget to clean up when you're done."
+
diff --git a/extras/rpc-coverage.sh b/extras/rpc-coverage.sh
new file mode 100755
index 000000000..9148a73e2
--- /dev/null
+++ b/extras/rpc-coverage.sh
@@ -0,0 +1,480 @@
+#!/bin/bash
+
+# This script can be used to provoke 35 fops (if afr is used),
+# 28 fops (if afr is not used) (-fstat,-readdirp, and lk,xattrop calls)
+# Pending are 7 procedures.
+# getspec, fsyncdir, access, fentrylk, fsetxattr, fgetxattr, rchecksum
+# TODO: add commands which can generate fops for missing fops
+
+## Script tests below File Operations over RPC (when afr is used)
+
+# CREATE
+# ENTRYLK
+# FINODELK
+# FLUSH
+# FSTAT
+# FSYNC
+# FTRUNCATE
+# FXATTROP
+# GETXATTR
+# INODELK
+# LINK
+# LK
+# LOOKUP
+# MKDIR
+# MKNOD
+# OPEN
+# OPENDIR
+# READ
+# READDIR
+# READDIRP
+# READLINK
+# RELEASE
+# RELEASEDIR
+# REMOVEXATTR
+# RENAME
+# RMDIR
+# SETATTR
+# SETXATTR
+# STAT
+# STATFS
+# SYMLINK
+# TRUNCATE
+# UNLINK
+# WRITE
+# XATTROP
+
+#set -e;
+set -o pipefail;
+
+function fail() {
+ echo "$*: failed.";
+ exit 1;
+}
+
+function test_mkdir()
+{
+ mkdir -p $PFX/dir;
+ test $(stat -c '%F' $PFX/dir) == "directory" || fail "mkdir"
+}
+
+
+function test_create()
+{
+ : > $PFX/dir/file;
+
+ test "$(stat -c '%F' $PFX/dir/file)" == "regular empty file" || fail "create"
+}
+
+
+function test_statfs()
+{
+ local size;
+
+ size=$(stat -f -c '%s' $PFX/dir/file);
+ test "x$size" != "x0" || fail "statfs"
+}
+
+
+function test_open()
+{
+ exec 4<$PFX/dir/file || fail "open"
+ exec 4>&- || fail "open"
+}
+
+
+function test_write()
+{
+ dd if=/dev/zero of=$PFX/dir/file bs=65536 count=16 2>/dev/null;
+ test $(stat -c '%s' $PFX/dir/file) == 1048576 || fail "open"
+}
+
+
+function test_read()
+{
+ local count;
+
+ count=$(dd if=$PFX/dir/file bs=64k count=16 2>/dev/null | wc -c);
+ test $count == 1048576 || fail "read"
+}
+
+
+function test_truncate()
+{
+ truncate -s 512 $PFX/dir/file;
+ test $(stat -c '%s' $PFX/dir/file) == 512 || fail "truncate"
+
+ truncate -s 0 $PFX/dir/file;
+ test $(stat -c '%s' $PFX/dir/file) == 0 || fail "truncate"
+}
+
+
+function test_fstat()
+{
+ local msg;
+
+ export PFX;
+ msg=$(sh -c 'tail -f $PFX/dir/file --pid=$$ & sleep 1 && echo hooha > $PFX/dir/file && sleep 1');
+ test "x$msg" == "xhooha" || fail "fstat"
+}
+
+
+function test_mknod()
+{
+ mknod -m 0666 $PFX/dir/block b 13 42;
+ test "$(stat -c '%F %a %t %T' $PFX/dir/block)" == "block special file 666 d 2a" \
+ || fail "mknod for block device"
+
+ mknod -m 0666 $PFX/dir/char c 13 42;
+ test "$(stat -c '%F %a %t %T' $PFX/dir/char)" == "character special file 666 d 2a" \
+ || fail "mknod for character device"
+
+ mknod -m 0666 $PFX/dir/fifo p;
+ test "$(stat -c '%F %a' $PFX/dir/fifo)" == "fifo 666" || \
+ fail "mknod for fifo"
+}
+
+
+function test_symlink()
+{
+ local msg;
+
+ ln -s $PFX/dir/file $PFX/dir/symlink;
+ test "$(stat -c '%F' $PFX/dir/symlink)" == "symbolic link" || fail "Creation of symlink"
+
+ msg=$(cat $PFX/dir/symlink);
+ test "x$msg" == "xhooha" || fail "Content match for symlink"
+}
+
+
+function test_hardlink()
+{
+ local ino1;
+ local ino2;
+ local nlink1;
+ local nlink2;
+ local msg;
+
+ ln $PFX/dir/file $PFX/dir/hardlink;
+
+ ino1=$(stat -c '%i' $PFX/dir/file);
+ nlink1=$(stat -c '%h' $PFX/dir/file);
+ ino2=$(stat -c '%i' $PFX/dir/hardlink);
+ nlink2=$(stat -c '%h' $PFX/dir/hardlink);
+
+ test $ino1 == $ino2 || fail "Inode comparison for hardlink"
+ test $nlink1 == 2 || fail "Link count for hardlink"
+ test $nlink2 == 2 || fail "Link count for hardlink"
+
+ msg=$(cat $PFX/dir/hardlink);
+
+ test "x$msg" == "xhooha" || fail "Content match for hardlinks"
+}
+
+
+function test_rename()
+{
+ local ino1;
+ local ino2;
+ local ino3;
+ local msg;
+
+ #### file
+
+ ino1=$(stat -c '%i' $PFX/dir/file);
+
+ mv $PFX/dir/file $PFX/dir/file2 || fail "mv"
+ msg=$(cat $PFX/dir/file2);
+ test "x$msg" == "xhooha" || fail "File contents comparison after mv"
+
+ ino2=$(stat -c '%i' $PFX/dir/file2);
+ test $ino1 == $ino2 || fail "Inode comparison after mv"
+
+ mv $PFX/dir/file2 $PFX/dir/file;
+ msg=$(cat $PFX/dir/file);
+ test "x$msg" == "xhooha" || fail "File contents comparison after mv"
+
+ ino3=$(stat -c '%i' $PFX/dir/file);
+ test $ino1 == $ino3 || fail "Inode comparison after mv"
+
+ #### dir
+
+ ino1=$(stat -c '%i' $PFX/dir);
+
+ mv $PFX/dir $PFX/dir2 || fail "Directory mv"
+ ino2=$(stat -c '%i' $PFX/dir2);
+ test $ino1 == $ino2 || fail "Inode comparison after directory mv"
+
+ mv $PFX/dir2 $PFX/dir || fail "Directory mv"
+ ino3=$(stat -c '%i' $PFX/dir);
+ test $ino1 == $ino3 || fail "Inode comparison after directory mv"
+}
+
+
+function test_chmod()
+{
+ local mode0;
+ local mode1;
+ local mode2;
+
+
+ #### file
+
+ mode0=$(stat -c '%a' $PFX/dir/file);
+ chmod 0753 $PFX/dir/file || fail "chmod"
+
+ mode1=$(stat -c '%a' $PFX/dir/file);
+ test 0$mode1 == 0753 || fail "Mode comparison after chmod"
+
+ chmod 0$mode0 $PFX/dir/file || fail "chmod"
+ mode2=$(stat -c '%a' $PFX/dir/file);
+ test 0$mode2 == 0$mode0 || fail "Mode comparison after chmod"
+
+ #### dir
+
+ mode0=$(stat -c '%a' $PFX/dir);
+ chmod 0753 $PFX/dir || fail "chmod"
+
+ mode1=$(stat -c '%a' $PFX/dir);
+ test 0$mode1 == 0753 || fail "Mode comparison after chmod"
+
+ chmod 0$mode0 $PFX/dir || fail "chmod"
+ mode2=$(stat -c '%a' $PFX/dir);
+ test 0$mode2 == 0$mode0 || fail "Mode comparison after chmod"
+}
+
+
+function test_chown()
+{
+ local user1;
+ local user2;
+ local group1;
+ local group2;
+
+ #### file
+
+ user1=$(stat -c '%u' $PFX/dir/file);
+ group1=$(stat -c '%g' $PFX/dir/file);
+
+ chown 13:42 $PFX/dir/file || fail "chown"
+
+ user2=$(stat -c '%u' $PFX/dir/file);
+ group2=$(stat -c '%g' $PFX/dir/file);
+
+ test $user2 == 13 || fail "User comparison after chown"
+ test $group2 == 42 || fail "Group comparison after chown"
+
+ chown $user1:$group1 $PFX/dir/file || fail "chown"
+
+ user2=$(stat -c '%u' $PFX/dir/file);
+ group2=$(stat -c '%g' $PFX/dir/file);
+
+ test $user2 == $user1 || fail "User comparison after chown"
+ test $group2 == $group1 || fail "Group comparison after chown"
+
+ #### dir
+
+ user1=$(stat -c '%u' $PFX/dir);
+ group1=$(stat -c '%g' $PFX/dir);
+
+ chown 13:42 $PFX/dir || fail "chown"
+
+ user2=$(stat -c '%u' $PFX/dir);
+ group2=$(stat -c '%g' $PFX/dir);
+
+ test $user2 == 13 || fail "User comparison after chown"
+ test $group2 == 42 || fail "Group comparison after chown"
+
+ chown $user1:$group1 $PFX/dir || fail "chown"
+
+ user2=$(stat -c '%u' $PFX/dir);
+ group2=$(stat -c '%g' $PFX/dir);
+
+ test $user2 == $user1 || fail "User comparison after chown"
+ test $group2 == $group1 || fail "Group comparison after chown"
+}
+
+
+function test_utimes()
+{
+ local acc0;
+ local acc1;
+ local acc2;
+ local mod0;
+ local mod1;
+ local mod2;
+
+ #### file
+
+ acc0=$(stat -c '%X' $PFX/dir/file);
+ mod0=$(stat -c '%Y' $PFX/dir/file);
+
+ sleep 1;
+ touch -a $PFX/dir/file || fail "atime change on file"
+
+ acc1=$(stat -c '%X' $PFX/dir/file);
+ mod1=$(stat -c '%Y' $PFX/dir/file);
+
+ sleep 1;
+ touch -m $PFX/dir/file || fail "mtime change on file"
+
+ acc2=$(stat -c '%X' $PFX/dir/file);
+ mod2=$(stat -c '%Y' $PFX/dir/file);
+
+ test $acc0 != $acc1 || fail "atime mismatch comparison on file"
+ test $acc1 == $acc2 || fail "atime match comparison on file"
+ test $mod0 == $mod1 || fail "mtime match comparison on file"
+ test $mod1 != $mod2 || fail "mtime mismatch comparison on file"
+
+ #### dir
+
+ acc0=$(stat -c '%X' $PFX/dir);
+ mod0=$(stat -c '%Y' $PFX/dir);
+
+ sleep 1;
+ touch -a $PFX/dir || fail "atime change on directory"
+
+ acc1=$(stat -c '%X' $PFX/dir);
+ mod1=$(stat -c '%Y' $PFX/dir);
+
+ sleep 1;
+ touch -m $PFX/dir || fail "mtime change on directory"
+
+ acc2=$(stat -c '%X' $PFX/dir);
+ mod2=$(stat -c '%Y' $PFX/dir);
+
+ test $acc0 != $acc1 || fail "atime mismatch comparison on directory"
+ test $acc1 == $acc2 || fail "atime match comparison on directory"
+ test $mod0 == $mod1 || fail "mtime match comparison on directory"
+ test $mod1 != $mod2 || fail "mtime mismatch comparison on directory"
+}
+
+
+function test_locks()
+{
+ exec 200>$PFX/dir/lockfile || fail "exec"
+
+ ## exclusive locks test
+ flock -e 200 || fail "flock -e"
+ ! flock -n -e $PFX/dir/lockfile -c true || fail "! flock -n -e"
+ ! flock -n -s $PFX/dir/lockfile -c true || fail "! flock -n -s"
+ flock -u 200 || fail "flock -u"
+
+ ## shared locks test
+ flock -s 200 || fail "flock -s"
+ ! flock -n -e $PFX/dir/lockfile -c true || fail "! flock -n -e"
+ flock -n -s $PFX/dir/lockfile -c true || fail "! flock -n -s"
+ flock -u 200 || fail "flock -u"
+
+ exec 200>&- || fail "exec"
+
+}
+
+
+function test_readdir()
+{
+ /bin/ls $PFX/dir >/dev/null || fail "ls"
+}
+
+
+function test_setxattr()
+{
+ setfattr -n trusted.testing -v c00k33 $PFX/dir/file || fail "setfattr"
+}
+
+
+function test_listxattr()
+{
+ getfattr -m trusted $PFX/dir/file 2>/dev/null | grep -q trusted.testing || fail "getfattr"
+}
+
+
+function test_getxattr()
+{
+ getfattr -n trusted.testing $PFX/dir/file 2>/dev/null | grep -q c00k33 || fail "getfattr"
+}
+
+
+function test_removexattr()
+{
+ setfattr -x trusted.testing $PFX/dir/file || fail "setfattr remove"
+ getfattr -n trusted.testing $PFXf/dir/file 2>&1 | grep -q "No such attribute"
+}
+
+
+function test_unlink()
+{
+ rm $PFX/dir/file || fail "rm"
+}
+
+
+function test_rmdir()
+{
+ rm -rf $PFX || fail "rm -rf"
+}
+
+
+function run_tests()
+{
+ test_mkdir;
+ test_create;
+ test_statfs;
+ test_open;
+ test_write;
+ test_read;
+ test_truncate;
+ test_fstat;
+ test_mknod;
+ test_hardlink;
+ test_symlink;
+ test_rename;
+ test_chmod;
+ test_chown;
+ test_utimes;
+ test_locks;
+ test_readdir;
+ test_setxattr;
+ test_listxattr;
+ test_getxattr;
+ test_removexattr;
+ test_unlink;
+ test_rmdir;
+}
+
+
+function _init()
+{
+ DIR=$(pwd);
+}
+
+
+function parse_cmdline()
+{
+ if [ "x$1" == "x" ] ; then
+ echo "Usage: $0 /path/mount"
+ exit 1
+ fi
+
+ DIR=$1;
+
+ if [ ! -d "$DIR" ] ; then
+ echo "$DIR: not a directory"
+ exit 1
+ fi
+
+ PFX="$DIR/coverage";
+ rm -rvf $PFX;
+}
+
+
+function main()
+{
+ parse_cmdline "$@";
+
+ run_tests;
+
+ exit 0;
+}
+
+
+_init && main "$@";
diff --git a/extras/specgen.scm b/extras/specgen.scm
index 32aff6480..0edbb6f62 100755
--- a/extras/specgen.scm
+++ b/extras/specgen.scm
@@ -1,7 +1,7 @@
#!/usr/bin/guile -s
!#
-;;; Copyright (C) 2007-2009 Z RESEARCH Inc. <http://www.zresearch.com>
+;;; Copyright (c) 2007-2011 Gluster Inc. <http://www.gluster.com>
;;;
;;; 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
diff --git a/extras/stripe-merge.c b/extras/stripe-merge.c
index 3f8e4b124..74bd47e30 100644
--- a/extras/stripe-merge.c
+++ b/extras/stripe-merge.c
@@ -1,48 +1,494 @@
+/*
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+/*
+ * stripe-merge.c
+ *
+ * This program recovers an original file based on the striped files stored on
+ * the individual bricks of a striped volume. The file format and stripe
+ * geometry is validated through the extended attributes stored in the file.
+ *
+ * TODO: Support optional xattr recovery (i.e., user xattrs). Perhaps provide a
+ * command-line flag to toggle this behavior.
+ */
+
#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <attr/xattr.h>
+#include <fnmatch.h>
-int
-main (int argc, char *argv[])
+#define ATTRNAME_STRIPE_INDEX "trusted.*.stripe-index"
+#define ATTRNAME_STRIPE_COUNT "trusted.*.stripe-count"
+#define ATTRNAME_STRIPE_SIZE "trusted.*.stripe-size"
+#define ATTRNAME_STRIPE_COALESCE "trusted.*.stripe-coalesce"
+
+#define INVALID_FD -1
+#define INVALID_MODE UINT32_MAX
+
+struct file_stripe_info {
+ int stripe_count;
+ int stripe_size;
+ int coalesce;
+ mode_t mode;
+ int fd[0];
+};
+
+static int close_files(struct file_stripe_info *);
+
+static struct
+file_stripe_info *alloc_file_stripe_info(int count)
{
- int fds[argc-1];
- char buf[argc-1][4096];
int i;
- int max_ret, ret;
+ struct file_stripe_info *finfo;
- if (argc < 2) {
- printf ("Usage: %s file1 file2 ... >file\n", argv[0]);
- return 1;
+ finfo = calloc(1, sizeof(struct file_stripe_info) +
+ (sizeof(int) * count));
+ if (!finfo)
+ return NULL;
+
+ for (i = 0; i < count; i++)
+ finfo->fd[i] = INVALID_FD;
+
+ finfo->mode = INVALID_MODE;
+ finfo->coalesce = INVALID_FD;
+
+ return finfo;
+}
+
+/*
+ * Search for an attribute matching the provided pattern. Return a count for
+ * the total number of matching entries (including 0). Allocate a buffer for
+ * the first matching entry found.
+ */
+static int
+get_stripe_attr_name(const char *path, const char *pattern, char **attrname)
+{
+ char attrbuf[4096];
+ char *ptr, *match = NULL;
+ int len, r, match_count = 0;
+
+ if (!path || !pattern || !attrname)
+ return -1;
+
+ len = listxattr(path, attrbuf, sizeof(attrbuf));
+ if (len < 0)
+ return len;
+
+ ptr = attrbuf;
+ while (ptr) {
+ r = fnmatch(pattern, ptr, 0);
+ if (!r) {
+ if (!match)
+ match = ptr;
+ match_count++;
+ } else if (r != FNM_NOMATCH) {
+ return -1;
+ }
+
+ len -= strlen(ptr) + 1;
+ if (len > 0)
+ ptr += strlen(ptr) + 1;
+ else
+ ptr = NULL;
}
- for (i=0; i<argc-1; i++) {
- fds[i] = open (argv[i+1], O_RDONLY);
- if (fds[i] == -1) {
- perror (argv[i+1]);
- return 1;
+ if (match)
+ *attrname = strdup(match);
+
+ return match_count;
+}
+
+/*
+ * Get the integer representation of a named attribute.
+ */
+static int
+get_stripe_attr_val(const char *path, const char *attr, int *val)
+{
+ char attrbuf[4096];
+ int len;
+
+ if (!path || !attr || !val)
+ return -1;
+
+ len = getxattr(path, attr, attrbuf, sizeof(attrbuf));
+ if (len < 0)
+ return len;
+
+ *val = atoi(attrbuf);
+
+ return 0;
+}
+
+/*
+ * Get an attribute name/value (assumed to be an integer) pair based on a
+ * specified search pattern. A buffer is allocated for the exact attr name
+ * returned. Optionally, skip the pattern search if a buffer is provided
+ * (which should contain an attribute name).
+ *
+ * Returns the attribute count or -1 on error. The value parameter is set only
+ * when a single attribute is found.
+ */
+static int
+get_attr(const char *path, const char *pattern, char **buf, int *val)
+{
+ int count = 1;
+
+ if (!buf)
+ return -1;
+
+ if (!*buf) {
+ count = get_stripe_attr_name(path, pattern, buf);
+ if (count > 1) {
+ /* pattern isn't good enough */
+ fprintf(stderr, "ERROR: duplicate attributes found "
+ "matching pattern: %s\n", pattern);
+ free(*buf);
+ *buf = NULL;
+ return count;
+ } else if (count < 1) {
+ return count;
}
}
- max_ret = 0;
+ if (get_stripe_attr_val(path, *buf, val) < 0)
+ return -1;
+
+ return count;
+}
+
+/*
+ * validate_and_open_files()
+ *
+ * Open the provided source files and validate the extended attributes. Verify
+ * that the geometric attributes are consistent across all of the files and
+ * print a warning if any files are missing. We proceed without error in the
+ * latter case to support partial recovery.
+ */
+static struct
+file_stripe_info *validate_and_open_files(char *paths[], int count)
+{
+ int i, val, tmp;
+ struct stat sbuf;
+ char *stripe_count_attr = NULL;
+ char *stripe_size_attr = NULL;
+ char *stripe_index_attr = NULL;
+ char *stripe_coalesce_attr = NULL;
+ struct file_stripe_info *finfo = NULL;
+
+ for (i = 0; i < count; i++) {
+ if (!paths[i])
+ goto err;
+
+ /*
+ * Check the stripe count first so we can allocate the info
+ * struct with the appropriate number of fds.
+ */
+ if (get_attr(paths[i], ATTRNAME_STRIPE_COUNT,
+ &stripe_count_attr, &val) != 1) {
+ fprintf(stderr, "ERROR: %s: attribute: '%s'\n",
+ paths[i], ATTRNAME_STRIPE_COUNT);
+ goto err;
+ }
+ if (!finfo) {
+ finfo = alloc_file_stripe_info(val);
+ if (!finfo)
+ goto err;
+
+ if (val != count)
+ fprintf(stderr, "WARNING: %s: stripe-count "
+ "(%d) != file count (%d). Result may "
+ "be incomplete.\n", paths[i], val,
+ count);
+
+ finfo->stripe_count = val;
+ } else if (val != finfo->stripe_count) {
+ fprintf(stderr, "ERROR %s: invalid stripe count: %d "
+ "(expected %d)\n", paths[i], val,
+ finfo->stripe_count);
+ goto err;
+ }
+
+ /*
+ * Get and validate the chunk size.
+ */
+ if (get_attr(paths[i], ATTRNAME_STRIPE_SIZE, &stripe_size_attr,
+ &val) != 1) {
+ fprintf(stderr, "ERROR: %s: attribute: '%s'\n",
+ paths[i], ATTRNAME_STRIPE_SIZE);
+ goto err;
+ }
+
+ if (!finfo->stripe_size) {
+ finfo->stripe_size = val;
+ } else if (val != finfo->stripe_size) {
+ fprintf(stderr, "ERROR: %s: invalid stripe size: %d "
+ "(expected %d)\n", paths[i], val,
+ finfo->stripe_size);
+ goto err;
+ }
+
+ /*
+ * stripe-coalesce is a backward compatible attribute. If the
+ * attribute does not exist, assume a value of zero for the
+ * traditional stripe format.
+ */
+ tmp = get_attr(paths[i], ATTRNAME_STRIPE_COALESCE,
+ &stripe_coalesce_attr, &val);
+ if (!tmp) {
+ val = 0;
+ } else if (tmp != 1) {
+ fprintf(stderr, "ERROR: %s: attribute: '%s'\n",
+ paths[i], ATTRNAME_STRIPE_COALESCE);
+ goto err;
+ }
+
+ if (finfo->coalesce == INVALID_FD) {
+ finfo->coalesce = val;
+ } else if (val != finfo->coalesce) {
+ fprintf(stderr, "ERROR: %s: invalid coalesce flag\n",
+ paths[i]);
+ goto err;
+ }
+
+ /*
+ * Get/validate the stripe index and open the file in the
+ * appropriate fd slot.
+ */
+ if (get_attr(paths[i], ATTRNAME_STRIPE_INDEX,
+ &stripe_index_attr, &val) != 1) {
+ fprintf(stderr, "ERROR: %s: attribute: '%s'\n",
+ paths[i], ATTRNAME_STRIPE_INDEX);
+ goto err;
+ }
+ if (finfo->fd[val] != INVALID_FD) {
+ fprintf(stderr, "ERROR: %s: duplicate stripe index: "
+ "%d\n", paths[i], val);
+ goto err;
+ }
+
+ finfo->fd[val] = open(paths[i], O_RDONLY);
+ if (finfo->fd[val] < 0)
+ goto err;
+
+ /*
+ * Get the creation mode for the file.
+ */
+ if (fstat(finfo->fd[val], &sbuf) < 0)
+ goto err;
+ if (finfo->mode == INVALID_MODE) {
+ finfo->mode = sbuf.st_mode;
+ } else if (sbuf.st_mode != finfo->mode) {
+ fprintf(stderr, "ERROR: %s: invalid mode\n", paths[i]);
+ goto err;
+ }
+ }
+
+ free(stripe_count_attr);
+ free(stripe_size_attr);
+ free(stripe_index_attr);
+ free(stripe_coalesce_attr);
+
+ return finfo;
+err:
+
+ free(stripe_count_attr);
+ free(stripe_size_attr);
+ free(stripe_index_attr);
+ free(stripe_coalesce_attr);
+
+ if (finfo) {
+ close_files(finfo);
+ free(finfo);
+ }
+
+ return NULL;
+}
+
+static int
+close_files(struct file_stripe_info *finfo)
+{
+ int i, ret;
+
+ if (!finfo)
+ return -1;
+
+ for (i = 0; i < finfo->stripe_count; i++) {
+ if (finfo->fd[i] == INVALID_FD)
+ continue;
+
+ ret = close(finfo->fd[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
+ * Generate the original file using files striped in the coalesced format.
+ * Data in the striped files is stored at a coalesced offset based on the
+ * stripe number.
+ *
+ * Walk through the finfo fds (which are already ordered) and and iteratively
+ * copy stripe_size bytes from the source files to the target file. If a source
+ * file is missing, seek past the associated stripe_size bytes in the target
+ * file.
+ */
+static int
+generate_file_coalesce(int target, struct file_stripe_info *finfo)
+{
+ char *buf;
+ int ret = 0;
+ int r, w, i;
+
+ buf = malloc(finfo->stripe_size);
+ if (!buf)
+ return -1;
+
+ i = 0;
+ while (1) {
+ if (finfo->fd[i] == INVALID_FD) {
+ if (lseek(target, finfo->stripe_size, SEEK_CUR) < 0)
+ break;
+
+ i = (i + 1) % finfo->stripe_count;
+ continue;
+ }
+
+ r = read(finfo->fd[i], buf, finfo->stripe_size);
+ if (r < 0) {
+ ret = r;
+ break;
+ }
+ if (!r)
+ break;
+
+ w = write(target, buf, r);
+ if (w < 0) {
+ ret = w;
+ break;
+ }
+
+ i = (i + 1) % finfo->stripe_count;
+ }
+
+ free(buf);
+ return ret;
+}
+
+/*
+ * Generate the original file using files striped with the traditional stripe
+ * format. Data in the striped files is stored at the equivalent offset from
+ * the source file.
+ */
+static int
+generate_file_traditional(int target, struct file_stripe_info *finfo)
+{
+ int i, j, max_ret, ret;
+ char buf[finfo->stripe_count][4096];
+
do {
char newbuf[4096] = {0, };
- int j;
max_ret = 0;
- for (i=0; i<argc-1; i++) {
- memset (buf[i], 0, 4096);
- ret = read (fds[i], buf[i], 4096);
+ for (i = 0; i < finfo->stripe_count; i++) {
+ memset(buf[i], 0, 4096);
+ ret = read(finfo->fd[i], buf[i], 4096);
if (ret > max_ret)
max_ret = ret;
}
- for (i=0; i<max_ret;i++)
- for (j=0; j<argc-1; j++)
+ for (i = 0; i < max_ret; i++)
+ for (j = 0; j < finfo->stripe_count; j++)
newbuf[i] |= buf[j][i];
- write (1, newbuf, max_ret);
+ write(target, newbuf, max_ret);
} while (max_ret);
return 0;
}
+static int
+generate_file(int target, struct file_stripe_info *finfo)
+{
+ if (finfo->coalesce)
+ return generate_file_coalesce(target, finfo);
+
+ return generate_file_traditional(target, finfo);
+}
+
+static void
+usage(char *name)
+{
+ fprintf(stderr, "Usage: %s [-o <outputfile>] <inputfile1> "
+ "<inputfile2> ...\n", name);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int file_count, opt;
+ char *opath = NULL;
+ int targetfd;
+ struct file_stripe_info *finfo;
+
+ while ((opt = getopt(argc, argv, "o:")) != -1) {
+ switch (opt) {
+ case 'o':
+ opath = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ return -1;
+ }
+ }
+
+ file_count = argc - optind;
+
+ if (!opath || !file_count) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ finfo = validate_and_open_files(&argv[optind], file_count);
+ if (!finfo)
+ goto err;
+
+ targetfd = open(opath, O_RDWR|O_CREAT, finfo->mode);
+ if (targetfd < 0)
+ goto err;
+
+ if (generate_file(targetfd, finfo) < 0)
+ goto err;
+
+ if (fsync(targetfd) < 0)
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ if (close(targetfd) < 0)
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+
+ close_files(finfo);
+ free(finfo);
+
+ return 0;
+
+err:
+ if (finfo) {
+ close_files(finfo);
+ free(finfo);
+ }
+
+ return -1;
+}
+
diff --git a/extras/systemd/Makefile.am b/extras/systemd/Makefile.am
new file mode 100644
index 000000000..3fc656b82
--- /dev/null
+++ b/extras/systemd/Makefile.am
@@ -0,0 +1,11 @@
+
+CLEANFILES =
+
+SYSTEMD_DIR = @systemddir@
+
+install-exec-local:
+ @if [ -d $(SYSTEMD_DIR) ]; then \
+ $(mkdir_p) $(DESTDIR)$(SYSTEMD_DIR); \
+ $(INSTALL_PROGRAM) glusterd.service $(DESTDIR)$(SYSTEMD_DIR)/; \
+ fi
+
diff --git a/extras/systemd/glusterd.service.in b/extras/systemd/glusterd.service.in
new file mode 100644
index 000000000..fc8d8c9a2
--- /dev/null
+++ b/extras/systemd/glusterd.service.in
@@ -0,0 +1,14 @@
+[Unit]
+Description=GlusterFS, a clustered file-system server
+After=network.target rpcbind.service
+Before=network-online.target
+
+[Service]
+Type=forking
+PIDFile=/run/glusterd.pid
+LimitNOFILE=65536
+ExecStart=@prefix@/sbin/glusterd -p /run/glusterd.pid
+KillMode=process
+
+[Install]
+WantedBy=multi-user.target
diff --git a/extras/test/bug-920583.t b/extras/test/bug-920583.t
new file mode 100755
index 000000000..eedbb800a
--- /dev/null
+++ b/extras/test/bug-920583.t
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+##Copy this file to tests/bugs before running run.sh (cp extras/test/bug-920583.t tests/bugs/)
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+
+cleanup;
+logdir=`gluster --print-logdir`
+
+## Start and create a volume
+TEST glusterd;
+TEST pidof glusterd;
+
+TEST $CLI volume create $V0 replica 2 stripe 2 $H0:$B0/${V0}{1,2,3,4,5,6,7,8};
+
+## Verify volume is is created
+EXPECT "$V0" volinfo_field $V0 'Volume Name';
+EXPECT 'Created' volinfo_field $V0 'Status';
+
+## Start volume and verify
+TEST $CLI volume start $V0;
+EXPECT 'Started' volinfo_field $V0 'Status';
+
+function log-file-name()
+{
+ logfilename=$M0".log"
+ echo ${logfilename:1} | tr / -
+}
+
+log_file=$logdir"/"`log-file-name`
+
+lookup_unhashed_count=`grep "adding option 'lookup-unhashed'" $log_file | wc -l`
+no_child_down_count=`grep "adding option 'assert-no-child-down'" $log_file | wc -l`
+mount -t glusterfs $H0:/$V0 $M0 -o "xlator-option=*dht.assert-no-child-down=yes,xlator-option=*dht.lookup-unhashed=yes"
+touch $M0/file1;
+
+new_lookup_unhashed_count=`grep "adding option 'lookup-unhashed'" $log_file | wc -l`
+new_no_child_down_count=`grep "adding option 'assert-no-child-down'" $log_file | wc -l`
+EXPECT "1" expr $new_lookup_unhashed_count - $lookup_unhashed_count
+EXPECT "1" expr $new_no_child_down_count - $no_child_down_count
+
+## Finish up
+TEST $CLI volume stop $V0;
+EXPECT 'Stopped' volinfo_field $V0 'Status';
+
+TEST $CLI volume delete $V0;
+TEST ! $CLI volume info $V0;
+
+cleanup;
diff --git a/extras/test/gluster_commands.sh b/extras/test/gluster_commands.sh
new file mode 100755
index 000000000..cb2a55fd5
--- /dev/null
+++ b/extras/test/gluster_commands.sh
@@ -0,0 +1,265 @@
+#!/bin/bash
+
+
+# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+# This file is part of GlusterFS.
+#
+# This file is licensed to you under your choice of the GNU Lesser
+# General Public License, version 3 or any later version (LGPLv3 or
+# later), or the GNU General Public License, version 2 (GPLv2), in all
+# cases as published by the Free Software Foundation.
+
+
+# This script tests the basics gluster cli commands.
+
+echo "Starting glusterd"
+glusterd
+if [ $? -ne 0 ]; then
+ echo "Could not start glusterd.Exiting"
+ exit;
+else
+ echo "glusterd started"
+fi
+
+if [ ! -d "/exports" ]; then
+ mkdir /exports;
+ mkdir /exports/exp{1..10};
+else
+ mkdir /exports/exp{1..10};
+fi
+
+if [ ! -d "/mnt/client" ]; then
+ mkdir /mnt/client -p;
+fi
+
+
+set -e #exit at the first error that happens
+
+# create distribute volume and try start, mount, add-brick, replace-brick, remove-brick, stop, unmount, delete
+
+echo "Creating distribute volume........"
+gluster volume create vol `hostname`:/exports/exp1
+gluster volume info
+
+echo "Starting distribute volume........"
+gluster volume start vol
+gluster volume info
+sleep 1
+mount -t glusterfs `hostname`:vol /mnt/client
+sleep 1
+df -h
+
+echo "adding-brick......."
+gluster volume add-brick vol `hostname`:/exports/exp2
+gluster volume info
+sleep 1
+umount /mnt/client
+mount -t glusterfs `hostname`:vol /mnt/client
+df -h
+sleep 1
+
+echo "replacing brick......"
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 status
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 pause
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 status
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 status
+gluster volume replace-brick vol `hostname`:/exports/exp1 `hostname`:/exports/exp3 commit
+
+
+echo "replcing brick for abort operation"
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 status
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 pause
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 status
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 status
+gluster volume replace-brick vol `hostname`:/exports/exp3 `hostname`:/exports/exp1 abort
+
+
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "removing brick......."
+gluster --mode=script volume remove-brick vol `hostname`:/exports/exp2
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "stopping distribute volume......"
+gluster --mode=script volume stop vol
+gluster volume info
+sleep 1
+umount /mnt/client
+df -h
+
+echo "deleting distribute volume......"
+gluster --mode=script volume delete vol
+gluster volume info
+sleep 1
+
+# create replicate volume and try start, mount, add-brick, replace-brick, remove-brick, stop, unmount, delete
+echo "creating replicate volume......"
+gluster volume create mirror replica 2 `hostname`:/exports/exp1 `hostname`:/exports/exp2
+gluster volume info
+sleep 1
+
+echo "starting replicate volume......"
+gluster volume start mirror
+gluster volume info
+sleep 1
+mount -t glusterfs `hostname`:mirror /mnt/client
+sleep 1
+df -h
+sleep 1
+
+echo "adding-brick......."
+gluster volume add-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "replacing-brick....."
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 pause
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick mirror `hostname`:/exports/exp1 `hostname`:/exports/exp5 commit
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "replacing brick for abort operation"
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 pause
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick mirror `hostname`:/exports/exp5 `hostname`:/exports/exp1 abort
+
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "removeing-brick....."
+gluster --mode=script volume remove-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "stopping replicate volume....."
+gluster --mode=script volume stop mirror
+gluster volume info
+sleep 1
+umount /mnt/client
+df -h
+
+echo "deleting replicate volume....."
+gluster --mode=script volume delete mirror
+gluster volume info
+sleep 1
+
+# create stripe volume and try start, mount, add-brick, replace-brick, remove-brick, stop, unmount, delete
+
+echo "creating stripe volume....."
+gluster volume create str stripe 2 `hostname`:/exports/exp1 `hostname`:/exports/exp2
+gluster volume info
+sleep 1
+
+echo "starting stripe volume....."
+gluster volume start str
+gluster volume info
+sleep 1
+mount -t glusterfs `hostname`:str /mnt/client
+sleep 1
+df -h
+sleep 1
+
+echo "adding brick...."
+gluster volume add-brick str `hostname`:/exports/exp3 `hostname`:/exports/exp4
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "replacing brick....."
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 pause
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 status
+gluster volume replace-brick str `hostname`:/exports/exp1 `hostname`:/exports/exp5 commit
+
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "replacing brick for abort operation"
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 pause
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 start
+#sleep for 5 seconds
+sleep 5
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 status
+gluster volume replace-brick str `hostname`:/exports/exp5 `hostname`:/exports/exp1 abort
+
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "removing-brick....."
+gluster --mode=script volume remove-brick str `hostname`:/exports/exp3 `hostname`:/exports/exp4
+gluster volume info
+sleep 1
+df -h
+sleep 1
+
+echo "stopping stripe volume....."
+gluster --mode=script volume stop str
+gluster volume info
+sleep 1
+umount /mnt/client
+df -h
+
+echo "deleting stripe volume....."
+gluster --mode=script volume delete str
+gluster volume info
+
diff --git a/extras/test/ld-preload-test/Makefile b/extras/test/ld-preload-test/Makefile
new file mode 100644
index 000000000..97aa01651
--- /dev/null
+++ b/extras/test/ld-preload-test/Makefile
@@ -0,0 +1,28 @@
+TOOL_CFLAGS32=-g -O0 -Wall
+TOOL_CFLAGS64=-g -O0 -D_GNU_SOURCE -Wall -D_FILE_OFFSET_BITS=64
+LIB_CFLAGS=-g -O0 -fPIC -Wall -shared -ldl
+%LIB_CFLAGS=-g -O0 -D_GNU_SOURCE -fPIC -Wall -shared -D_FILE_OFFSET_BITS=64 -ldl
+
+all: ld-preload-test32 ld-preload-test64 ld-preload-lib
+
+
+copy32:
+ cp ld-preload-test.c test32.c
+
+ld-preload-test32: copy32
+ gcc ${TOOL_CFLAGS32} test32.c -o ld-preload-test32
+ rm -f test32.c
+
+copy64:
+ cp ld-preload-test.c test64.c
+
+ld-preload-test64: copy64
+ gcc ${TOOL_CFLAGS64} test64.c -o ld-preload-test64
+ rm -f test64.c
+
+ld-preload-lib: ld-preload-lib.c
+ gcc ${LIB_CFLAGS} ld-preload-lib.c -o ld-preload-lib.so
+
+clean:
+ rm -f ld-preload-test32 ld-preload-test64 ld-preload-lib.so
+
diff --git a/extras/test/ld-preload-test/README b/extras/test/ld-preload-test/README
new file mode 100644
index 000000000..725b94023
--- /dev/null
+++ b/extras/test/ld-preload-test/README
@@ -0,0 +1,40 @@
+ld-preload-test
+===============
+1. The idea of this test tool is to check the sanity of the LD_PRELOAD
+mechanism in libc for the system on which booster needs to run.
+
+2. Basically, this test tool calls various system calls for which there is
+support in the booster library. Combined with the logging output from this
+tool and the preload-test-lib, one can determine whether the
+pre-loading mechanism is working working in order for booster to initialize.
+
+3. This tool does not test GlusterFS functionality running under booster
+although the path specified to the tool can be a GlusterFS mountpoint but
+that is not very useful.
+
+4. This tool is incomplete without the preload-test-lib and the
+accompanyung shell script that needs to be run for running the test.
+
+ld-preload-lib.so
+=================
+A very simple library that intercepts booster supported system calls
+and prints a log message to stdout.
+Combined with the ld-preload-test, we cam determine whether all system calls
+are getting redirected into this library when LD_PRELOAD'ed. This helps us
+conduct a basic test to ensure that the required syscalls actually will
+be intercepted by the booster library.
+
+
+Instructions
+============
+
+1. Build the binaries.
+ $ make
+
+(We've tested the tool on Debian and CentOS. If there are build errors or
+warnings, please do report them to glusterfs-devel@nongnu.org.)
+
+2. Run the test.
+ $ ./test-preload.sh > preload.log
+
+3. Mail the log to glusterfs-devel@nongnu.org.
diff --git a/extras/test/ld-preload-test/ld-preload-lib.c b/extras/test/ld-preload-test/ld-preload-lib.c
new file mode 100644
index 000000000..88afd14c3
--- /dev/null
+++ b/extras/test/ld-preload-test/ld-preload-lib.c
@@ -0,0 +1,627 @@
+/*
+ Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+/* LD PRELOAD'able library
+ * A very simple library that intercepts booster supported system calls
+ * and prints a log message to stdout.
+ *
+ * Combined with the ld-preload-test, we cam determine whether all system calls
+ * are getting redirected into this library when LD_PRELOAD'ed. This helps us
+ * conduct a basic test to ensure that the required syscalls actually will
+ * be intercepted by the booster library.
+ */
+
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <utime.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <attr/xattr.h>
+#include <sys/sendfile.h>
+
+/* Err number that is assigned to errno so that test application can
+ * verify that the function was intercepted correctly.
+ */
+#define PRELOAD_ERRNO_VERF 6449
+#define set_errno() (errno = PRELOAD_ERRNO_VERF)
+
+inline void
+intercept (char *call, int tabs)
+{
+ while (tabs > 0) {
+ fprintf (stdout, "\t");
+ --tabs;
+ }
+
+ fprintf (stdout, "Intercepted by %s", call);
+}
+
+int
+creat64 (const char *pathname, mode_t mode)
+{
+ intercept ("creat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+creat (const char *pathname, mode_t mode)
+{
+ intercept ("creat", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+close (int fd)
+{
+ intercept ("close", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+open64 (const char *pathname, int flags, ...)
+{
+ intercept ("open64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+open (const char *pathname, int flags, ...)
+{
+ intercept ("open", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+read (int fd, void *buf, size_t count)
+{
+ intercept ("read", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+readv (int fd, const struct iovec *vector, int count)
+{
+ intercept ("readv", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pread (int fd, void *buf, size_t count, unsigned long offset)
+{
+ intercept ("pread", 2);
+ set_errno ();
+ return -1;
+}
+
+
+ssize_t
+pread64 (int fd, void *buf, size_t count, uint64_t offset)
+{
+ intercept ("pread64", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+write (int fd, const void *buf, size_t count)
+{
+ intercept ("write", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+writev (int fd, const struct iovec *vector, int count)
+{
+ intercept ("writev", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pwrite (int fd, const void *buf, size_t count, unsigned long offset)
+{
+ intercept ("pwrite", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pwrite64 (int fd, const void *buf, size_t count, uint64_t offset)
+{
+ intercept ("pwrite64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+off_t
+lseek (int fildes, unsigned long offset, int whence)
+{
+ intercept ("lseek", 2);
+ set_errno ();
+ return -1;
+}
+
+off_t
+lseek64 (int fildes, uint64_t offset, int whence)
+{
+ intercept ("lseek64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+dup (int fd)
+{
+ intercept ("dup", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+dup2 (int oldfd, int newfd)
+{
+ intercept ("dup2", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+mkdir (const char *pathname, mode_t mode)
+{
+ intercept ("mkdir", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+rmdir (const char *pathname)
+{
+ intercept ("rmdir", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+chmod (const char *pathname, mode_t mode)
+{
+ intercept ("chmod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+chown (const char *pathname, uid_t owner, gid_t group)
+{
+ intercept ("chown", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fchmod (int fd, mode_t mode)
+{
+ intercept ("fchmod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fchown (int fd, uid_t uid, gid_t gid)
+{
+ intercept ("fchown", 2);
+ set_errno ();
+ return -1;
+}
+
+int fsync (int fd)
+{
+ intercept ("fsync", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+ftruncate (int fd, off_t length)
+{
+ intercept ("ftruncate", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+ftruncate64 (int fd, off_t length)
+{
+ intercept ("ftruncate64", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+link (const char *oldpath, const char *newname)
+{
+ intercept ("link", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+rename (const char *oldpath, const char *newpath)
+{
+ intercept ("rename", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+utimes (const char *path, const struct timeval times[2])
+{
+ intercept ("utimes", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+utime (const char *path, const struct utimbuf *buf)
+{
+ intercept ("utime", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+mknod (const char *path, mode_t mode, dev_t dev)
+{
+ intercept ("mknod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__xmknod (int ver, const char *path, mode_t mode, dev_t *dev)
+{
+ intercept ("__xmknod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+mkfifo (const char *path, mode_t mode)
+{
+ intercept ("mkfifo", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+unlink (const char *path)
+{
+ intercept ("unlink", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+symlink (const char *oldpath, const char *newpath)
+{
+ intercept ("symlink", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+readlink (const char *path, char *buf, size_t bufsize)
+{
+ intercept ("readlink", 1);
+ set_errno ();
+ return -1;
+}
+
+
+char *
+realpath (const char *path, char *resolved)
+{
+ intercept ("realpath", 1);
+ set_errno ();
+ return NULL;
+}
+
+
+DIR *
+opendir (const char *path)
+{
+ intercept ("opendir", 2);
+ set_errno ();
+ return NULL;
+}
+
+
+struct dirent *
+readdir (DIR *dir)
+{
+ intercept ("readdir\t", 2);
+ set_errno ();
+ return NULL;
+}
+
+struct dirent *
+readdir64 (DIR *dir)
+{
+ intercept ("readdir64", 2);
+ set_errno ();
+ return NULL;
+}
+
+
+int
+readdir_r (DIR *dir, struct dirent *entry, struct dirent **result)
+{
+ intercept ("readdir_r", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+readdir64_r (DIR *dir, struct dirent *entry, struct dirent **result)
+{
+ intercept ("readdir64_r", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+closedir (DIR *dh)
+{
+ intercept ("closedir", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+__xstat (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__xstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+__xstat64 (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__xstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+stat (const char *path, struct stat *buf)
+{
+ intercept ("stat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+stat64 (const char *path, struct stat *buf)
+{
+ intercept ("stat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__fxstat (int ver, int fd, struct stat *buf)
+{
+ intercept ("__fxstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+__fxstat64 (int ver, int fd, struct stat *buf)
+{
+ intercept ("__fxstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fstat (int fd, struct stat *buf)
+{
+ intercept ("fstat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fstat64 (int fd , struct stat *buf)
+{
+ intercept ("fstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__lxstat (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__lxstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__lxstat64 (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__lxstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lstat (const char *path, struct stat *buf)
+{
+ intercept ("lstat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lstat64 (const char *path, struct stat *buf)
+{
+ intercept ("lstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+statfs (const char *path, struct statfs *buf)
+{
+ intercept ("statfs", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+statfs64 (const char *path, struct statfs *buf)
+{
+ intercept ("statfs64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+statvfs (const char *path, struct statvfs *buf)
+{
+ intercept ("statvfs\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+statvfs64 (const char *path, struct statvfs *buf)
+{
+ intercept ("statvfs64", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+getxattr (const char *path, const char *name, void *value, size_t size)
+{
+ intercept ("getxattr", 1);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+lgetxattr (const char *path, const char *name, void *value, size_t size)
+{
+ intercept ("lgetxattr", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+remove (const char* path)
+{
+ intercept ("remove", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lchown (const char *path, uid_t owner, gid_t group)
+{
+ intercept ("lchown", 2);
+ set_errno ();
+ return -1;
+}
+
+void
+rewinddir (DIR *dirp)
+{
+ intercept ("rewinddir", 1);
+ set_errno ();
+ return;
+}
+
+void
+seekdir (DIR *dirp, off_t offset)
+{
+ intercept ("seekdir", 2);
+ set_errno ();
+ return;
+}
+
+off_t
+telldir (DIR *dirp)
+{
+ intercept ("telldir", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+sendfile (int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ intercept ("sendfile\t", 1);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+sendfile64 (int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ intercept ("sendfile64", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+fcntl (int fd, int cmd, ...)
+{
+ intercept ("fcntl", 2);
+ set_errno ();
+ return -1;
+}
+
diff --git a/extras/test/ld-preload-test/ld-preload-test.c b/extras/test/ld-preload-test/ld-preload-test.c
new file mode 100644
index 000000000..78772f598
--- /dev/null
+++ b/extras/test/ld-preload-test/ld-preload-test.c
@@ -0,0 +1,367 @@
+/*
+ Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+/*
+ * LD PRELOAD Test Tool
+ *
+ * 1. The idea of this test tool is to check the sanity of the LD_PRELOAD
+ * mechanism in libc for the system on which booster needs to run.
+ *
+ * 2. Basically, this test tool calls various system calls for which there is
+ * support in the booster library. Combined with the logging output from this
+ * tool and the preload-test-lib, one can determine whether the
+ * pre-loading mechanism is working working in order for booster to initialize.
+ *
+ * 3. This tool does not test GlusterFS functionality running under booster
+ * although the path specified to the tool can be a GlusterFS mountpoint but
+ * that is not very useful.
+ *
+ * 4. This tool is incomplete without the preload-test-lib and the
+ * accompanyung shell script that needs to be run for running the test.
+ */
+#define _XOPEN_SOURCE 500
+
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <utime.h>
+#include <sys/time.h>
+#include <attr/xattr.h>
+#include <sys/sendfile.h>
+
+
+#define PRELOAD_ERRNO_VERF 6449
+inline void
+check_err(int ret, char *call, int tabs)
+{
+ while (tabs > 0) {
+ fprintf (stdout, "\t");
+ --tabs;
+ }
+ if (ret != -1) {
+ fprintf (stdout, "Not intercepted: %s\n", call);
+ return;
+ }
+
+ if (errno != PRELOAD_ERRNO_VERF) {
+ fprintf (stdout, "Not intercepted: %s: err: %s\n", call,
+ strerror (errno));
+ return;
+ }
+
+ fprintf (stdout, "Intercept verified: %s\n", call);
+ return;
+}
+
+void
+usage (FILE *fp)
+{
+ fprintf (fp, "Usage: ld-preload-test <Options>\n");
+ fprintf (fp, "Options\n");
+ fprintf (fp, "\t--path\t\tPathname is used as the file/directory"
+ " created for the test.\n");
+
+}
+
+
+int
+run_file_tests (char *testfile)
+{
+ int ret = -1;
+ struct stat buf;
+
+ assert (testfile);
+ fprintf (stdout, "Testing creat");
+ ret = creat (testfile, S_IRWXU);
+ check_err (ret, "creat", 2);
+
+ fprintf (stdout, "Testing close");
+ ret = close (ret);
+ check_err (ret, "close", 2);
+
+ fprintf (stdout, "Testing open");
+ ret = open (testfile, O_RDONLY);
+ check_err (ret, "open", 2);
+
+ fprintf (stdout, "Testing read");
+ ret = read (0, NULL, 0);
+ check_err (ret, "read", 2);
+
+ fprintf (stdout, "Testing readv");
+ ret = readv (0, NULL, 0);
+ check_err (ret, "readv", 2);
+
+ fprintf (stdout, "Testing pread");
+ ret = pread (0, NULL, 0, 0);
+ check_err (ret, "pread", 2);
+
+ fprintf (stdout, "Testing write");
+ ret = write (0, NULL, 0);
+ check_err (ret, "write", 2);
+
+ fprintf (stdout, "Testing writev");
+ ret = writev (0, NULL, 0);
+ check_err (ret, "writev", 2);
+
+ fprintf (stdout, "Testing pwrite");
+ ret = pwrite (0, NULL, 0, 0);
+ check_err (ret, "pwrite", 2);
+
+ fprintf (stdout, "Testing lseek");
+ ret = lseek (0, 0, 0);
+ check_err (ret, "lseek", 2);
+
+ fprintf (stdout, "Testing dup");
+ ret = dup (0);
+ check_err (ret, "dup", 2);
+
+ fprintf (stdout, "Testing dup2");
+ ret = dup2 (0, 0);
+ check_err (ret, "dup2", 2);
+
+ fprintf (stdout, "Testing fchmod");
+ ret = fchmod (0, 0);
+ check_err (ret, "fchmod", 2);
+
+ fprintf (stdout, "Testing fchown");
+ ret = fchown (0, 0, 0);
+ check_err (ret, "fchown", 2);
+
+ fprintf (stdout, "Testing fsync");
+ ret = fsync (0);
+ check_err (ret, "fsync", 2);
+
+ fprintf (stdout, "Testing ftruncate");
+ ret = ftruncate (0, 0);
+ check_err (ret, "ftruncate", 1);
+
+ fprintf (stdout, "Testing fstat");
+ ret = fstat (0, &buf);
+ check_err (ret, "fstat", 1);
+
+ fprintf (stdout, "Testing sendfile");
+ ret = sendfile (0, 0, NULL, 0);
+ check_err (ret, "sendfile", 1);
+
+ fprintf (stdout, "Testing fcntl");
+ ret = fcntl (0, 0, NULL);
+ check_err (ret, "fcntl", 2);
+
+ fprintf (stdout, "Testing close");
+ ret = close (ret);
+ check_err (ret, "close", 2);
+
+ fprintf (stdout, "Testing remove");
+ ret = remove (testfile);
+ check_err (ret, "remove", 2);
+
+ return ret;
+}
+
+
+int
+run_attr_tests (char *testfile)
+{
+ int ret = -1;
+ char *res = NULL;
+ struct stat buf;
+ struct statfs sbuf;
+ struct statvfs svbuf;
+
+ assert (testfile);
+
+ fprintf (stdout, "Testing chmod");
+ ret = chmod (testfile, 0);
+ check_err (ret, "chmod", 2);
+
+ fprintf (stdout, "Testing chown");
+ ret = chown (testfile, 0, 0);
+ check_err (ret, "chown", 2);
+
+ fprintf (stdout, "Testing link");
+ ret = link (testfile, testfile);
+ check_err (ret, "link", 2);
+
+ fprintf (stdout, "Testing rename");
+ ret = rename (testfile, testfile);
+ check_err (ret, "rename", 2);
+
+ fprintf (stdout, "Testing utimes");
+ ret = utimes (testfile, NULL);
+ check_err (ret, "utimes", 2);
+
+ fprintf (stdout, "Testing utime");
+ ret = utime (testfile, NULL);
+ check_err (ret, "utime", 2);
+
+ fprintf (stdout, "Testing unlink");
+ ret = unlink (testfile);
+ check_err (ret, "unlink", 2);
+
+ fprintf (stdout, "Testing symlink");
+ ret = symlink (testfile, testfile);
+ check_err (ret, "symlink", 2);
+
+ fprintf (stdout, "Testing readlink");
+ ret = readlink (testfile, testfile, 0);
+ check_err (ret, "readlink", 2);
+
+ fprintf (stdout, "Testing realpath");
+ ret = 0;
+ res = realpath ((const char *)testfile, testfile);
+ if (!res)
+ ret = -1;
+ check_err (ret, "realpath", 2);
+
+ fprintf (stdout, "Testing stat");
+ ret = stat (testfile, &buf);
+ check_err (ret, "stat", 1);
+
+ fprintf (stdout, "Testing lstat");
+ ret = lstat (testfile, &buf);
+ check_err (ret, "lstat", 1);
+
+ fprintf (stdout, "Testing statfs");
+ ret = statfs (testfile, &sbuf);
+ check_err (ret, "statfs", 2);
+
+ fprintf (stdout, "Testing statvfs");
+ ret = statvfs (testfile, &svbuf);
+ check_err (ret, "statvfs", 1);
+
+ fprintf (stdout, "Testing getxattr");
+ ret = getxattr (testfile, NULL, NULL, 0);
+ check_err (ret, "getxattr", 2);
+
+ fprintf (stdout, "Testing lgetxattr");
+ ret = lgetxattr (testfile, NULL, NULL, 0);
+ check_err (ret, "lgetxattr", 1);
+
+ fprintf (stdout, "Testing lchown");
+ ret = lchown (testfile, 0, 0);
+ check_err (ret, "lchown", 2);
+ return 0;
+}
+
+
+int
+run_dev_tests (char *testfile)
+{
+ int ret = -1;
+
+ assert (testfile);
+
+ fprintf (stdout, "Testing mknod");
+ ret = mknod (testfile, 0, 0);
+ check_err (ret, "mknod", 2);
+
+ fprintf (stdout, "Testing mkfifo");
+ ret = mkfifo (testfile, 0);
+ check_err (ret, "mkfifo", 2);
+ return 0;
+}
+
+int
+run_dir_tests (char *testpath)
+{
+ int ret = -1;
+ DIR *dh = NULL;
+ struct dirent *dire = NULL;
+
+ assert (testpath);
+
+ fprintf (stdout, "Testing mkdir");
+ ret = mkdir (testpath, 0);
+ check_err (ret, "mkdir", 2);
+
+ fprintf (stdout, "Testing rmdir");
+ ret = rmdir (testpath);
+ check_err (ret, "rmdir", 2);
+
+ fprintf (stdout, "Testing opendir");
+ ret = 0;
+ dh = opendir (testpath);
+ if (!dh)
+ ret = -1;
+ check_err (ret, "opendir", 2);
+
+ fprintf (stdout, "Testing readdir");
+ ret = 0;
+ dire = readdir (dh);
+ if (!dire)
+ ret = -1;
+ check_err (ret, "readdir", 1);
+
+ fprintf (stdout, "Testing readdir_r");
+ ret = readdir_r (dh, dire, &dire);
+ check_err (ret, "readdir_r", 1);
+
+ fprintf (stdout, "Testing rewinddir");
+ rewinddir (dh);
+ check_err (-1, "rewinddir", 1);
+
+ fprintf (stdout, "Testing seekdir");
+ seekdir (dh, 0);
+ check_err (-1, "seekdir", 2);
+
+ fprintf (stdout, "Testing telldir");
+ ret = telldir (dh);
+ check_err (ret, "telldir", 2);
+
+ fprintf (stdout, "Testing closedir");
+ ret = closedir (dh);
+ check_err (ret, "closedir", 2);
+ return 0;
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+ char *testpath = NULL;
+ int x = 0;
+
+ for (;x < argc; ++x) {
+ if (strcmp (argv[x], "--path") == 0) {
+ testpath = argv[x+1];
+ continue;
+ }
+
+ }
+
+ if (!testpath) {
+ fprintf (stderr, "--path not specified\n");
+ usage (stderr);
+ return -1;
+ }
+
+ run_file_tests (testpath);
+ run_dir_tests (testpath);
+ run_attr_tests (testpath);
+ run_dev_tests (testpath);
+
+ return 0;
+}
+
+
diff --git a/extras/test/ld-preload-test/test-preload.sh b/extras/test/ld-preload-test/test-preload.sh
new file mode 100755
index 000000000..faed5cee3
--- /dev/null
+++ b/extras/test/ld-preload-test/test-preload.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+echo "Testing 32-bit offsets build"
+LD_PRELOAD="$(pwd)/ld-preload-lib.so" $(pwd)/ld-preload-test32 --path /tmp/testfile
+echo
+echo "Testing 64-bit offsets build"
+LD_PRELOAD="$(pwd)/ld-preload-lib.so" $(pwd)/ld-preload-test64 --path /tmp/testfile
diff --git a/extras/test/open-fd-tests.c b/extras/test/open-fd-tests.c
new file mode 100644
index 000000000..4184079d0
--- /dev/null
+++ b/extras/test/open-fd-tests.c
@@ -0,0 +1,64 @@
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <attr/xattr.h>
+#include <errno.h>
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ int ret = -1;
+ int fd = 0;
+ char *filename = NULL;
+ int loop = 0;
+ struct stat stbuf = {0,};
+ char string[1024] = {0,};
+
+ if (argc > 1)
+ filename = argv[1];
+
+ if (!filename)
+ filename = "temp-fd-test-file";
+
+ fd = open (filename, O_RDWR|O_CREAT|O_TRUNC);
+ if (fd < 0) {
+ fd = 0;
+ fprintf (stderr, "open failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ while (loop < 1000) {
+ /* Use it as a mechanism to test time delays */
+ memset (string, 0, 1024);
+ scanf ("%s", string);
+
+ ret = write (fd, string, strlen (string));
+ if (ret != strlen (string)) {
+ fprintf (stderr, "write failed : %s (%s %d)\n",
+ strerror (errno), string, loop);
+ goto out;
+ }
+
+ ret = write (fd, "\n", 1);
+ if (ret != 1) {
+ fprintf (stderr, "write failed : %s (%d)\n",
+ strerror (errno), loop);
+ goto out;
+ }
+
+ loop++;
+ }
+
+ fprintf (stdout, "finishing the test after %d loops\n", loop);
+
+ ret = 0;
+out:
+ if (fd)
+ close (fd);
+
+ return ret;
+}
diff --git a/extras/test/run.sh b/extras/test/run.sh
new file mode 100755
index 000000000..4b3839cf6
--- /dev/null
+++ b/extras/test/run.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+# This file is part of GlusterFS.
+#
+# This file is licensed to you under your choice of the GNU Lesser
+# General Public License, version 3 or any later version (LGPLv3 or
+# later), or the GNU General Public License, version 2 (GPLv2), in all
+# cases as published by the Free Software Foundation.
+
+# Running gluster sanity test which starts glusterd and runs gluster commands, and exit at the first failure.
+$PWD/gluster_commands.sh
+
+if [ $? -ne 0 ]; then
+ echo "sanity failed"
+else
+ echo "sanity passed"
+fi
+
+# Stopping glusterd
+$PWD/stop_glusterd.sh
+
diff --git a/extras/test/stop_glusterd.sh b/extras/test/stop_glusterd.sh
new file mode 100755
index 000000000..a2db13f42
--- /dev/null
+++ b/extras/test/stop_glusterd.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+# This file is part of GlusterFS.
+#
+# This file is licensed to you under your choice of the GNU Lesser
+# General Public License, version 3 or any later version (LGPLv3 or
+# later), or the GNU General Public License, version 2 (GPLv2), in all
+# cases as published by the Free Software Foundation.
+
+#This script stops the glusterd running on the machine. Helpful for gluster sanity script
+
+killall -9 glusterd
+
+if [ $? -ne 0 ]; then
+ echo "Error: Could not kill glusterd. Either glusterd is not running or kill it manually"
+else
+ echo "Killed glusterd"
+fi
diff --git a/extras/test/test-ffop.c b/extras/test/test-ffop.c
new file mode 100644
index 000000000..2d174d452
--- /dev/null
+++ b/extras/test/test-ffop.c
@@ -0,0 +1,870 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <attr/xattr.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+int fd_based_fops_1 (char *filename); //for fd based fops after unlink
+int fd_based_fops_2 (char *filename); //for fd based fops before unlink
+int dup_fd_based_fops (char *filename); // fops based on fd after dup
+int path_based_fops (char *filename); //for fops based on path
+int dir_based_fops (char *filename); // for fops which operate on directory
+int link_based_fops (char *filename); //for fops which operate in link files (symlinks)
+int test_open_modes (char *filename); // to test open syscall with open modes available.
+int generic_open_read_write (char *filename, int flag); // generic function which does open write and read.
+
+int
+main (int argc, char *argv[])
+{
+ int ret = -1;
+ char filename[255] = {0,};
+
+ if (argc > 1)
+ strcpy(filename, argv[1]);
+ else
+ strcpy(filename, "temp-xattr-test-file");
+
+ ret = fd_based_fops_1 (strcat(filename, "_1"));
+ if (ret < 0)
+ fprintf (stderr, "fd based file operation 1 failed\n");
+ else
+ fprintf (stdout, "fd based file operation 1 passed\n");
+
+ ret = fd_based_fops_2 (strcat(filename, "_2"));
+ if (ret < 0)
+ fprintf (stderr, "fd based file operation 2 failed\n");
+ else
+ fprintf (stdout, "fd based file operation 2 passed\n");
+
+ ret = dup_fd_based_fops (strcat (filename, "_3"));
+ if (ret < 0)
+ fprintf (stderr, "dup fd based file operation failed\n");
+ else
+ fprintf (stdout, "dup fd based file operation passed\n");
+
+ ret = path_based_fops (strcat (filename, "_4"));
+ if (ret < 0)
+ fprintf (stderr, "path based file operation failed\n");
+ else
+ fprintf (stdout, "path based file operation passed\n");
+
+ ret = dir_based_fops (strcat (filename, "_5"));
+ if (ret < 0)
+ fprintf (stderr, "directory based file operation failed\n");
+ else
+ fprintf (stdout, "directory based file operation passed\n");
+
+ ret = link_based_fops (strcat (filename, "_5"));
+ if (ret < 0)
+ fprintf (stderr, "link based file operation failed\n");
+ else
+ fprintf (stdout, "link based file operation passed\n");
+
+ ret = test_open_modes (strcat (filename, "_5"));
+ if (ret < 0)
+ fprintf (stderr, "testing modes of 'open' call failed\n");
+ else
+ fprintf (stdout, "testing modes of 'open' call passed\n");
+
+out:
+ return ret;
+}
+
+int
+fd_based_fops_1 (char *filename)
+{
+ int fd = 0;
+ int ret = -1;
+ struct stat stbuf = {0,};
+ char wstr[50] = {0,};
+ char rstr[50] = {0,};
+
+ fd = open (filename, O_RDWR|O_CREAT);
+ if (fd < 0) {
+ fd = 0;
+ fprintf (stderr, "open failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = unlink (filename);
+ if (ret < 0) {
+ fprintf (stderr, "unlink failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (wstr, "This is my string\n");
+ ret = write (fd, wstr, strlen(wstr));
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "write failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lseek (fd, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf (stderr, "lseek failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = read (fd, rstr, strlen(wstr));
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "read failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = memcmp (rstr, wstr, strlen (wstr));
+ if (ret != 0) {
+ ret = -1;
+ fprintf (stderr, "read returning junk\n");
+ goto out;
+ }
+
+ ret = ftruncate (fd, 0);
+ if (ret < 0) {
+ fprintf (stderr, "ftruncate failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fstat (fd, &stbuf);
+ if (ret < 0) {
+ fprintf (stderr, "fstat failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchmod (fd, 0640);
+ if (ret < 0) {
+ fprintf (stderr, "fchmod failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchown (fd, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "fchown failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsync (fd);
+ if (ret < 0) {
+ fprintf (stderr, "fsync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsetxattr (fd, "trusted.xattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "fsetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fdatasync (fd);
+ if (ret < 0) {
+ fprintf (stderr, "fdatasync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = flistxattr (fd, NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "flistxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fgetxattr (fd, "trusted.xattr-test", NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "fgetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fremovexattr (fd, "trusted.xattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "fremovexattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (fd)
+ close (fd);
+
+ return ret;
+}
+
+
+int
+fd_based_fops_2 (char *filename)
+{
+ int fd = 0;
+ int ret = -1;
+ struct stat stbuf = {0,};
+ char wstr[50] = {0,};
+ char rstr[50] = {0,};
+
+ fd = open (filename, O_RDWR|O_CREAT);
+ if (fd < 0) {
+ fd = 0;
+ fprintf (stderr, "open failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = ftruncate (fd, 0);
+
+ if (ret < 0) {
+ fprintf (stderr, "ftruncate failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (wstr, "This is my second string\n");
+ ret = write (fd, wstr, strlen (wstr));
+ if (ret < 0) {
+ ret = -1;
+ fprintf (stderr, "write failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ lseek (fd, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf (stderr, "lseek failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = read (fd, rstr, strlen (wstr));
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "read failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = memcmp (rstr, wstr, strlen (wstr));
+ if (ret != 0) {
+ ret = -1;
+ fprintf (stderr, "read returning junk\n");
+ goto out;
+ }
+
+ ret = fstat (fd, &stbuf);
+ if (ret < 0) {
+ fprintf (stderr, "fstat failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchmod (fd, 0640);
+ if (ret < 0) {
+ fprintf (stderr, "fchmod failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchown (fd, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "fchown failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsync (fd);
+ if (ret < 0) {
+ fprintf (stderr, "fsync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsetxattr (fd, "trusted.xattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "fsetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fdatasync (fd);
+ if (ret < 0) {
+ fprintf (stderr, "fdatasync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = flistxattr (fd, NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "flistxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fgetxattr (fd, "trusted.xattr-test", NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "fgetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fremovexattr (fd, "trusted.xattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "fremovexattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+out:
+ if (fd)
+ close (fd);
+ unlink (filename);
+
+ return ret;
+}
+
+int
+path_based_fops (char *filename)
+{
+ int ret = -1;
+ int fd = 0;
+ struct stat stbuf = {0,};
+ char newfilename[255] = {0,};
+
+ fd = creat (filename, 0644);
+ if (fd < 0) {
+ fprintf (stderr, "creat failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = truncate (filename, 0);
+ if (ret < 0) {
+ fprintf (stderr, "truncate failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = stat (filename, &stbuf);
+ if (ret < 0) {
+ fprintf (stderr, "stat failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = chmod (filename, 0640);
+ if (ret < 0) {
+ fprintf (stderr, "chmod failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = chown (filename, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "chown failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = setxattr (filename, "trusted.xattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "setxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = listxattr (filename, NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "listxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = getxattr (filename, "trusted.xattr-test", NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "getxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = removexattr (filename, "trusted.xattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "removexattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = access (filename, R_OK|W_OK);
+ if (ret < 0) {
+ fprintf (stderr, "access failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (newfilename, filename);
+ strcat(newfilename, "_new");
+ ret = rename (filename, newfilename);
+ if (ret < 0) {
+ fprintf (stderr, "rename failed: %s\n", strerror (errno));
+ goto out;
+ }
+ unlink (newfilename);
+
+out:
+ if (fd)
+ close (fd);
+
+ unlink (filename);
+ return ret;
+}
+
+int
+dup_fd_based_fops (char *filename)
+{
+ int fd = 0;
+ int newfd = 0;
+ int ret = -1;
+ struct stat stbuf = {0,};
+ char wstr[50] = {0,};
+ char rstr[50] = {0,};
+
+ fd = open (filename, O_RDWR|O_CREAT);
+ if (fd < 0) {
+ fd = 0;
+ fprintf (stderr, "open failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ newfd = dup (fd);
+ if (newfd < 0) {
+ ret = -1;
+ fprintf (stderr, "dup failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ close (fd);
+
+ strcpy (wstr, "This is my string\n");
+ ret = write (newfd, wstr, strlen(wstr));
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "write failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lseek (newfd, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf (stderr, "lseek failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = read (newfd, rstr, strlen(wstr));
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "read failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = memcmp (rstr, wstr, strlen (wstr));
+ if (ret != 0) {
+ ret = -1;
+ fprintf (stderr, "read returning junk\n");
+ goto out;
+ }
+
+ ret = ftruncate (newfd, 0);
+ if (ret < 0) {
+ fprintf (stderr, "ftruncate failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fstat (newfd, &stbuf);
+ if (ret < 0) {
+ fprintf (stderr, "fstat failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchmod (newfd, 0640);
+ if (ret < 0) {
+ fprintf (stderr, "fchmod failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fchown (newfd, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "fchown failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsync (newfd);
+ if (ret < 0) {
+ fprintf (stderr, "fsync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fsetxattr (newfd, "trusted.xattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "fsetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fdatasync (newfd);
+ if (ret < 0) {
+ fprintf (stderr, "fdatasync failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = flistxattr (newfd, NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "flistxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fgetxattr (newfd, "trusted.xattr-test", NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "fgetxattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = fremovexattr (newfd, "trusted.xattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "fremovexattr failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (newfd)
+ close (newfd);
+ ret = unlink (filename);
+ if (ret < 0) {
+ fprintf (stderr, "unlink failed : %s\n", strerror (errno));
+ goto out;
+ }
+
+ return ret;
+}
+
+int
+dir_based_fops (char *dirname)
+{
+ int ret = -1;
+ DIR *dp = NULL;
+ char buff[255] = {0,};
+ struct dirent *dbuff = {0,};
+ struct stat stbuff = {0,};
+ char newdname[255] = {0,};
+ char *cwd = NULL;
+
+ ret = mkdir (dirname, 0755);
+ if (ret < 0) {
+ fprintf (stderr, "mkdir failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ dp = opendir (dirname);
+ if (dp == NULL) {
+ fprintf (stderr, "opendir failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ dbuff = readdir (dp);
+ if (NULL == dbuff) {
+ fprintf (stderr, "readdir failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = closedir (dp);
+ if (ret < 0) {
+ fprintf (stderr, "closedir failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = stat (dirname, &stbuff);
+ if (ret < 0) {
+ fprintf (stderr, "stat failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = chmod (dirname, 0744);
+ if (ret < 0) {
+ fprintf (stderr, "chmod failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = chown (dirname, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "chmod failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = setxattr (dirname, "trusted.xattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "setxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = listxattr (dirname, NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "listxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = getxattr (dirname, "trusted.xattr-test", NULL, 0);
+ if (ret <= 0) {
+ ret = -1;
+ fprintf (stderr, "getxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = removexattr (dirname, "trusted.xattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "removexattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (newdname, dirname);
+ strcat (newdname, "/../");
+ ret = chdir (newdname);
+ if (ret < 0) {
+ fprintf (stderr, "chdir failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ cwd = getcwd (buff, 255);
+ if (NULL == cwd) {
+ fprintf (stderr, "getcwd failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (newdname, dirname);
+ strcat (newdname, "new");
+ ret = rename (dirname, newdname);
+ if (ret < 0) {
+ fprintf (stderr, "rename failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = rmdir (newdname);
+ if (ret < 0) {
+ fprintf (stderr, "rmdir failed: %s\n", strerror (errno));
+ return ret;
+ }
+
+out:
+ rmdir (dirname);
+ return ret;
+}
+
+int
+link_based_fops (char *filename)
+{
+ int ret = -1;
+ int fd = 0;
+ char newname[255] = {0,};
+ char linkname[255] = {0,};
+ struct stat lstbuf = {0,};
+
+ fd = creat (filename, 0644);
+ if (fd < 0) {
+ fd = 0;
+ fprintf (stderr, "creat failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (newname, filename);
+ strcat (newname, "_hlink");
+ ret = link (filename, newname);
+ if (ret < 0) {
+ fprintf (stderr, "link failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = unlink (filename);
+ if (ret < 0) {
+ fprintf (stderr, "unlink failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ strcpy (linkname, filename);
+ strcat (linkname, "_slink");
+ ret = symlink (newname, linkname);
+ if (ret < 0) {
+ fprintf (stderr, "symlink failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lstat (linkname, &lstbuf);
+ if (ret < 0) {
+ fprintf (stderr, "lstbuf failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lchown (linkname, 10001, 10001);
+ if (ret < 0) {
+ fprintf (stderr, "lchown failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lsetxattr (linkname, "trusted.lxattr-test", "working", 8, 0);
+ if (ret < 0) {
+ fprintf (stderr, "lsetxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = llistxattr (linkname, NULL, 0);
+ if (ret < 0) {
+ ret = -1;
+ fprintf (stderr, "llistxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lgetxattr (linkname, "trusted.lxattr-test", NULL, 0);
+ if (ret < 0) {
+ ret = -1;
+ fprintf (stderr, "lgetxattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+ ret = lremovexattr (linkname, "trusted.lxattr-test");
+ if (ret < 0) {
+ fprintf (stderr, "lremovexattr failed: %s\n", strerror (errno));
+ goto out;
+ }
+
+
+out:
+ if (fd)
+ close(fd);
+ unlink (linkname);
+ unlink (newname);
+}
+
+int
+test_open_modes (char *filename)
+{
+ int ret = -1;
+
+ ret = generic_open_read_write (filename, O_CREAT|O_WRONLY);
+ if (3 != ret) {
+ fprintf (stderr, "flag O_CREAT|O_WRONLY failed: \n");
+ goto out;
+ }
+
+ ret = generic_open_read_write (filename, O_CREAT|O_RDWR);
+ if (ret != 0) {
+ fprintf (stderr, "flag O_CREAT|O_RDWR failed\n");
+ goto out;
+ }
+
+ ret = generic_open_read_write (filename, O_CREAT|O_RDONLY);
+ if (ret != 0) {
+ fprintf (stderr, "flag O_CREAT|O_RDONLY failed\n");
+ goto out;
+ }
+
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_WRONLY);
+ if (3 != ret) {
+ fprintf (stderr, "flag O_WRONLY failed\n");
+ goto out;
+ }
+
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_RDWR);
+ if (0 != ret) {
+ fprintf (stderr, "flag O_RDWR failed\n");
+ goto out;
+ }
+
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_RDONLY);
+ if (0 != ret) {
+ fprintf (stderr, "flag O_RDONLY failed\n");
+ goto out;
+ }
+
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_TRUNC|O_WRONLY);
+ if (3 != ret) {
+ fprintf (stderr, "flag O_TRUNC|O_WRONLY failed\n");
+ goto out;
+ }
+
+#if 0 /* undefined behaviour, unable to reliably test */
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_TRUNC|O_RDONLY);
+ if (0 != ret) {
+ fprintf (stderr, "flag O_TRUNC|O_RDONLY failed\n");
+ goto out;
+ }
+#endif
+
+ ret = generic_open_read_write (filename, O_CREAT|O_RDWR|O_SYNC);
+ if (0 != ret) {
+ fprintf (stderr, "flag O_CREAT|O_RDWR|O_SYNC failed\n");
+ goto out;
+ }
+
+ ret = creat (filename, 0644);
+ close (ret);
+ ret = generic_open_read_write (filename, O_CREAT|O_EXCL);
+ if (0 != ret) {
+ fprintf (stderr, "flag O_CREAT|O_EXCL failed\n");
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int generic_open_read_write (char *filename, int flag)
+{
+ int fd = 0;
+ int ret = -1;
+ char wstring[50] = {0,};
+ char rstring[50] = {0,};
+
+ fd = open (filename, flag);
+ if (fd < 0) {
+ if (flag == O_CREAT|O_EXCL && errno == EEXIST) {
+ unlink (filename);
+ return 0;
+ }
+ else {
+ fd = 0;
+ fprintf (stderr, "open failed: %s\n", strerror (errno));
+ return 1;
+ }
+ }
+
+ strcpy (wstring, "My string to write\n");
+ ret = write (fd, wstring, strlen(wstring));
+ if (ret <= 0) {
+ if (errno != EBADF) {
+ fprintf (stderr, "write failed: %s\n", strerror (errno));
+ close (fd);
+ unlink(filename);
+ return 2;
+ }
+ }
+
+ ret = lseek (fd, 0, SEEK_SET);
+ if (ret < 0) {
+ close (fd);
+ unlink(filename);
+ return 4;
+ }
+
+ ret = read (fd, rstring, strlen(wstring));
+ if (ret < 0) {
+ close (fd);
+ unlink (filename);
+ return 3;
+ }
+
+ /* Compare the rstring with wstring. But we do not want to return
+ * error when the flag is either O_RDONLY, O_CREAT|O_RDONLY or
+ * O_TRUNC|O_RDONLY. Because in that case we are not writing
+ * anything to the file.*/
+
+ ret = memcmp (wstring, rstring, strlen (wstring));
+ if (0 != ret && !(flag == O_CREAT|O_RDONLY || flag == O_RDONLY ||\
+ flag == O_TRUNC|O_RDONLY)) {
+ fprintf (stderr, "read is returning junk\n");
+ close (fd);
+ unlink (filename);
+ return 4;
+ }
+
+ close (fd);
+ unlink (filename);
+ return 0;
+}
diff --git a/extras/volfilter.py b/extras/volfilter.py
new file mode 100644
index 000000000..0ca456a78
--- /dev/null
+++ b/extras/volfilter.py
@@ -0,0 +1,167 @@
+# Copyright (c) 2010-2011 Red Hat, Inc.
+#
+# This file is part of HekaFS.
+#
+# HekaFS is free software: you can redistribute it and/or modify it under the
+# terms of the GNU General Public License, version 3, as published by the Free
+# Software Foundation.
+#
+# HekaFS 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 HekaFS. If not, see <http://www.gnu.org/licenses/>.
+
+import copy
+import string
+import sys
+import types
+
+good_xlators = [
+ "cluster/afr",
+ "cluster/dht",
+ "cluster/distribute",
+ "cluster/replicate",
+ "cluster/stripe",
+ "debug/io-stats",
+ "features/access-control",
+ "features/locks",
+ "features/marker",
+ "features/uidmap",
+ "performance/io-threads",
+ "protocol/client",
+ "protocol/server",
+ "storage/posix",
+]
+
+def copy_stack (old_xl,suffix,recursive=False):
+ if recursive:
+ new_name = old_xl.name + "-" + suffix
+ else:
+ new_name = suffix
+ new_xl = Translator(new_name)
+ new_xl.type = old_xl.type
+ # The results with normal assignment here are . . . amusing.
+ new_xl.opts = copy.deepcopy(old_xl.opts)
+ for sv in old_xl.subvols:
+ new_xl.subvols.append(copy_stack(sv,suffix,True))
+ # Patch up the path at the bottom.
+ if new_xl.type == "storage/posix":
+ new_xl.opts["directory"] += ("/" + suffix)
+ return new_xl
+
+def cleanup (parent, graph):
+ if parent.type in good_xlators:
+ # Temporary fix so that HekaFS volumes can use the
+ # SSL-enabled multi-threaded socket transport.
+ if parent.type == "protocol/server":
+ parent.type = "protocol/server2"
+ parent.opts["transport-type"] = "ssl"
+ elif parent.type == "protocol/client":
+ parent.type = "protocol/client2"
+ parent.opts["transport-type"] = "ssl"
+ sv = []
+ for child in parent.subvols:
+ sv.append(cleanup(child,graph))
+ parent.subvols = sv
+ else:
+ parent = cleanup(parent.subvols[0],graph)
+ return parent
+
+class Translator:
+ def __init__ (self, name):
+ self.name = name
+ self.type = ""
+ self.opts = {}
+ self.subvols = []
+ self.dumped = False
+ def __repr__ (self):
+ return "<Translator %s>" % self.name
+
+def load (path):
+ # If it's a string, open it; otherwise, assume it's already a
+ # file-like object (most notably from urllib*).
+ if type(path) in types.StringTypes:
+ fp = file(path,"r")
+ else:
+ fp = path
+ all_xlators = {}
+ xlator = None
+ last_xlator = None
+ while True:
+ text = fp.readline()
+ if text == "":
+ break
+ text = text.split()
+ if not len(text):
+ continue
+ if text[0] == "volume":
+ if xlator:
+ raise RuntimeError, "nested volume definition"
+ xlator = Translator(text[1])
+ continue
+ if not xlator:
+ raise RuntimeError, "text outside volume definition"
+ if text[0] == "type":
+ xlator.type = text[1]
+ continue
+ if text[0] == "option":
+ xlator.opts[text[1]] = string.join(text[2:])
+ continue
+ if text[0] == "subvolumes":
+ for sv in text[1:]:
+ xlator.subvols.append(all_xlators[sv])
+ continue
+ if text[0] == "end-volume":
+ all_xlators[xlator.name] = xlator
+ last_xlator = xlator
+ xlator = None
+ continue
+ raise RuntimeError, "unrecognized keyword %s" % text[0]
+ if xlator:
+ raise RuntimeError, "unclosed volume definition"
+ return all_xlators, last_xlator
+
+def generate (graph, last, stream=sys.stdout):
+ for sv in last.subvols:
+ if not sv.dumped:
+ generate(graph,sv,stream)
+ print >> stream, ""
+ sv.dumped = True
+ print >> stream, "volume %s" % last.name
+ print >> stream, " type %s" % last.type
+ for k, v in last.opts.iteritems():
+ print >> stream, " option %s %s" % (k, v)
+ if last.subvols:
+ print >> stream, " subvolumes %s" % string.join(
+ [ sv.name for sv in last.subvols ])
+ print >> stream, "end-volume"
+
+def push_filter (graph, old_xl, filt_type, opts={}):
+ suffix = "-" + old_xl.type.split("/")[1]
+ if len(old_xl.name) > len(suffix):
+ if old_xl.name[-len(suffix):] == suffix:
+ old_xl.name = old_xl.name[:-len(suffix)]
+ new_xl = Translator(old_xl.name+suffix)
+ new_xl.type = old_xl.type
+ new_xl.opts = old_xl.opts
+ new_xl.subvols = old_xl.subvols
+ graph[new_xl.name] = new_xl
+ old_xl.name += ("-" + filt_type.split("/")[1])
+ old_xl.type = filt_type
+ old_xl.opts = opts
+ old_xl.subvols = [new_xl]
+ graph[old_xl.name] = old_xl
+
+def delete (graph, victim):
+ if len(victim.subvols) != 1:
+ raise RuntimeError, "attempt to delete non-unary translator"
+ for xl in graph.itervalues():
+ while xl.subvols.count(victim):
+ i = xl.subvols.index(victim)
+ xl.subvols[i] = victim.subvols[0]
+
+if __name__ == "__main__":
+ graph, last = load(sys.argv[1])
+ generate(graph,last)
diff --git a/extras/who-wrote-glusterfs/gitdm.aliases b/extras/who-wrote-glusterfs/gitdm.aliases
new file mode 100644
index 000000000..784a3e3bc
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.aliases
@@ -0,0 +1,48 @@
+#
+# This is the email aliases file, mapping secondary addresses onto a single,
+# canonical address. This file should probably match the contents of .mailmap
+# in the root of the git repository.
+#
+# Format: <alias> <real>
+
+amar@gluster.com amarts@redhat.com
+amar@del.gluster.com amarts@redhat.com
+avati@amp.gluster.com avati@redhat.com
+avati@blackhole.gluster.com avati@redhat.com
+avati@dev.gluster.com avati@redhat.com
+avati@gluster.com avati@redhat.com
+wheelear@gmail.com awheeler@redhat.com
+anush@gluster.com ashetty@redhat.com
+csaba@gluster.com csaba@redhat.com
+csaba@lowlife.hu csaba@redhat.com
+csaba@zresearch.com csaba@redhat.com
+harsha@gluster.com fharshav@redhat.com
+harsha@zresearch.com fharshav@redhat.com
+harsha@dev.gluster.com fharshav@redhat.com
+harsha@harshavardhana.net fharshav@redhat.com
+kkeithle@f16node1.kkeithle.usersys.redhat.com kkeithle@redhat.com
+kaushal@gluster.com kaushal@redhat.com
+kaushikbv@gluster.com kbudiger@redhat.com
+krishna@gluster.com ksriniva@redhat.com
+krishna@zresearch.com ksriniva@redhat.com
+krishna@guest-laptop ksriniva@redhat.com
+kp@gluster.com kparthas@redhat.com
+me@louiszuckerman.com louiszuckerman@gmail.com
+msvbhat@gmail.com vbhat@redhat.com
+vishwanath@gluster.com vbhat@redhat.com
+pavan@dev.gluster.com pavan@gluster.com
+zaitcev@yahoo.com zaitcev@kotori.zaitcev.us
+pranithk@gluster.com pkarampu@redhat.com
+raghavendrabhat@gluster.com raghavendra@redhat.com
+raghavendra@gluster.com rgowdapp@redhat.com
+raghavendra@zresearch.com rgowdapp@redhat.com
+rahulcssjce@gmail.com rahulcs@redhat.com
+rajesh@gluster.com rajesh@redhat.com
+rajesh.amaravathi@gmail.com rajesh@redhat.com
+shehjart@zresearch.com shehjart@gluster.com
+venky@gluster.com vshankar@redhat.com
+vijay@gluster.com vbellur@redhat.com
+vijay@dev.gluster.com vbellur@redhat.com
+vijaykumar.koppad@gmail.com vkoppad@redhat.com
+vikas@zresearch.com vikas@gluster.com
+shishirng@gluster.com sgowda@redhat.com
diff --git a/extras/who-wrote-glusterfs/gitdm.config b/extras/who-wrote-glusterfs/gitdm.config
new file mode 100644
index 000000000..e1ff2bd5b
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.config
@@ -0,0 +1,8 @@
+#
+# This is the gitdm configuration file for GlusterFS.
+# See the gitdm.config in the gitdm repositofy for additional options and
+# comments.
+#
+
+EmailAliases gitdm.aliases
+EmailMap gitdm.domain-map
diff --git a/extras/who-wrote-glusterfs/gitdm.domain-map b/extras/who-wrote-glusterfs/gitdm.domain-map
new file mode 100644
index 000000000..f1c305898
--- /dev/null
+++ b/extras/who-wrote-glusterfs/gitdm.domain-map
@@ -0,0 +1,15 @@
+#
+# Here is a set of mappings of domain names onto employer names.
+#
+active.by ActiveCloud
+cern.ch CERN
+gluster.com Red Hat
+gooddata.com GoodData
+hastexo.com hastexo
+ibm.com IBM
+linbit.com LINBIT
+netbsd.org NetBSD
+netdirect.ca Net Direct
+redhat.com Red Hat
+stepping-stone.ch stepping stone GmbH
+zresearch.com Red Hat
diff --git a/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh
new file mode 100755
index 000000000..487f5874b
--- /dev/null
+++ b/extras/who-wrote-glusterfs/who-wrote-glusterfs.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Gather statistics on "Who wrote GlusterFS". The idea comes from the excellent
+# articles on http://lwn.net/ named "Who wrote <linux-version>?".
+#
+# gitdm comes from git://git.lwn.net/gitdm.git by Jonathan Corbet.
+#
+# Confguration files used:
+# - gitdm.config: main configuration file, pointing to the others
+# - gitdm.aliases: merge users with different emailaddresses into one
+# - gitdm.domain-map: map domain names from emailaddresses to companies
+#
+
+DIRNAME=$(dirname $0)
+
+GITDM_REPO=git://git.lwn.net/gitdm.git
+GITDM_DIR=${DIRNAME}/gitdm
+GITDM_CMD="python ${GITDM_DIR}/gitdm"
+
+error()
+{
+ local ret=${?}
+ printf "${@}\n" > /dev/stderr
+ return ${ret}
+}
+
+check_gitdm()
+{
+ if [ ! -e "${GITDM_DIR}/gitdm" ]
+ then
+ git clone --quiet git://git.lwn.net/gitdm.git ${DIRNAME}/gitdm
+ fi
+}
+
+# The first argument is the revision-range (see 'git rev-list --help').
+# REV can be empty, and the statistics will be calculated over the whole
+# current branch.
+REV=${1}
+shift
+# all remaining options are passed to gitdm, see the gitdm script for an
+# explanation of the accepted options.
+GITDM_OPTS=${@}
+
+if ! check_gitdm
+then
+ error "Could not find 'gitdm', exiting..."
+ exit 1
+fi
+
+git log --numstat -M ${REV} | ${GITDM_CMD} -b ${DIRNAME} -n ${GITDM_OPTS}