[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