[Sheepdog] [PATCH] Autotoolize sheepdog

Steven Dake sdake at redhat.com
Sat May 15 08:14:41 CEST 2010


On Fri, 2010-05-14 at 23:06 -0700, Steven Dake wrote:
> This patch contains the initial work to autotoolize sheepdog.  To generate the
> configure script, run the autogen.sh script.  Then run ./configure followed by
> make.  make install also works properly.
> 
> Then run configure as normal.  The configure.ac supports several options
> including --enable-profiling and --enable-debug as well as the standard GNU
> automake setup.
> 
> The warnings list is a pretty standard list of warning catches, but does
> generate alot of warning output.
> 
> One thing that is missing is using the git version field rather then
> PACKAGE_VERSION generated from configure.ac.
> 
> Finally, if you want to generate an output tarball, run make dist.
> 
> make distcheck verifies the make system included all the proper files to
> support a self-build.
> 

As a follow-up, when I first started developing software for GNU
platforms I was not interested in using autotools because I perceived it
difficult to maintain.  I can tell you from experience this perception
led to a long lapse in getting projects I work on merged into upstream
distros.

I found a nice article which gives a brief overview of how to setup a
project for automake and maintain the files:
http://www.freesoftwaremagazine.com/books/agaal/automatically_writing_makefiles_with_autotools

Regards
-steve

