summaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
Diffstat (limited to 'extras')
-rw-r--r--extras/LinuxRPM/Makefile.am57
-rw-r--r--extras/Makefile.am18
-rw-r--r--extras/Ubuntu/README.Ubuntu28
-rw-r--r--extras/Ubuntu/glusterd.conf17
-rw-r--r--extras/Ubuntu/mounting-glusterfs.conf7
-rw-r--r--extras/benchmarking/Makefile.am4
-rw-r--r--extras/benchmarking/glfs-bm.c25
-rw-r--r--extras/benchmarking/rdd.c24
-rwxr-xr-xextras/generate-xdr-files.sh19
-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.vim21
-rw-r--r--extras/gnfs-loganalyse.py18
-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.am17
-rwxr-xr-xextras/init.d/glusterd-Redhat.in123
-rwxr-xr-xextras/init.d/glusterd-SuSE.in10
-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-profiler23
-rwxr-xr-xextras/prot_filter.py144
-rwxr-xr-xextras/rebalance.py299
-rwxr-xr-xextras/rpc-coverage.sh3
-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.sh40
-rw-r--r--extras/test/ld-preload-test/ld-preload-lib.c20
-rw-r--r--extras/test/ld-preload-test/ld-preload-test.c20
-rw-r--r--extras/test/open-fd-tests.c64
-rwxr-xr-xextras/test/run.sh23
-rwxr-xr-xextras/test/stop_glusterd.sh23
-rw-r--r--extras/test/test-ffop.c779
-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
58 files changed, 3869 insertions, 286 deletions
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/Makefile.am b/extras/Makefile.am
index 5c77ce73d..cf619329b 100644
--- a/extras/Makefile.am
+++ b/extras/Makefile.am
@@ -1,12 +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
+
+confdir = $(sysconfdir)/glusterfs
+conf_DATA = glusterfs-logrotate gluster-rsyslog-7.2.conf gluster-rsyslog-5.8.conf \
+ logger.conf.example glusterfs-georep-logrotate
+
+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
-
+ 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/Ubuntu/README.Ubuntu b/extras/Ubuntu/README.Ubuntu
index 651bd046e..0c5b7828d 100644
--- a/extras/Ubuntu/README.Ubuntu
+++ b/extras/Ubuntu/README.Ubuntu
@@ -1,20 +1,24 @@
-Bug 3282 - Mounting from localhost in fstab fails at boot on ubuntu
-(http://bugs.gluster.com/show_bug.cgi?id=3282)
+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,
-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. An upstart job for glusterd is needed
-to correct this.
+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.
+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.
-It can also be added to Ubuntu deb packages by placing it in debian/upstart
-inside the source package (or debian/glusterd.upstart if the source package
-builds multiple binary packages.)
+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.
+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
index b987ffa13..aa99502b0 100644
--- a/extras/Ubuntu/glusterd.conf
+++ b/extras/Ubuntu/glusterd.conf
@@ -1,17 +1,10 @@
-# glusterd service upstart job
-#
-# Author: Louis Zuckerman <me@louiszuckerman.com>
+author "Louis Zuckerman <me@louiszuckerman.com>"
+description "GlusterFS Management Daemon"
-description "GlusterFS Management Daemon"
-
-start on (local-filesystems and net-device-up IFACE=lo and net-device-up IFACE=eth0) or (mounting TYPE=glusterfs)
+start on runlevel [2345]
stop on runlevel [016]
-respawn
-
-exec /usr/sbin/glusterd -N -p /var/run/glusterd.pid
+expect fork
-post-start script
- sleep 1
-end script
+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/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 035d055df..dc717f33c 100644
--- a/extras/benchmarking/glfs-bm.c
+++ b/extras/benchmarking/glfs-bm.c
@@ -1,21 +1,12 @@
-/*
- Copyright (c) 2008-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/>.
+/*
+ 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
diff --git a/extras/benchmarking/rdd.c b/extras/benchmarking/rdd.c
index b06333370..a667c6a1d 100644
--- a/extras/benchmarking/rdd.c
+++ b/extras/benchmarking/rdd.c
@@ -1,22 +1,12 @@
/*
- Copyright (c) 2008-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/>.
-*/
+ 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>
diff --git a/extras/generate-xdr-files.sh b/extras/generate-xdr-files.sh
index e52321cd3..bc02f77c9 100755
--- a/extras/generate-xdr-files.sh
+++ b/extras/generate-xdr-files.sh
@@ -22,22 +22,13 @@ append_licence_header ()
cat >$dst_file <<EOF
/*
- Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com>
+ Copyright (c) 2007-2012 Red 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.
*/
#include "xdr-common.h"
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.vim b/extras/glusterfs.vim
index 62102c1ee..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) 2017-2011 Gluster, Inc. <http://www.gluster.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
index 6b24e5a71..71e79b6be 100644
--- a/extras/gnfs-loganalyse.py
+++ b/extras/gnfs-loganalyse.py
@@ -1,21 +1,13 @@
#!/bin/python
"""
- Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com>
+ Copyright (c) 2006-2012 Red 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.
+ 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.
- 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/>.
"""
import os
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 66715f431..38898fddd 100644
--- a/extras/init.d/Makefile.am
+++ b/extras/init.d/Makefile.am
@@ -1,19 +1,22 @@
-EXTRA_DIST = glusterd-Debian glusterd-Redhat glusterd-SuSE glusterd.plist
+EXTRA_DIST = glusterd-Debian glusterd-Redhat glusterd-SuSE glusterd.plist rhel5-load-fuse.modules
CLEANFILES =
-initdir = @initdir@
-launchddir = @launchddir@
+INIT_DIR = @initdir@
+SYSTEMD_DIR = @systemddir@
+LAUNCHD_DIR = @launchddir@
$(GF_DISTRIBUTION):
- $(mkdir_p) $(DESTDIR)$(initdir)
- $(INSTALL_PROGRAM) glusterd-$(GF_DISTRIBUTION) $(DESTDIR)$(initdir)/glusterd
+ @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
- $(mkdir_p) $(DESTDIR)$(launchddir)
- $(INSTALL_PROGRAM) glusterd.plist $(DESTDIR)$(launchddir)/com.gluster.glusterd.plist
+ $(mkdir_p) $(DESTDIR)$(LAUNCHD_DIR)
+ $(INSTALL_PROGRAM) glusterd.plist $(DESTDIR)$(LAUNCHD_DIR)/com.gluster.glusterd.plist
endif
diff --git a/extras/init.d/glusterd-Redhat.in b/extras/init.d/glusterd-Redhat.in
index cf9d390f0..e320708ae 100755
--- a/extras/init.d/glusterd-Redhat.in
+++ b/extras/init.d/glusterd-Redhat.in
@@ -1,89 +1,142 @@
#!/bin/bash
#
-# chkconfig: 35 20 80
-# description: Gluster File System service for volume management
+# glusterd Startup script for the glusterfs server
#
+# chkconfig: - 20 80
+# description: Clustered file-system server
-# Get function from functions library
+### 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
-PIDFILE=/var/run/$BASE.pid
+
+# 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_OPTS="--pid-file=$PIDFILE ${GLUSTERD_OPTIONS}"
GLUSTERD="$GLUSTERD_BIN $GLUSTERD_OPTS"
RETVAL=0
+LOCKFILE=/var/lock/subsys/${BASE}
+
# Start the service $BASE
start()
{
- pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null
- status=$?
- if [ $status -eq 0 ]; then
+ if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then
echo "glusterd service is already running with pid $PID"
- exit 1
+ return 0
else
+ ulimit -n $GLUSTERD_NOFILE
echo -n $"Starting $BASE:"
daemon $GLUSTERD
RETVAL=$?
echo
- [ $RETVAL -ne 0 ] && exit $RETVAL
+ [ $RETVAL -eq 0 ] && touch $LOCKFILE
+ return $RETVAL
fi
-
}
# Stop the service $BASE
stop()
{
echo -n $"Stopping $BASE:"
- pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null
- status=$?
- if [ $status -eq 0 ]; then
+ if pidofproc -p $PIDFILE $GLUSTERD_BIN &> /dev/null; then
killproc -p $PIDFILE $BASE
- [ -w $PIDFILE ] && rm -f $PIDFILE
else
killproc $BASE
fi
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && rm -f $LOCKFILE
+ return $RETVAL
+}
- echo
- pidof -c -o %PPID -x $GLUSTERFSD &> /dev/null
- [ $? -eq 0 ] && killproc $GLUSTERFSD &> /dev/null
+restart()
+{
+ stop
+ start
+}
- #pidof -c -o %PPID -x $GLUSTERFS &> /dev/null
- #[ $? -eq 0 ] && killproc $GLUSTERFS &> /dev/null
+reload()
+{
+ restart
+}
- if [ -f /etc/glusterd/nfs/run/nfs.pid ] ;then
- pid=`cat /etc/glusterd/nfs/run/nfs.pid`;
- cmd=`ps -p $pid -o comm=`
+force_reload()
+{
+ restart
+}
- if [ $cmd == "glusterfs" ]; then
- kill `cat /etc/glusterd/nfs/run/nfs.pid`
- fi
- fi
+rh_status()
+{
+ status $BASE
+}
+
+rh_status_q()
+{
+ rh_status &>/dev/null
}
### service arguments ###
case $1 in
start)
- start
+ rh_status_q && exit 0
+ $1
;;
stop)
- stop
+ rh_status_q || exit 0
+ $1
+ ;;
+ restart)
+ $1
+ ;;
+ reload)
+ rh_status_q || exit 7
+ $1
+ ;;
+ force-reload)
+ force_reload
;;
status)
- status $BASE
+ rh_status
;;
- restart)
- $0 stop
- $0 start
+ condrestart|try-restart)
+ rh_status_q || exit 0
+ restart
;;
*)
- echo $"Usage: $0 {start|stop|status|restart}."
+ echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit 1
esac
-exit 0
+exit $?
diff --git a/extras/init.d/glusterd-SuSE.in b/extras/init.d/glusterd-SuSE.in
index 16cf8de6a..6259bab00 100755
--- a/extras/init.d/glusterd-SuSE.in
+++ b/extras/init.d/glusterd-SuSE.in
@@ -2,8 +2,8 @@
#
### BEGIN INIT INFO
# Provides: glusterd
-# Required-Start: $local_fs $network
-# Required-Stop:
+# Required-Start: $remote_fs $network
+# Required-Stop: $remote_fs $network
# Default-Start: 3 5
# Default-Stop:
# Short-Description: Gluster File System service for volume management
@@ -61,13 +61,17 @@ case $1 in
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/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
index 042eadcf2..65d445864 100755
--- a/extras/profiler/glusterfs-profiler
+++ b/extras/profiler/glusterfs-profiler
@@ -1,22 +1,15 @@
#!/usr/bin/env python
-# texttable - module for creating simple ASCII tables
-# Copyright (C) 2003-2010 Gerome Fournier <jefke(at)free.fr>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
+# Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com>
+# This file is part of GlusterFS.
#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+# 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
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/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
index ebb92a2a1..9148a73e2 100755
--- a/extras/rpc-coverage.sh
+++ b/extras/rpc-coverage.sh
@@ -398,8 +398,7 @@ function test_getxattr()
function test_removexattr()
{
setfattr -x trusted.testing $PFX/dir/file || fail "setfattr remove"
- getfattr -n trusted.testing $PFX/dir/file 2>&1 | grep -q 'No such attribute' \
- || fail "getfattr"
+ getfattr -n trusted.testing $PFXf/dir/file 2>&1 | grep -q "No such attribute"
}
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
index e1e396020..cb2a55fd5 100755
--- a/extras/test/gluster_commands.sh
+++ b/extras/test/gluster_commands.sh
@@ -1,21 +1,13 @@
#!/bin/bash
-# Copyright (c) 2006-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/>.
+# 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.
@@ -54,13 +46,13 @@ gluster volume start vol
gluster volume info
sleep 1
mount -t glusterfs `hostname`:vol /mnt/client
-sleep 1
+sleep 1
df -h
echo "adding-brick......."
gluster volume add-brick vol `hostname`:/exports/exp2
gluster volume info
-sleep 1
+sleep 1
umount /mnt/client
mount -t glusterfs `hostname`:vol /mnt/client
df -h
@@ -102,7 +94,7 @@ sleep 1
echo "removing brick......."
gluster --mode=script volume remove-brick vol `hostname`:/exports/exp2
gluster volume info
-sleep 1
+sleep 1
df -h
sleep 1
@@ -127,7 +119,7 @@ sleep 1
echo "starting replicate volume......"
gluster volume start mirror
gluster volume info
-sleep 1
+sleep 1
mount -t glusterfs `hostname`:mirror /mnt/client
sleep 1
df -h
@@ -136,7 +128,7 @@ sleep 1
echo "adding-brick......."
gluster volume add-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4
gluster volume info
-sleep 1
+sleep 1
df -h
sleep 1
@@ -178,14 +170,14 @@ sleep 1
echo "removeing-brick....."
gluster --mode=script volume remove-brick mirror `hostname`:/exports/exp3 `hostname`:/exports/exp4
gluster volume info
-sleep 1
+sleep 1
df -h
sleep 1
echo "stopping replicate volume....."
gluster --mode=script volume stop mirror
gluster volume info
-sleep 1
+sleep 1
umount /mnt/client
df -h
@@ -206,14 +198,14 @@ gluster volume start str
gluster volume info
sleep 1
mount -t glusterfs `hostname`:str /mnt/client
-sleep 1
+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
+sleep 1
df -h
sleep 1
diff --git a/extras/test/ld-preload-test/ld-preload-lib.c b/extras/test/ld-preload-test/ld-preload-lib.c
index e17305a4a..88afd14c3 100644
--- a/extras/test/ld-preload-test/ld-preload-lib.c
+++ b/extras/test/ld-preload-test/ld-preload-lib.c
@@ -1,23 +1,13 @@
/*
- Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com>
+ Copyright (c) 2007-2012 Red 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.
*/
-
/* LD PRELOAD'able library
* A very simple library that intercepts booster supported system calls
* and prints a log message to stdout.
diff --git a/extras/test/ld-preload-test/ld-preload-test.c b/extras/test/ld-preload-test/ld-preload-test.c
index 55dd98805..78772f598 100644
--- a/extras/test/ld-preload-test/ld-preload-test.c
+++ b/extras/test/ld-preload-test/ld-preload-test.c
@@ -1,23 +1,13 @@
/*
- Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com>
+ Copyright (c) 2007-2012 Red 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.
*/
-
/*
* LD PRELOAD Test Tool
*
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
index 2440af237..4b3839cf6 100755
--- a/extras/test/run.sh
+++ b/extras/test/run.sh
@@ -1,21 +1,12 @@
#!/bin/sh
-# Copyright (c) 2006-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/>.
+# 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
diff --git a/extras/test/stop_glusterd.sh b/extras/test/stop_glusterd.sh
index a84689beb..a2db13f42 100755
--- a/extras/test/stop_glusterd.sh
+++ b/extras/test/stop_glusterd.sh
@@ -1,21 +1,12 @@
#!/bin/bash
-# Copyright (c) 2006-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/>.
+# 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
diff --git a/extras/test/test-ffop.c b/extras/test/test-ffop.c
index 2c47ab004..2d174d452 100644
--- a/extras/test/test-ffop.c
+++ b/extras/test/test-ffop.c
@@ -6,20 +6,82 @@
#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;
- int fd = 0;
- char *filename = NULL;
- struct stat stbuf = {0,};
+ int ret = -1;
+ char filename[255] = {0,};
if (argc > 1)
- filename = argv[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");
- if (!filename)
- filename = "temp-xattr-test-file";
+ 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) {
@@ -34,6 +96,34 @@ main (int argc, char *argv[])
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));
@@ -103,3 +193,678 @@ out:
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}