> Signed-off-by: Steven Dake <sdake at redhat.com>
> ---
>  Makefile            |   40 ----
>  Makefile.am         |   23 ++
>  autogen.sh          |    5 +
>  collie/Makefile     |   30 ---
>  configure.ac        |  326 ++++++++++++++++++++++++++
>  include/Makefile.am |    3 +
>  lib/Makefile        |    3 -
>  lib/Makefile.am     |    3 +
>  script/Makefile.am  |    3 +
>  sheep/Makefile      |   30 ---
>  sheep/Makefile.am   |   42 ++++
>  sheep/net.c         |  643 ---------------------------------------------------
>  sheep/sdnet.c       |  643 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  sheep/sheep.c       |    7 +-
>  sheep/store.c       |    3 +
>  15 files changed, 1056 insertions(+), 748 deletions(-)
>  delete mode 100644 Makefile
>  create mode 100644 Makefile.am
>  create mode 100755 autogen.sh
>  delete mode 100644 collie/Makefile
>  create mode 100644 configure.ac
>  create mode 100644 include/Makefile.am
>  delete mode 100644 lib/Makefile
>  create mode 100644 lib/Makefile.am
>  create mode 100644 script/Makefile.am
>  delete mode 100644 sheep/Makefile
>  create mode 100644 sheep/Makefile.am
>  delete mode 100644 sheep/net.c
>  create mode 100644 sheep/sdnet.c
> 
> diff --git a/Makefile b/Makefile
> deleted file mode 100644
> index 6f4f0c3..0000000
> --- a/Makefile
> +++ /dev/null
> @@ -1,40 +0,0 @@
> -VERSION ?= $(shell git log -1 --pretty=format:%h-%p || echo "unknown-version")
> -
> -PREFIX ?= /usr
> -
> -CHECK_CC = cgcc
> -CHECK_CC_FLAGS = '$(CHECK_CC) -Wbitwise -Wno-return-void -no-compile $(ARCH)'
> -
> -export VERSION PREFIX
> -
> -.PHONY:all
> -all:
> -	$(MAKE) -C sheep
> -	$(MAKE) -C collie
> -
> -.PHONY:clean
> -clean:
> -	$(MAKE) -C sheep clean
> -	$(MAKE) -C collie clean
> -	$(MAKE) -C lib clean
> -
> -.PHONY:install
> -install:
> -	$(MAKE) -C sheep install
> -	$(MAKE) -C collie install
> -
> -.PHONY:check
> -check: ARCH=$(shell sh script/checkarch.sh)
> -check:
> -	CC=$(CHECK_CC_FLAGS) $(MAKE) all
> -
> -.PHONY:check32
> -check32: override ARCH=-m32
> -check32:
> -	CC=$(CHECK_CC_FLAGS) $(MAKE) all
> -
> -.PHONY:check64
> -check64: override ARCH=-m64
> -check64:
> -	CC=$(CHECK_CC_FLAGS) $(MAKE) all
> -
> diff --git a/Makefile.am b/Makefile.am
> new file mode 100644
> index 0000000..fedd5ab
> --- /dev/null
> +++ b/Makefile.am
> @@ -0,0 +1,23 @@
> +EXTRA_DIST		= 
> +
> +AUTOMAKE_OPTIONS	= foreign
> +
> +MAINTAINERCLEANFILES	= Makefile.in aclocal.m4 configure depcomp	\
> +			  config.guess config.sub missing install-sh	\
> +			  autoheader automake autoconf config.status	\
> +			  config.log
> +
> +dist_doc_DATA		= 
> +
> +sheepdogsysconfdir	= ${SHEEPDOGCONFDIR}
> +
> +sheepdogsysconf_DATA	= 
> +
> +SUBDIRS			= collie sheep include script lib
> +
> +install-exec-local:
> +
> +uninstall-local:
> +
> +dist-clean-local:
> +	rm -f autoconf automake autoheader
> diff --git a/autogen.sh b/autogen.sh
> new file mode 100755
> index 0000000..83770a1
> --- /dev/null
> +++ b/autogen.sh
> @@ -0,0 +1,5 @@
> +#!/bin/sh
> +# Run this to generate all the initial makefiles, etc.
> +
> +echo Building configuration system...
> +autoreconf -i && echo Now run ./configure and make
> diff --git a/collie/Makefile b/collie/Makefile
> deleted file mode 100644
> index 98ef2b1..0000000
> --- a/collie/Makefile
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -sbindir ?= $(PREFIX)/sbin
> -
> -CFLAGS += -g -O2 -Wall -Wstrict-prototypes -I../include
> -CFLAGS += -D_GNU_SOURCE
> -LIBS += -lncurses
> -
> -PROGRAMS = collie
> -COLLIE_OBJS = collie.o treeview.o ../lib/event.o ../lib/net.o ../lib/logger.o
> -COLLIE_DEP = $(COLLIE_OBJS:.o=.d)
> -
> -.PHONY:all
> -all: $(PROGRAMS)
> -
> -collie: $(COLLIE_OBJS)
> -	$(CC) $^ -o $@ $(LIBS)
> -
> --include $(COLLIE_DEP)
> -
> -%.o: %.c
> -	$(CC) -c $(CFLAGS) $*.c -o $*.o
> -	@$(CC) -MM $(CFLAGS) -MF $*.d -MT $*.o $*.c
> -
> -.PHONY:clean
> -clean:
> -	rm -f *.[od] $(PROGRAMS)
> -
> -.PHONY:install
> -install: $(PROGRAMS)
> -	install -d -m 755 $(DESTDIR)$(sbindir)
> -	install -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir)
> diff --git a/configure.ac b/configure.ac
> new file mode 100644
> index 0000000..309ae79
> --- /dev/null
> +++ b/configure.ac
> @@ -0,0 +1,326 @@
> +#
> +# Copyright 2010 Red Hat, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; see the file COPYING.  If not, write to
> +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
> +#
> +
> +# bootstrap / init
> +AC_PREREQ([2.61])
> +
> +AC_INIT([sheepdog], [0.0.1], [sheepdog at lists.wpkg.org])
> +AM_INIT_AUTOMAKE([-Wno-portability])
> +
> +AC_CONFIG_SRCDIR([collie/collie.c])
> +AC_CONFIG_HEADER([include/config.h])
> +
> +AC_CANONICAL_HOST
> +
> +AC_LANG([C])
> +
> +dnl Fix default variables - "prefix" variable if not specified
> +if test "$prefix" = "NONE"; then
> +	prefix="/usr"
> +
> +	dnl Fix "localstatedir" variable if not specified
> +	if test "$localstatedir" = "\${prefix}/var"; then
> +		localstatedir="/var"
> +	fi
> +	dnl Fix "sysconfdir" variable if not specified
> +	if test "$sysconfdir" = "\${prefix}/etc"; then
> +		sysconfdir="/etc"
> +	fi
> +	dnl Fix "libdir" variable if not specified
> +	if test "$libdir" = "\${exec_prefix}/lib"; then
> +		if test -e /usr/lib64; then
> +			libdir="/usr/lib64"
> +		else
> +			libdir="/usr/lib"
> +		fi
> +	fi
> +fi
> +
> +# check stolen from gnulib/m4/gnu-make.m4
> +if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then
> +	AC_MSG_ERROR([you don't seem to have GNU make; it is required])
> +fi
> +
> +AC_PROG_CC
> +AC_PROG_INSTALL
> +AC_PROG_LN_S
> +AC_PROG_MAKE_SET
> +AC_PROG_RANLIB
> +AC_CHECK_PROGS([GROFF], [groff])
> +
> +# Checks for libraries.
> +AC_CHECK_LIB([socket], [socket])
> +
> +# Checks for header files.
> +AC_FUNC_ALLOCA
> +AC_HEADER_DIRENT
> +AC_HEADER_STDC
> +AC_HEADER_SYS_WAIT
> +AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdint.h \
> +		  stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h \
> +		  sys/time.h syslog.h unistd.h sys/types.h getopt.h malloc.h \
> +		  sys/sockio.h utmpx.h])
> +
> +# Checks for typedefs, structures, and compiler characteristics.
> +AC_C_CONST
> +AC_TYPE_UID_T
> +AC_C_INLINE
> +AC_TYPE_INT16_T
> +AC_TYPE_INT32_T
> +AC_TYPE_INT64_T
> +AC_TYPE_INT8_T
> +AC_TYPE_SIZE_T
> +AC_TYPE_SSIZE_T
> +AC_HEADER_TIME
> +AC_TYPE_UINT16_T
> +AC_TYPE_UINT32_T
> +AC_TYPE_UINT64_T
> +AC_TYPE_UINT8_T
> +AC_C_VOLATILE
> +
> +# Checks for library functions.
> +AC_FUNC_CLOSEDIR_VOID
> +AC_FUNC_ERROR_AT_LINE
> +AC_REPLACE_FNMATCH
> +AC_FUNC_FORK
> +AC_PROG_GCC_TRADITIONAL
> +AC_FUNC_MALLOC
> +AC_FUNC_MEMCMP
> +AC_FUNC_REALLOC
> +AC_FUNC_SELECT_ARGTYPES
> +AC_TYPE_SIGNAL
> +AC_FUNC_VPRINTF
> +AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
> +		getcwd getpeerucred getpeereid gettimeofday inet_ntoa memmove \
> +		memset mkdir scandir select socket strcasecmp strchr strdup \
> +		strerror strrchr strspn strstr])
> +
> +AC_CONFIG_FILES([Makefile
> +		collie/Makefile
> +		sheep/Makefile
> +		include/Makefile
> +		script/Makefile
> +		lib/Makefile])
> +
> +### Local business
> +
> +# ===============================================
> +# Helpers
> +# ===============================================
> +
> +## helper for CC stuff
> +cc_supports_flag() {
> +	local CFLAGS="$@"
> +	AC_MSG_CHECKING([whether $CC supports "$@"])
> +	AC_COMPILE_IFELSE([int main(){return 0;}] ,
> +			  [RC=0; AC_MSG_RESULT([yes])],
> +			  [RC=1; AC_MSG_RESULT([no])])
> +	return $RC
> +}
> +
> +## cleanup
> +AC_MSG_NOTICE(Sanitizing prefix: ${prefix})
> +case $prefix in
> +  NONE) prefix=/usr/local;;
> +esac
> +
> +AC_MSG_NOTICE(Sanitizing exec_prefix: ${exec_prefix})
> +case $exec_prefix in
> +  dnl For consistency with Sheepdog, map NONE->$prefix
> +  NONE)   exec_prefix=$prefix;;
> +  prefix) exec_prefix=$prefix;;
> +esac
> +
> +## local defines
> +PACKAGE_FEATURES=""
> +
> +LINT_FLAGS="-weak -unrecog +posixlib +ignoresigns -fcnuse \
> +	-badflag -D__gnuc_va_list=va_list -D__attribute\(x\)="
> +
> +AC_ARG_ENABLE([fatal-warnings],
> +	[  --enable-fatal-warnings : enable fatal warnings. ],
> +	[ default="no" ])
> +
> +AC_ARG_ENABLE([debug],
> +	[ --enable-debug          : enable debug build. ],
> +	[ default="no" ])
> +
> +AC_ARG_ENABLE([coverage],
> +	[  --enable-coverage       : coverage analysis of the codebase. ],
> +	[ default="no" ])
> +
> +AC_ARG_WITH([initddir],
> +	[  --with-initddir=DIR     : path to init script directory. ],
> +	[ INITDDIR="$withval" ],
> +	[ INITDDIR="$sysconfdir/init.d" ])
> +
> +CP=cp
> +OS_LDL="-ldl"
> +case "$host_os" in
> +	*linux*)
> +		AC_DEFINE_UNQUOTED([SHEEPDOG_LINUX], [1],
> +				   [Compiling for Linux platform])
> +		OS_CFLAGS=""
> +		OS_CPPFLAGS=""
> +		OS_LDFLAGS=""
> +		OS_DYFLAGS=""
> +		DARWIN_OPTS=""
> +	;;
> +	*)
> +		AC_MSG_ERROR([Unsupported OS? hmmmm])
> +	;;
> +esac
> +
> +AC_SUBST(CP)
> +# *FLAGS handling goes here
> +
> +ENV_CFLAGS="$CFLAGS"
> +ENV_CPPFLAGS="$CPPFLAGS"
> +ENV_LDFLAGS="$LDFLAGS"
> +
> +# debug build stuff
> +if test "x${enable_debug}" = xyes; then
> +	AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code])
> +	OPT_CFLAGS="-O0"
> +	PACKAGE_FEATURES="$PACKAGE_FEATURES debug"
> +fi
> +
> +# gdb flags
> +if test "x${GCC}" = xyes; then
> +	GDB_FLAGS="-ggdb3"
> +else
> +	GDB_FLAGS="-g"
> +fi
> +
> +PKG_CHECK_MODULES([ncurses],[ncurses])
> +PKG_CHECK_MODULES([corosync],[corosync])
> +PKG_CHECK_MODULES([libcpg],[libcpg])
> +PKG_CHECK_MODULES([libcfg],[libcfg])
> +
> +# extra warnings
> +EXTRA_WARNINGS=""
> +
> +WARNLIST="
> +	all
> +	shadow
> +	missing-prototypes
> +	missing-declarations
> +	strict-prototypes
> +	declaration-after-statement
> +	pointer-arith
> +	write-strings
> +	cast-align
> +	bad-function-cast
> +	missing-format-attribute
> +	format=2
> +	format-security
> +	format-nonliteral
> +	no-long-long
> +	unsigned-char
> +	gnu89-inline
> +	no-strict-aliasing
> +	"
> +
> +for j in $WARNLIST; do
> +	if cc_supports_flag -W$j; then
> +		EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j";
> +	fi
> +done
> +
> +if test "x${enable_coverage}" = xyes && \
> +		cc_supports_flag -ftest-coverage && \
> +		cc_supports_flag -fprofile-arcs ; then
> +	AC_MSG_NOTICE([Enabling Coverage (enable -O0 by default)])
> +	OPT_CFLAGS="-O0"
> +	COVERAGE_CFLAGS="-ftest-coverage -fprofile-arcs"
> +	COVERAGE_LDFLAGS="-ftest-coverage -fprofile-arcs"
> +	PACKAGE_FEATURES="$PACKAGE_FEATURES coverage"
> +else
> +	COVERAGE_CFLAGS=""
> +	COVERAGE_LDFLAGS=""
> +fi
> +
> +
> +if test "x${enable_fatal_warnings}" = xyes && \
> +		cc_supports_flag -Werror ; then
> +	AC_MSG_NOTICE([Enabling Fatal Warnings (-Werror)])
> +	WERROR_CFLAGS="-Werror"
> +	PACKAGE_FEATURES="$PACKAGE_FEATURES fatal-warnings"
> +else
> +	WERROR_CFLAGS=""
> +fi
> +
> +# final build of *FLAGS
> +CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS $OS_CFLAGS \
> +	$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS $NSS_CFLAGS"
> +CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS $OS_CPPFLAGS"
> +LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS"
> +
> +# substitute what we need:
> +AC_SUBST([OS_DYFLAGS])
> +
> +AM_CONDITIONAL(BUILD_HTML_DOCS, test -n "${GROFF}")
> +
> +AC_SUBST([LINT_FLAGS])
> +
> +AC_DEFINE_UNQUOTED([LOCALSTATEDIR], "$(eval echo ${localstatedir})", [localstate directory])
> +
> +COROSYSCONFDIR=${sysconfdir}/sheepdog
> +AC_SUBST([COROSYSCONFDIR])
> +AC_DEFINE_UNQUOTED([COROSYSCONFDIR], "$(eval echo ${COROSYSCONFDIR})", [sheepdog config directory])
> +
> +AC_DEFINE_UNQUOTED([PACKAGE_FEATURES], "${PACKAGE_FEATURES}", [sheepdog built-in features])
> +
> +AC_OUTPUT
> +
> +AC_MSG_RESULT([])
> +AC_MSG_RESULT([$PACKAGE configuration:])
> +AC_MSG_RESULT([  Version                  = ${VERSION}])
> +AC_MSG_RESULT([  Prefix                   = ${prefix}])
> +AC_MSG_RESULT([  Executables              = ${sbindir}])
> +AC_MSG_RESULT([  Man pages                = ${mandir}])
> +AC_MSG_RESULT([  Doc dir                  = ${docdir}])
> +AC_MSG_RESULT([  Libraries                = ${libdir}])
> +AC_MSG_RESULT([  Header files             = ${includedir}])
> +AC_MSG_RESULT([  Arch-independent files   = ${datadir}])
> +AC_MSG_RESULT([  State information        = ${localstatedir}])
> +AC_MSG_RESULT([  System configuration     = ${sysconfdir}])
> +AC_MSG_RESULT([  System init.d directory  = ${INITDDIR}])
> +AC_MSG_RESULT([  sheepdog config dir      = ${COROSYSCONFDIR}])
> +AC_MSG_RESULT([  Features                 =${PACKAGE_FEATURES}])
> +AC_MSG_RESULT([])
> +AC_MSG_RESULT([$PACKAGE build info:])
> +AC_MSG_RESULT([  Library SONAME           = ${SONAME}])
> +LIB_MSG_RESULT(m4_shift(local_soname_list))dnl
> +AC_MSG_RESULT([  Default optimization     = ${OPT_CFLAGS}])
> +AC_MSG_RESULT([  Default debug options    = ${GDB_CFLAGS}])
> +AC_MSG_RESULT([  Extra compiler warnings  = ${EXTRA_WARNING}])
> +AC_MSG_RESULT([  Env. defined CFLAG       = ${ENV_CFLAGS}])
> +AC_MSG_RESULT([  Env. defined CPPFLAGS    = ${ENV_CPPFLAGS}])
> +AC_MSG_RESULT([  Env. defined LDFLAGS     = ${ENV_LDFLAGS}])
> +AC_MSG_RESULT([  OS   defined CFLAGS      = ${OS_CFLAGS}])
> +AC_MSG_RESULT([  OS   defined CPPFLAGS    = ${OS_CPPFLAGS}])
> +AC_MSG_RESULT([  OS   defined LDFLAGS     = ${OS_LDFLAGS}])
> +AC_MSG_RESULT([  OS   defined LDL         = ${OS_LDL}])
> +AC_MSG_RESULT([  OS   defined DYFLAGS     = ${OS_DYFLAGS}])
> +AC_MSG_RESULT([  ANSI defined CPPFLAGS    = ${ANSI_CPPFLAGS}])
> +AC_MSG_RESULT([  Coverage     CFLAGS      = ${COVERAGE_CFLAGS}])
> +AC_MSG_RESULT([  Coverage     LDFLAGS     = ${COVERAGE_LDFLAGS}])
> +AC_MSG_RESULT([  Fatal War.   CFLAGS      = ${WERROR_CFLAGS}])
> +AC_MSG_RESULT([  Final        CFLAGS      = ${CFLAGS}])
> +AC_MSG_RESULT([  Final        CPPFLAGS    = ${CPPFLAGS}])
> +AC_MSG_RESULT([  Final        LDFLAGS     = ${LDFLAGS}])
> diff --git a/include/Makefile.am b/include/Makefile.am
> new file mode 100644
> index 0000000..94c530e
> --- /dev/null
> +++ b/include/Makefile.am
> @@ -0,0 +1,3 @@
> +MAINTAINERCLEANFILES    = Makefile.in config.h.in
> +
> +noinst_HEADERS          = bitops.h  event.h  logger.h sheepdog_proto.h util.h list.h  net.h sheep.h
> diff --git a/lib/Makefile b/lib/Makefile
> deleted file mode 100644
> index ad4245b..0000000
> --- a/lib/Makefile
> +++ /dev/null
> @@ -1,3 +0,0 @@
> -.PHONY:clean
> -clean:
> -	rm -f *.[od]
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> new file mode 100644
> index 0000000..2375b68
> --- /dev/null
> +++ b/lib/Makefile.am
> @@ -0,0 +1,3 @@
> +MAINTAINERCLEANFILES    = Makefile.in config.h.in
> +
> +noinst_HEADERS          = event.c logger.c net.c
> diff --git a/script/Makefile.am b/script/Makefile.am
> new file mode 100644
> index 0000000..3e6c380
> --- /dev/null
> +++ b/script/Makefile.am
> @@ -0,0 +1,3 @@
> +MAINTAINERCLEANFILES    = Makefile.in
> +
> +noinst_HEADERS		= bash_completion_collie checkarch.sh check-dog.pl start-sheepdog stop-sheepdog vditest
> diff --git a/sheep/Makefile b/sheep/Makefile
> deleted file mode 100644
> index 089bb7d..0000000
> --- a/sheep/Makefile
> +++ /dev/null
> @@ -1,30 +0,0 @@
> -sbindir ?= $(PREFIX)/sbin
> -
> -CFLAGS += -g -O2 -Wall -Wstrict-prototypes -I../include
> -CFLAGS += -D_GNU_SOURCE -DSD_VERSION=\"$(VERSION)\"
> -LIBS += -lpthread -lcpg -lcfg
> -
> -PROGRAMS = sheep
> -SHEEP_OBJS = sheep.o net.o vdi.o group.o store.o work.o ../lib/event.o ../lib/net.o ../lib/logger.o
> -SHEEP_DEP = $(SHEEP_OBJS:.o=.d)
> -
> -.PHONY:all
> -all: $(PROGRAMS)
> -
> -sheep: $(SHEEP_OBJS)
> -	$(CC) $^ -o $@ $(LIBS)
> -
> --include $(SHEEP_DEP)
> -
> -%.o: %.c
> -	$(CC) -c $(CFLAGS) $*.c -o $*.o
> -	@$(CC) -MM $(CFLAGS) -MF $*.d -MT $*.o $*.c
> -
> -.PHONY:clean
> -clean:
> -	rm -f *.[od] $(PROGRAMS)
> -
> -.PHONY:install
> -install: $(PROGRAMS)
> -	install -d -m 755 $(DESTDIR)$(sbindir)
> -	install -m 755 $(PROGRAMS) $(DESTDIR)$(sbindir)
> diff --git a/sheep/Makefile.am b/sheep/Makefile.am
> new file mode 100644
> index 0000000..4f68683
> --- /dev/null
> +++ b/sheep/Makefile.am
> @@ -0,0 +1,42 @@
> +#
> +# Copyright 2010 Red Hat, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; see the file COPYING.  If not, write to
> +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
> +#
> +
> +MAINTAINERCLEANFILES	= Makefile.in
> +
> +AM_CFLAGS		=
> +
> +INCLUDES		= -I$(top_builddir)/include -I$(top_srcdir)/include $(libcpg_CFLAGS) $(libcfg_CFLAGS)
> +
> +sbin_PROGRAMS		= sheep
> +
> +sheep_SOURCES		= sheep.c group.c sdnet.c store.c vdi.c work.c ../lib/event.c ../lib/logger.c ../lib/net.c
> +sheep_LDADD	  	= $(libcpg_LIBS) $(libcfg_LIBS)
> +sheep_DEPENDENCIES	= 
> +
> +
> +noinst_HEADERS		= work.h sheep_priv.h
> +
> +EXTRA_DIST		= 
> +
> +lint:
> +	-splint $(INCLUDES) $(LINT_FLAGS) $(CFLAGS) *.c
> +
> +all-local: 
> +	@echo Built sheep
> +
> +clean-local:
> +	rm -f sheep *.o gmon.out *.da *.bb *.bbg
> diff --git a/sheep/net.c b/sheep/net.c
> deleted file mode 100644
> index f1ce8ea..0000000
> --- a/sheep/net.c
> +++ /dev/null
> @@ -1,643 +0,0 @@
> -/*
> - * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License version
> - * 2 as published by the Free Software Foundation.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <unistd.h>
> -#include <netinet/tcp.h>
> -#include <sys/epoll.h>
> -
> -#include "sheep_priv.h"
> -
> -int is_io_request(unsigned op)
> -{
> -	int ret = 0;
> -
> -	switch (op) {
> -	case SD_OP_CREATE_AND_WRITE_OBJ:
> -	case SD_OP_REMOVE_OBJ:
> -	case SD_OP_READ_OBJ:
> -	case SD_OP_WRITE_OBJ:
> -		ret = 1;
> -		break;
> -	default:
> -		break;
> -	}
> -
> -	return ret;
> -}
> -
> -void resume_pending_requests(void)
> -{
> -	struct request *next, *tmp;
> -
> -	list_for_each_entry_safe(next, tmp, &sys->req_wait_for_obj_list,
> -				 r_wlist) {
> -		struct cpg_event *cevent = &next->cev;
> -
> -		list_del(&next->r_wlist);
> -		list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> -	}
> -
> -	if (!list_empty(&sys->cpg_event_siblings))
> -		start_cpg_event_work();
> -}
> -
> -static int is_access_local(struct sheepdog_node_list_entry *e, int nr_nodes,
> -			   uint64_t oid, int copies)
> -{
> -	int i, n;
> -
> -	for (i = 0; i < copies; i++) {
> -		n = obj_to_sheep(e, nr_nodes, oid, i);
> -
> -		if (is_myself(&e[n]))
> -			return 1;
> -	}
> -
> -	return 0;
> -}
> -
> -static void setup_access_to_local_objects(struct request *req)
> -{
> -	struct sd_obj_req *hdr = (struct sd_obj_req *)&req->rq;
> -	int copies;
> -
> -	if (hdr->flags & SD_FLAG_CMD_DIRECT) {
> -		req->local_oid[0] = hdr->oid;
> -
> -		if (hdr->flags & SD_FLAG_CMD_COW)
> -			req->local_oid[1] = hdr->cow_oid;
> -
> -		return;
> -	}
> -
> -	copies = hdr->copies;
> -	if (!copies)
> -		copies = sys->nr_sobjs;
> -
> -	if (is_access_local(req->entry, req->nr_nodes, hdr->oid, copies))
> -		req->local_oid[0] = hdr->oid;
> -
> -	if ((hdr->flags & SD_FLAG_CMD_COW) &&
> -	    is_access_local(req->entry, req->nr_nodes, hdr->cow_oid, copies))
> -		req->local_oid[1] = hdr->cow_oid;
> -}
> -
> -static void __done(struct work *work, int idx)
> -{
> -	struct request *req = container_of(work, struct request, work);
> -	struct sd_req *hdr = (struct sd_req *)&req->rq;
> -	int again = 0;
> -
> -	switch (hdr->opcode) {
> -	case SD_OP_NEW_VDI:
> -	case SD_OP_DEL_VDI:
> -	case SD_OP_LOCK_VDI:
> -	case SD_OP_RELEASE_VDI:
> -	case SD_OP_GET_VDI_INFO:
> -	case SD_OP_MAKE_FS:
> -	case SD_OP_SHUTDOWN:
> -		/* request is forwarded to cpg group */
> -		return;
> -	}
> -
> -	if (is_io_request(hdr->opcode)) {
> -		struct cpg_event *cevent = &req->cev;
> -
> -		list_del(&req->r_wlist);
> -
> -		sys->nr_outstanding_io--;
> -		/*
> -		 * TODO: if the request failed due to epoch unmatch,
> -		 * we should retry here (adds this request to the tail
> -		 * of sys->cpg_event_siblings.
> -		 */
> -
> -		if (!(req->rq.flags & SD_FLAG_CMD_DIRECT) &&
> -		    (req->rp.result == SD_RES_OLD_NODE_VER ||
> -		     req->rp.result == SD_RES_NEW_NODE_VER)) {
> -
> -
> -			req->rq.epoch = sys->epoch;
> -			req->nr_nodes = setup_ordered_sd_node_list(req);
> -			setup_access_to_local_objects(req);
> -
> -			list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> -			again = 1;
> -		}
> -
> -		resume_pending_requests();
> -		resume_recovery_work();
> -	}
> -
> -	if (!again)
> -		req->done(req);
> -}
> -
> -static void queue_request(struct request *req)
> -{
> -	struct cpg_event *cevent = &req->cev;
> -
> -	struct sd_req *hdr = (struct sd_req *)&req->rq;
> -	struct sd_rsp *rsp = (struct sd_rsp *)&req->rp;
> -
> -	if (hdr->opcode == SD_OP_KILL_NODE) {
> -		log_close();
> -		exit(1);
> -	}
> -
> -	if (sys->status == SD_STATUS_SHUTDOWN) {
> -		rsp->result = SD_RES_SHUTDOWN;
> -		req->done(req);
> -		return;
> -	}
> -
> -	if (sys->status == SD_STATUS_JOIN_FAILED) {
> -		rsp->result = SD_RES_JOIN_FAILED;
> -		req->done(req);
> -		return;
> -	}
> -
> -	if (sys->status == SD_STATUS_WAIT_FOR_FORMAT ||
> -	    sys->status == SD_STATUS_WAIT_FOR_JOIN) {
> -		/* TODO: cleanup */
> -		switch (hdr->opcode) {
> -		case SD_OP_STAT_CLUSTER:
> -		case SD_OP_MAKE_FS:
> -		case SD_OP_GET_NODE_LIST:
> -		case SD_OP_READ_VDIS:
> -			break;
> -		default:
> -			if (sys->status == SD_STATUS_WAIT_FOR_FORMAT)
> -				rsp->result = SD_RES_WAIT_FOR_FORMAT;
> -			else
> -				rsp->result = SD_RES_WAIT_FOR_JOIN;
> -			req->done(req);
> -			return;
> -		}
> -	}
> -
> -	switch (hdr->opcode) {
> -	case SD_OP_CREATE_AND_WRITE_OBJ:
> -	case SD_OP_REMOVE_OBJ:
> -	case SD_OP_READ_OBJ:
> -	case SD_OP_WRITE_OBJ:
> -	case SD_OP_STAT_SHEEP:
> -	case SD_OP_GET_OBJ_LIST:
> -		req->work.fn = store_queue_request;
> -		break;
> -	case SD_OP_GET_NODE_LIST:
> -	case SD_OP_GET_VM_LIST:
> -	case SD_OP_NEW_VDI:
> -	case SD_OP_DEL_VDI:
> -	case SD_OP_LOCK_VDI:
> -	case SD_OP_RELEASE_VDI:
> -	case SD_OP_GET_VDI_INFO:
> -	case SD_OP_MAKE_FS:
> -	case SD_OP_SHUTDOWN:
> -	case SD_OP_STAT_CLUSTER:
> -		req->work.fn = cluster_queue_request;
> -		break;
> -	case SD_OP_READ_VDIS:
> -		rsp->result = read_vdis(req->data, hdr->data_length, &rsp->data_length);
> -		req->done(req);
> -		return;
> -	default:
> -		eprintf("unknown operation %d\n", hdr->opcode);
> -		rsp->result = SD_RES_SYSTEM_ERROR;
> -		req->done(req);
> -		return;
> -	}
> -
> -	req->work.done = __done;
> -
> -	list_del(&req->r_wlist);
> -
> -	/*
> -	 * we set epoch for non direct requests here. Note that we
> -	 * can't access to sys->epoch after calling
> -	 * start_cpg_event_work(that is, passing requests to work
> -	 * threads).
> -	 */
> -	if (!(hdr->flags & SD_FLAG_CMD_DIRECT))
> -		hdr->epoch = sys->epoch;
> -
> -	req->nr_nodes = setup_ordered_sd_node_list(req);
> -	setup_access_to_local_objects(req);
> -
> -	cevent->ctype = CPG_EVENT_REQUEST;
> -	list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> -	start_cpg_event_work();
> -}
> -
> -static struct request *alloc_request(struct client_info *ci, int data_length)
> -{
> -	struct request *req;
> -
> -	req = zalloc(sizeof(struct request) + data_length);
> -	if (!req)
> -		return NULL;
> -
> -	req->ci = ci;
> -	if (data_length)
> -		req->data = (char *)req + sizeof(*req);
> -
> -	list_add(&req->r_siblings, &ci->reqs);
> -	INIT_LIST_HEAD(&req->r_wlist);
> -
> -	return req;
> -}
> -
> -static void free_request(struct request *req)
> -{
> -	list_del(&req->r_siblings);
> -	free(req);
> -}
> -
> -static void req_done(struct request *req)
> -{
> -	list_add(&req->r_wlist, &req->ci->done_reqs);
> -	conn_tx_on(&req->ci->conn);
> -}
> -
> -static void init_rx_hdr(struct client_info *ci)
> -{
> -	ci->conn.c_rx_state = C_IO_HEADER;
> -	ci->rx_req = NULL;
> -	ci->conn.rx_length = sizeof(struct sd_req);
> -	ci->conn.rx_buf = &ci->conn.rx_hdr;
> -}
> -
> -static void client_rx_handler(struct client_info *ci)
> -{
> -	int ret;
> -	uint64_t data_len;
> -	struct connection *conn = &ci->conn;
> -	struct sd_req *hdr = &conn->rx_hdr;
> -	struct request *req;
> -
> -	switch (conn->c_rx_state) {
> -	case C_IO_HEADER:
> -		ret = rx(conn, C_IO_DATA_INIT);
> -		if (!ret || conn->c_rx_state != C_IO_DATA_INIT)
> -			break;
> -	case C_IO_DATA_INIT:
> -		data_len = hdr->data_length;
> -
> -		req = alloc_request(ci, data_len);
> -		if (!req) {
> -			conn->c_rx_state = C_IO_CLOSED;
> -			break;
> -		}
> -		ci->rx_req = req;
> -
> -		/* use le_to_cpu */
> -		memcpy(&req->rq, hdr, sizeof(req->rq));
> -
> -		if (data_len && hdr->flags & SD_FLAG_CMD_WRITE) {
> -			conn->c_rx_state = C_IO_DATA;
> -			conn->rx_length = data_len;
> -			conn->rx_buf = req->data;
> -		} else {
> -			conn->c_rx_state = C_IO_END;
> -			break;
> -		}
> -	case C_IO_DATA:
> -		ret = rx(conn, C_IO_END);
> -		break;
> -	default:
> -		eprintf("BUG: unknown state %d\n", conn->c_rx_state);
> -	}
> -
> -	if (is_conn_dead(conn) || conn->c_rx_state != C_IO_END)
> -		return;
> -
> -	/* now we have a complete command */
> -
> -	req = ci->rx_req;
> -
> -	init_rx_hdr(ci);
> -
> -	if (hdr->flags & SD_FLAG_CMD_WRITE)
> -		req->rp.data_length = 0;
> -	else
> -		req->rp.data_length = hdr->data_length;
> -
> -	req->done = req_done;
> -
> -	queue_request(req);
> -}
> -
> -static void init_tx_hdr(struct client_info *ci)
> -{
> -	struct sd_rsp *rsp = (struct sd_rsp *)&ci->conn.tx_hdr;
> -	struct request *req;
> -
> -	if (ci->tx_req || list_empty(&ci->done_reqs))
> -		return;
> -
> -	memset(rsp, 0, sizeof(*rsp));
> -
> -	req = list_first_entry(&ci->done_reqs, struct request, r_wlist);
> -	list_del(&req->r_wlist);
> -
> -	ci->tx_req = req;
> -	ci->conn.tx_length = sizeof(*rsp);
> -	ci->conn.c_tx_state = C_IO_HEADER;
> -	ci->conn.tx_buf = rsp;
> -
> -	/* use cpu_to_le */
> -	memcpy(rsp, &req->rp, sizeof(*rsp));
> -
> -	rsp->epoch = sys->epoch;
> -	rsp->opcode = req->rq.opcode;
> -	rsp->id = req->rq.id;
> -}
> -
> -static void client_tx_handler(struct client_info *ci)
> -{
> -	int ret, opt;
> -	struct sd_rsp *rsp = (struct sd_rsp *)&ci->conn.tx_hdr;
> -
> -again:
> -	init_tx_hdr(ci);
> -	if (!ci->tx_req) {
> -		conn_tx_off(&ci->conn);
> -		return;
> -	}
> -
> -	opt = 1;
> -	setsockopt(ci->conn.fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
> -
> -	switch (ci->conn.c_tx_state) {
> -	case C_IO_HEADER:
> -		if (rsp->data_length)
> -			ret = tx(&ci->conn, C_IO_DATA_INIT, MSG_MORE);
> -		else
> -			ret = tx(&ci->conn, C_IO_DATA_INIT, 0);
> -
> -		if (!ret)
> -			break;
> -
> -		if (rsp->data_length) {
> -			ci->conn.tx_length = rsp->data_length;
> -			ci->conn.tx_buf = ci->tx_req->data;
> -			ci->conn.c_tx_state = C_IO_DATA;
> -		} else {
> -			ci->conn.c_tx_state = C_IO_END;
> -			break;
> -		}
> -	case C_IO_DATA:
> -		ret = tx(&ci->conn, C_IO_END, 0);
> -		if (!ret)
> -			break;
> -	default:
> -		break;
> -	}
> -
> -	opt = 0;
> -	setsockopt(ci->conn.fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
> -
> -	if (is_conn_dead(&ci->conn) || ci->conn.c_tx_state != C_IO_END)
> -		return;
> -
> -	if (ci->conn.c_tx_state == C_IO_END) {
> -		free_request(ci->tx_req);
> -		ci->tx_req = NULL;
> -		goto again;
> -	}
> -}
> -
> -static void destroy_client(struct client_info *ci)
> -{
> -	close(ci->conn.fd);
> -	free(ci);
> -}
> -
> -static struct client_info *create_client(int fd, struct cluster_info *cluster)
> -{
> -	struct client_info *ci;
> -
> -	ci = zalloc(sizeof(*ci));
> -	if (!ci)
> -		return NULL;
> -
> -	ci->conn.fd = fd;
> -
> -	INIT_LIST_HEAD(&ci->reqs);
> -	INIT_LIST_HEAD(&ci->done_reqs);
> -
> -	init_rx_hdr(ci);
> -
> -	return ci;
> -}
> -
> -static void client_handler(int fd, int events, void *data)
> -{
> -	struct client_info *ci = (struct client_info *)data;
> -
> -	if (events & EPOLLIN)
> -		client_rx_handler(ci);
> -
> -	if (!is_conn_dead(&ci->conn) && events & EPOLLOUT)
> -		client_tx_handler(ci);
> -
> -	if (is_conn_dead(&ci->conn)) {
> -		dprintf("closed a connection, %d\n", fd);
> -		unregister_event(fd);
> -		destroy_client(ci);
> -	}
> -}
> -
> -static void listen_handler(int listen_fd, int events, void *data)
> -{
> -	struct sockaddr_storage from;
> -	socklen_t namesize;
> -	int fd, ret, opt;
> -	struct client_info *ci;
> -
> -	namesize = sizeof(from);
> -	fd = accept(listen_fd, (struct sockaddr *)&from, &namesize);
> -	if (fd < 0) {
> -		eprintf("can't accept a new connection, %m\n");
> -		return;
> -	}
> -
> -	opt = 1;
> -	ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
> -	if (ret) {
> -		close(fd);
> -		return;
> -	}
> -
> -	ci = create_client(fd, data);
> -	if (!ci) {
> -		close(fd);
> -		return;
> -	}
> -
> -	ret = register_event(fd, client_handler, ci);
> -	if (ret) {
> -		destroy_client(ci);
> -		return;
> -	}
> -
> -	dprintf("accepted a new connection, %d\n", fd);
> -}
> -
> -static int create_listen_port_fn(int fd, void *data)
> -{
> -	return register_event(fd, listen_handler, data);
> -}
> -
> -int create_listen_port(int port, void *data)
> -{
> -	return create_listen_ports(port, create_listen_port_fn, data);
> -}
> -
> -int write_object(struct sheepdog_node_list_entry *e,
> -		 int nodes, uint32_t node_version,
> -		 uint64_t oid, char *data, unsigned int datalen,
> -		 uint64_t offset, int nr, int create)
> -{
> -	struct sd_obj_req hdr;
> -	int i, n, fd, ret, success = 0;
> -	uint16_t vosts[3];
> -	char name[128];
> -
> -	for (i = 0; i < nr; i++) {
> -		unsigned rlen = 0, wlen = datalen;
> -
> -		n = obj_to_sheep(e, nodes, oid, i);
> -
> -		addr_to_str(name, sizeof(name), e[n].addr, 0);
> -
> -		fd = connect_to(name, e[n].port);
> -		if (fd < 0) {
> -			eprintf("can't connect to vost %u, %s\n", vosts[i], name);
> -			continue;
> -		}
> -
> -		memset(&hdr, 0, sizeof(hdr));
> -		hdr.epoch = node_version;
> -		if (create)
> -			hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
> -		else
> -			hdr.opcode = SD_OP_WRITE_OBJ;
> -
> -		hdr.oid = oid;
> -		hdr.copies = nr;
> -
> -		hdr.flags = SD_FLAG_CMD_WRITE | SD_FLAG_CMD_DIRECT;
> -		hdr.data_length = wlen;
> -		hdr.offset = offset;
> -
> -		ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
> -		close(fd);
> -		if (ret)
> -			eprintf("can't update vost %u, %s\n", vosts[i], name);
> -		else
> -			success++;
> -	}
> -
> -	return !success;
> -}
> -
> -int read_object(struct sheepdog_node_list_entry *e,
> -		int nodes, uint32_t node_version,
> -		uint64_t oid, char *data, unsigned int datalen,
> -		uint64_t offset, int nr)
> -{
> -	struct sd_obj_req hdr;
> -	struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
> -	char name[128];
> -	int i = 0, n, fd, ret;
> -
> -	for (i = 0; i < nr; i++) {
> -		unsigned wlen = 0, rlen = datalen;
> -
> -		n = obj_to_sheep(e, nodes, oid, i);
> -
> -		addr_to_str(name, sizeof(name), e[n].addr, 0);
> -
> -		fd = connect_to(name, e[n].port);
> -		if (fd < 0) {
> -			printf("%s(%d): %s, %m\n", __func__, __LINE__,
> -			       name);
> -			return -1;
> -		}
> -
> -		memset(&hdr, 0, sizeof(hdr));
> -		hdr.epoch = node_version;
> -		hdr.opcode = SD_OP_READ_OBJ;
> -		hdr.oid = oid;
> -
> -		hdr.flags =  SD_FLAG_CMD_DIRECT;
> -		hdr.data_length = rlen;
> -		hdr.offset = offset;
> -
> -		ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
> -		close(fd);
> -
> -		if (!ret) {
> -			if (rsp->result == SD_RES_SUCCESS)
> -				return rsp->data_length;
> -		}
> -	}
> -
> -	return -1;
> -}
> -
> -int remove_object(struct sheepdog_node_list_entry *e,
> -		  int nodes, uint32_t node_version,
> -		  uint64_t oid, int nr)
> -{
> -	char name[128];
> -	struct sd_obj_req hdr;
> -	struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
> -	int i = 0, n, fd, ret;
> -
> -	if (nr > nodes)
> -		nr = nodes;
> -
> -	for (i = 0; i < nr; i++) {
> -		unsigned wlen = 0, rlen = 0;
> -
> -		n = obj_to_sheep(e, nodes, oid, i);
> -
> -		addr_to_str(name, sizeof(name), e[n].addr, 0);
> -
> -		fd = connect_to(name, e[n].port);
> -		if (fd < 0) {
> -			rsp->result = SD_RES_EIO;
> -			return -1;
> -		}
> -
> -		memset(&hdr, 0, sizeof(hdr));
> -		hdr.epoch = node_version;
> -		hdr.opcode = SD_OP_REMOVE_OBJ;
> -		hdr.oid = oid;
> -
> -		hdr.flags = 0;
> -		hdr.data_length = rlen;
> -
> -		ret = exec_req(fd, (struct sd_req *)&hdr, NULL, &wlen, &rlen);
> -		close(fd);
> -
> -		if (ret)
> -			return -1;
> -	}
> -
> -	if (rsp->result != SD_RES_SUCCESS)
> -		return -1;
> -
> -	return 0;
> -}
> diff --git a/sheep/sdnet.c b/sheep/sdnet.c
> new file mode 100644
> index 0000000..f1ce8ea
> --- /dev/null
> +++ b/sheep/sdnet.c
> @@ -0,0 +1,643 @@
> +/*
> + * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <netinet/tcp.h>
> +#include <sys/epoll.h>
> +
> +#include "sheep_priv.h"
> +
> +int is_io_request(unsigned op)
> +{
> +	int ret = 0;
> +
> +	switch (op) {
> +	case SD_OP_CREATE_AND_WRITE_OBJ:
> +	case SD_OP_REMOVE_OBJ:
> +	case SD_OP_READ_OBJ:
> +	case SD_OP_WRITE_OBJ:
> +		ret = 1;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +void resume_pending_requests(void)
> +{
> +	struct request *next, *tmp;
> +
> +	list_for_each_entry_safe(next, tmp, &sys->req_wait_for_obj_list,
> +				 r_wlist) {
> +		struct cpg_event *cevent = &next->cev;
> +
> +		list_del(&next->r_wlist);
> +		list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> +	}
> +
> +	if (!list_empty(&sys->cpg_event_siblings))
> +		start_cpg_event_work();
> +}
> +
> +static int is_access_local(struct sheepdog_node_list_entry *e, int nr_nodes,
> +			   uint64_t oid, int copies)
> +{
> +	int i, n;
> +
> +	for (i = 0; i < copies; i++) {
> +		n = obj_to_sheep(e, nr_nodes, oid, i);
> +
> +		if (is_myself(&e[n]))
> +			return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +static void setup_access_to_local_objects(struct request *req)
> +{
> +	struct sd_obj_req *hdr = (struct sd_obj_req *)&req->rq;
> +	int copies;
> +
> +	if (hdr->flags & SD_FLAG_CMD_DIRECT) {
> +		req->local_oid[0] = hdr->oid;
> +
> +		if (hdr->flags & SD_FLAG_CMD_COW)
> +			req->local_oid[1] = hdr->cow_oid;
> +
> +		return;
> +	}
> +
> +	copies = hdr->copies;
> +	if (!copies)
> +		copies = sys->nr_sobjs;
> +
> +	if (is_access_local(req->entry, req->nr_nodes, hdr->oid, copies))
> +		req->local_oid[0] = hdr->oid;
> +
> +	if ((hdr->flags & SD_FLAG_CMD_COW) &&
> +	    is_access_local(req->entry, req->nr_nodes, hdr->cow_oid, copies))
> +		req->local_oid[1] = hdr->cow_oid;
> +}
> +
> +static void __done(struct work *work, int idx)
> +{
> +	struct request *req = container_of(work, struct request, work);
> +	struct sd_req *hdr = (struct sd_req *)&req->rq;
> +	int again = 0;
> +
> +	switch (hdr->opcode) {
> +	case SD_OP_NEW_VDI:
> +	case SD_OP_DEL_VDI:
> +	case SD_OP_LOCK_VDI:
> +	case SD_OP_RELEASE_VDI:
> +	case SD_OP_GET_VDI_INFO:
> +	case SD_OP_MAKE_FS:
> +	case SD_OP_SHUTDOWN:
> +		/* request is forwarded to cpg group */
> +		return;
> +	}
> +
> +	if (is_io_request(hdr->opcode)) {
> +		struct cpg_event *cevent = &req->cev;
> +
> +		list_del(&req->r_wlist);
> +
> +		sys->nr_outstanding_io--;
> +		/*
> +		 * TODO: if the request failed due to epoch unmatch,
> +		 * we should retry here (adds this request to the tail
> +		 * of sys->cpg_event_siblings.
> +		 */
> +
> +		if (!(req->rq.flags & SD_FLAG_CMD_DIRECT) &&
> +		    (req->rp.result == SD_RES_OLD_NODE_VER ||
> +		     req->rp.result == SD_RES_NEW_NODE_VER)) {
> +
> +
> +			req->rq.epoch = sys->epoch;
> +			req->nr_nodes = setup_ordered_sd_node_list(req);
> +			setup_access_to_local_objects(req);
> +
> +			list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> +			again = 1;
> +		}
> +
> +		resume_pending_requests();
> +		resume_recovery_work();
> +	}
> +
> +	if (!again)
> +		req->done(req);
> +}
> +
> +static void queue_request(struct request *req)
> +{
> +	struct cpg_event *cevent = &req->cev;
> +
> +	struct sd_req *hdr = (struct sd_req *)&req->rq;
> +	struct sd_rsp *rsp = (struct sd_rsp *)&req->rp;
> +
> +	if (hdr->opcode == SD_OP_KILL_NODE) {
> +		log_close();
> +		exit(1);
> +	}
> +
> +	if (sys->status == SD_STATUS_SHUTDOWN) {
> +		rsp->result = SD_RES_SHUTDOWN;
> +		req->done(req);
> +		return;
> +	}
> +
> +	if (sys->status == SD_STATUS_JOIN_FAILED) {
> +		rsp->result = SD_RES_JOIN_FAILED;
> +		req->done(req);
> +		return;
> +	}
> +
> +	if (sys->status == SD_STATUS_WAIT_FOR_FORMAT ||
> +	    sys->status == SD_STATUS_WAIT_FOR_JOIN) {
> +		/* TODO: cleanup */
> +		switch (hdr->opcode) {
> +		case SD_OP_STAT_CLUSTER:
> +		case SD_OP_MAKE_FS:
> +		case SD_OP_GET_NODE_LIST:
> +		case SD_OP_READ_VDIS:
> +			break;
> +		default:
> +			if (sys->status == SD_STATUS_WAIT_FOR_FORMAT)
> +				rsp->result = SD_RES_WAIT_FOR_FORMAT;
> +			else
> +				rsp->result = SD_RES_WAIT_FOR_JOIN;
> +			req->done(req);
> +			return;
> +		}
> +	}
> +
> +	switch (hdr->opcode) {
> +	case SD_OP_CREATE_AND_WRITE_OBJ:
> +	case SD_OP_REMOVE_OBJ:
> +	case SD_OP_READ_OBJ:
> +	case SD_OP_WRITE_OBJ:
> +	case SD_OP_STAT_SHEEP:
> +	case SD_OP_GET_OBJ_LIST:
> +		req->work.fn = store_queue_request;
> +		break;
> +	case SD_OP_GET_NODE_LIST:
> +	case SD_OP_GET_VM_LIST:
> +	case SD_OP_NEW_VDI:
> +	case SD_OP_DEL_VDI:
> +	case SD_OP_LOCK_VDI:
> +	case SD_OP_RELEASE_VDI:
> +	case SD_OP_GET_VDI_INFO:
> +	case SD_OP_MAKE_FS:
> +	case SD_OP_SHUTDOWN:
> +	case SD_OP_STAT_CLUSTER:
> +		req->work.fn = cluster_queue_request;
> +		break;
> +	case SD_OP_READ_VDIS:
> +		rsp->result = read_vdis(req->data, hdr->data_length, &rsp->data_length);
> +		req->done(req);
> +		return;
> +	default:
> +		eprintf("unknown operation %d\n", hdr->opcode);
> +		rsp->result = SD_RES_SYSTEM_ERROR;
> +		req->done(req);
> +		return;
> +	}
> +
> +	req->work.done = __done;
> +
> +	list_del(&req->r_wlist);
> +
> +	/*
> +	 * we set epoch for non direct requests here. Note that we
> +	 * can't access to sys->epoch after calling
> +	 * start_cpg_event_work(that is, passing requests to work
> +	 * threads).
> +	 */
> +	if (!(hdr->flags & SD_FLAG_CMD_DIRECT))
> +		hdr->epoch = sys->epoch;
> +
> +	req->nr_nodes = setup_ordered_sd_node_list(req);
> +	setup_access_to_local_objects(req);
> +
> +	cevent->ctype = CPG_EVENT_REQUEST;
> +	list_add_tail(&cevent->cpg_event_list, &sys->cpg_event_siblings);
> +	start_cpg_event_work();
> +}
> +
> +static struct request *alloc_request(struct client_info *ci, int data_length)
> +{
> +	struct request *req;
> +
> +	req = zalloc(sizeof(struct request) + data_length);
> +	if (!req)
> +		return NULL;
> +
> +	req->ci = ci;
> +	if (data_length)
> +		req->data = (char *)req + sizeof(*req);
> +
> +	list_add(&req->r_siblings, &ci->reqs);
> +	INIT_LIST_HEAD(&req->r_wlist);
> +
> +	return req;
> +}
> +
> +static void free_request(struct request *req)
> +{
> +	list_del(&req->r_siblings);
> +	free(req);
> +}
> +
> +static void req_done(struct request *req)
> +{
> +	list_add(&req->r_wlist, &req->ci->done_reqs);
> +	conn_tx_on(&req->ci->conn);
> +}
> +
> +static void init_rx_hdr(struct client_info *ci)
> +{
> +	ci->conn.c_rx_state = C_IO_HEADER;
> +	ci->rx_req = NULL;
> +	ci->conn.rx_length = sizeof(struct sd_req);
> +	ci->conn.rx_buf = &ci->conn.rx_hdr;
> +}
> +
> +static void client_rx_handler(struct client_info *ci)
> +{
> +	int ret;
> +	uint64_t data_len;
> +	struct connection *conn = &ci->conn;
> +	struct sd_req *hdr = &conn->rx_hdr;
> +	struct request *req;
> +
> +	switch (conn->c_rx_state) {
> +	case C_IO_HEADER:
> +		ret = rx(conn, C_IO_DATA_INIT);
> +		if (!ret || conn->c_rx_state != C_IO_DATA_INIT)
> +			break;
> +	case C_IO_DATA_INIT:
> +		data_len = hdr->data_length;
> +
> +		req = alloc_request(ci, data_len);
> +		if (!req) {
> +			conn->c_rx_state = C_IO_CLOSED;
> +			break;
> +		}
> +		ci->rx_req = req;
> +
> +		/* use le_to_cpu */
> +		memcpy(&req->rq, hdr, sizeof(req->rq));
> +
> +		if (data_len && hdr->flags & SD_FLAG_CMD_WRITE) {
> +			conn->c_rx_state = C_IO_DATA;
> +			conn->rx_length = data_len;
> +			conn->rx_buf = req->data;
> +		} else {
> +			conn->c_rx_state = C_IO_END;
> +			break;
> +		}
> +	case C_IO_DATA:
> +		ret = rx(conn, C_IO_END);
> +		break;
> +	default:
> +		eprintf("BUG: unknown state %d\n", conn->c_rx_state);
> +	}
> +
> +	if (is_conn_dead(conn) || conn->c_rx_state != C_IO_END)
> +		return;
> +
> +	/* now we have a complete command */
> +
> +	req = ci->rx_req;
> +
> +	init_rx_hdr(ci);
> +
> +	if (hdr->flags & SD_FLAG_CMD_WRITE)
> +		req->rp.data_length = 0;
> +	else
> +		req->rp.data_length = hdr->data_length;
> +
> +	req->done = req_done;
> +
> +	queue_request(req);
> +}
> +
> +static void init_tx_hdr(struct client_info *ci)
> +{
> +	struct sd_rsp *rsp = (struct sd_rsp *)&ci->conn.tx_hdr;
> +	struct request *req;
> +
> +	if (ci->tx_req || list_empty(&ci->done_reqs))
> +		return;
> +
> +	memset(rsp, 0, sizeof(*rsp));
> +
> +	req = list_first_entry(&ci->done_reqs, struct request, r_wlist);
> +	list_del(&req->r_wlist);
> +
> +	ci->tx_req = req;
> +	ci->conn.tx_length = sizeof(*rsp);
> +	ci->conn.c_tx_state = C_IO_HEADER;
> +	ci->conn.tx_buf = rsp;
> +
> +	/* use cpu_to_le */
> +	memcpy(rsp, &req->rp, sizeof(*rsp));
> +
> +	rsp->epoch = sys->epoch;
> +	rsp->opcode = req->rq.opcode;
> +	rsp->id = req->rq.id;
> +}
> +
> +static void client_tx_handler(struct client_info *ci)
> +{
> +	int ret, opt;
> +	struct sd_rsp *rsp = (struct sd_rsp *)&ci->conn.tx_hdr;
> +
> +again:
> +	init_tx_hdr(ci);
> +	if (!ci->tx_req) {
> +		conn_tx_off(&ci->conn);
> +		return;
> +	}
> +
> +	opt = 1;
> +	setsockopt(ci->conn.fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
> +
> +	switch (ci->conn.c_tx_state) {
> +	case C_IO_HEADER:
> +		if (rsp->data_length)
> +			ret = tx(&ci->conn, C_IO_DATA_INIT, MSG_MORE);
> +		else
> +			ret = tx(&ci->conn, C_IO_DATA_INIT, 0);
> +
> +		if (!ret)
> +			break;
> +
> +		if (rsp->data_length) {
> +			ci->conn.tx_length = rsp->data_length;
> +			ci->conn.tx_buf = ci->tx_req->data;
> +			ci->conn.c_tx_state = C_IO_DATA;
> +		} else {
> +			ci->conn.c_tx_state = C_IO_END;
> +			break;
> +		}
> +	case C_IO_DATA:
> +		ret = tx(&ci->conn, C_IO_END, 0);
> +		if (!ret)
> +			break;
> +	default:
> +		break;
> +	}
> +
> +	opt = 0;
> +	setsockopt(ci->conn.fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt));
> +
> +	if (is_conn_dead(&ci->conn) || ci->conn.c_tx_state != C_IO_END)
> +		return;
> +
> +	if (ci->conn.c_tx_state == C_IO_END) {
> +		free_request(ci->tx_req);
> +		ci->tx_req = NULL;
> +		goto again;
> +	}
> +}
> +
> +static void destroy_client(struct client_info *ci)
> +{
> +	close(ci->conn.fd);
> +	free(ci);
> +}
> +
> +static struct client_info *create_client(int fd, struct cluster_info *cluster)
> +{
> +	struct client_info *ci;
> +
> +	ci = zalloc(sizeof(*ci));
> +	if (!ci)
> +		return NULL;
> +
> +	ci->conn.fd = fd;
> +
> +	INIT_LIST_HEAD(&ci->reqs);
> +	INIT_LIST_HEAD(&ci->done_reqs);
> +
> +	init_rx_hdr(ci);
> +
> +	return ci;
> +}
> +
> +static void client_handler(int fd, int events, void *data)
> +{
> +	struct client_info *ci = (struct client_info *)data;
> +
> +	if (events & EPOLLIN)
> +		client_rx_handler(ci);
> +
> +	if (!is_conn_dead(&ci->conn) && events & EPOLLOUT)
> +		client_tx_handler(ci);
> +
> +	if (is_conn_dead(&ci->conn)) {
> +		dprintf("closed a connection, %d\n", fd);
> +		unregister_event(fd);
> +		destroy_client(ci);
> +	}
> +}
> +
> +static void listen_handler(int listen_fd, int events, void *data)
> +{
> +	struct sockaddr_storage from;
> +	socklen_t namesize;
> +	int fd, ret, opt;
> +	struct client_info *ci;
> +
> +	namesize = sizeof(from);
> +	fd = accept(listen_fd, (struct sockaddr *)&from, &namesize);
> +	if (fd < 0) {
> +		eprintf("can't accept a new connection, %m\n");
> +		return;
> +	}
> +
> +	opt = 1;
> +	ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
> +	if (ret) {
> +		close(fd);
> +		return;
> +	}
> +
> +	ci = create_client(fd, data);
> +	if (!ci) {
> +		close(fd);
> +		return;
> +	}
> +
> +	ret = register_event(fd, client_handler, ci);
> +	if (ret) {
> +		destroy_client(ci);
> +		return;
> +	}
> +
> +	dprintf("accepted a new connection, %d\n", fd);
> +}
> +
> +static int create_listen_port_fn(int fd, void *data)
> +{
> +	return register_event(fd, listen_handler, data);
> +}
> +
> +int create_listen_port(int port, void *data)
> +{
> +	return create_listen_ports(port, create_listen_port_fn, data);
> +}
> +
> +int write_object(struct sheepdog_node_list_entry *e,
> +		 int nodes, uint32_t node_version,
> +		 uint64_t oid, char *data, unsigned int datalen,
> +		 uint64_t offset, int nr, int create)
> +{
> +	struct sd_obj_req hdr;
> +	int i, n, fd, ret, success = 0;
> +	uint16_t vosts[3];
> +	char name[128];
> +
> +	for (i = 0; i < nr; i++) {
> +		unsigned rlen = 0, wlen = datalen;
> +
> +		n = obj_to_sheep(e, nodes, oid, i);
> +
> +		addr_to_str(name, sizeof(name), e[n].addr, 0);
> +
> +		fd = connect_to(name, e[n].port);
> +		if (fd < 0) {
> +			eprintf("can't connect to vost %u, %s\n", vosts[i], name);
> +			continue;
> +		}
> +
> +		memset(&hdr, 0, sizeof(hdr));
> +		hdr.epoch = node_version;
> +		if (create)
> +			hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
> +		else
> +			hdr.opcode = SD_OP_WRITE_OBJ;
> +
> +		hdr.oid = oid;
> +		hdr.copies = nr;
> +
> +		hdr.flags = SD_FLAG_CMD_WRITE | SD_FLAG_CMD_DIRECT;
> +		hdr.data_length = wlen;
> +		hdr.offset = offset;
> +
> +		ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
> +		close(fd);
> +		if (ret)
> +			eprintf("can't update vost %u, %s\n", vosts[i], name);
> +		else
> +			success++;
> +	}
> +
> +	return !success;
> +}
> +
> +int read_object(struct sheepdog_node_list_entry *e,
> +		int nodes, uint32_t node_version,
> +		uint64_t oid, char *data, unsigned int datalen,
> +		uint64_t offset, int nr)
> +{
> +	struct sd_obj_req hdr;
> +	struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
> +	char name[128];
> +	int i = 0, n, fd, ret;
> +
> +	for (i = 0; i < nr; i++) {
> +		unsigned wlen = 0, rlen = datalen;
> +
> +		n = obj_to_sheep(e, nodes, oid, i);
> +
> +		addr_to_str(name, sizeof(name), e[n].addr, 0);
> +
> +		fd = connect_to(name, e[n].port);
> +		if (fd < 0) {
> +			printf("%s(%d): %s, %m\n", __func__, __LINE__,
> +			       name);
> +			return -1;
> +		}
> +
> +		memset(&hdr, 0, sizeof(hdr));
> +		hdr.epoch = node_version;
> +		hdr.opcode = SD_OP_READ_OBJ;
> +		hdr.oid = oid;
> +
> +		hdr.flags =  SD_FLAG_CMD_DIRECT;
> +		hdr.data_length = rlen;
> +		hdr.offset = offset;
> +
> +		ret = exec_req(fd, (struct sd_req *)&hdr, data, &wlen, &rlen);
> +		close(fd);
> +
> +		if (!ret) {
> +			if (rsp->result == SD_RES_SUCCESS)
> +				return rsp->data_length;
> +		}
> +	}
> +
> +	return -1;
> +}
> +
> +int remove_object(struct sheepdog_node_list_entry *e,
> +		  int nodes, uint32_t node_version,
> +		  uint64_t oid, int nr)
> +{
> +	char name[128];
> +	struct sd_obj_req hdr;
> +	struct sd_obj_rsp *rsp = (struct sd_obj_rsp *)&hdr;
> +	int i = 0, n, fd, ret;
> +
> +	if (nr > nodes)
> +		nr = nodes;
> +
> +	for (i = 0; i < nr; i++) {
> +		unsigned wlen = 0, rlen = 0;
> +
> +		n = obj_to_sheep(e, nodes, oid, i);
> +
> +		addr_to_str(name, sizeof(name), e[n].addr, 0);
> +
> +		fd = connect_to(name, e[n].port);
> +		if (fd < 0) {
> +			rsp->result = SD_RES_EIO;
> +			return -1;
> +		}
> +
> +		memset(&hdr, 0, sizeof(hdr));
> +		hdr.epoch = node_version;
> +		hdr.opcode = SD_OP_REMOVE_OBJ;
> +		hdr.oid = oid;
> +
> +		hdr.flags = 0;
> +		hdr.data_length = rlen;
> +
> +		ret = exec_req(fd, (struct sd_req *)&hdr, NULL, &wlen, &rlen);
> +		close(fd);
> +
> +		if (ret)
> +			return -1;
> +	}
> +
> +	if (rsp->result != SD_RES_SUCCESS)
> +		return -1;
> +
> +	return 0;
> +}
> diff --git a/sheep/sheep.c b/sheep/sheep.c
> index b14c5c6..b95b436 100644
> --- a/sheep/sheep.c
> +++ b/sheep/sheep.c
> @@ -8,6 +8,9 @@
>   * You should have received a copy of the GNU General Public License
>   * along with this program. If not, see <http://www.gnu.org/licenses/>.
>   */
> +
> +#include "../include/config.h"
> +
>  #include <getopt.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> @@ -49,7 +52,7 @@ Sheepdog Daemon, version %s\n\
>    -l, --loglevel          specify the message level printed by default\n\
>    -d, --debug             print debug messages\n\
>    -h, --help              display this help and exit\n\
> -", SD_VERSION);
> +", PACKAGE_VERSION);
>  	}
>  	exit(status);
>  }
> @@ -127,7 +130,7 @@ int main(int argc, char **argv)
>  		exit(1);
>  	}
>  
> -	vprintf(SDOG_NOTICE "Sheepdog daemon (version %s) started\n", SD_VERSION);
> +	vprintf(SDOG_NOTICE "Sheepdog daemon (version %s) started\n", PACKAGE_VERSION);
>  
>  	while (sys->status != SD_STATUS_SHUTDOWN)
>  		event_loop(-1);
> diff --git a/sheep/store.c b/sheep/store.c
> index c5552bb..72cd287 100644
> --- a/sheep/store.c
> +++ b/sheep/store.c
> @@ -18,6 +18,9 @@
>  #include <poll.h>
>  #include <sys/xattr.h>
>  #include <sys/statvfs.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
>  
>  #include "sheep_priv.h"
>  




More information about the sheepdog mailing list