[sheepdog] [PATCH 2/8] move functions used by libsheepdog.a out of util.c
Liu Yuan
namei.unix at gmail.com
Fri Apr 3 05:20:48 CEST 2015
From: Liu Yuan <liuyuan at cmss.chinamobile.com>
This is a prepation patch to make util.c self-contained and then can be used
outside sheep.
Signed-off-by: Liu Yuan <liuyuan at cmss.chinamobile.com>
---
dog/common.c | 25 +++++
dog/dog.h | 5 +
include/Makefile.am | 3 +-
include/util.h | 18 ----
lib/Makefile.am | 3 +-
lib/common.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/logger.c | 1 +
lib/util.c | 282 ----------------------------------------------------
sheep/cluster.h | 1 +
sheep/sheep_priv.h | 1 +
sheepfs/core.c | 1 +
shepherd/shepherd.c | 1 +
12 files changed, 318 insertions(+), 302 deletions(-)
create mode 100644 lib/common.c
diff --git a/dog/common.c b/dog/common.c
index 6ff1e19..e3cb3a2 100644
--- a/dog/common.c
+++ b/dog/common.c
@@ -14,6 +14,31 @@
#include "sockfd_cache.h"
#include "fec.h"
+struct timespec get_time_tick(void)
+{
+ struct timespec ts;
+ int ret;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret < 0)
+ sd_err("clock_gettime failure: %m");
+
+ return ts;
+}
+
+double get_time_interval(const struct timespec *start,
+ const struct timespec *end)
+{
+ assert(start);
+ assert(end);
+
+ return ((end->tv_nsec - start->tv_nsec) * 0.000000001)
+ + end->tv_sec - start->tv_sec;
+}
+
char *strnumber_raw(uint64_t _size, bool raw)
{
const char *units[] = {"MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
diff --git a/dog/dog.h b/dog/dog.h
index bcf0e6e..707f31b 100644
--- a/dog/dog.h
+++ b/dog/dog.h
@@ -25,6 +25,7 @@
#include "work.h"
#include "event.h"
#include "config.h"
+#include "common.h"
#define CMD_NEED_NODELIST (1 << 0)
#define CMD_NEED_ARG (1 << 1)
@@ -105,6 +106,10 @@ int dog_bnode_reader(uint64_t oid, void **mem, unsigned int len,
int read_vdi_obj(const char *vdiname, int snapid, const char *tag,
uint32_t *pvid, struct sd_inode *inode, size_t size);
+struct timespec get_time_tick(void);
+double get_time_interval(const struct timespec *start,
+ const struct timespec *end);
+
extern struct command vdi_command;
extern struct command node_command;
extern struct command cluster_command;
diff --git a/include/Makefile.am b/include/Makefile.am
index ad73266..6fee5c8 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -3,4 +3,5 @@ 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 exits.h strbuf.h rbtree.h \
sha1.h option.h internal_proto.h shepherd.h work.h \
- sockfd_cache.h compiler.h fec.h lttng_disable.h
+ sockfd_cache.h compiler.h fec.h lttng_disable.h \
+ common.h
diff --git a/include/util.h b/include/util.h
index 632a193..6c11b54 100644
--- a/include/util.h
+++ b/include/util.h
@@ -106,15 +106,8 @@ int eventfd_xread(int efd);
void eventfd_xwrite(int efd, int value);
void pstrcpy(char *buf, int buf_size, const char *str);
char *chomp(char *str);
-int rmdir_r(const char *dir_path);
-int purge_directory(const char *dir_path);
-int purge_directory_async(const char *dir_path);
bool is_numeric(const char *p);
const char *data_to_str(void *data, size_t data_length);
-int install_sighandler(int signum, void (*handler)(int, siginfo_t *, void *),
- bool once);
-int install_crash_handler(void (*handler)(int, siginfo_t *, void *));
-void reraise_crash_signal(int signo, int status);
pid_t gettid(void);
int tkill(int tid, int sig);
bool is_xattr_enabled(const char *path);
@@ -123,16 +116,9 @@ const char *my_exe_path(void);
int split_path(const char *path, size_t nr_segs, char **segs);
void make_path(char *path, size_t size, size_t nr_segs, const char **segs);
-int atomic_create_and_write(const char *path, const char *buf, size_t len,
- bool force_create);
-
void find_zero_blocks(const void *buf, uint64_t *poffset, uint32_t *plen);
void trim_zero_blocks(void *buf, uint64_t *poffset, uint32_t *plen);
-struct timespec get_time_tick(void);
-double get_time_interval(const struct timespec *start,
- const struct timespec *end);
-
/* a type safe version of qsort() */
#define xqsort(base, nmemb, compar) \
({ \
@@ -562,8 +548,4 @@ static inline uint64_t clock_get_time(void)
}
char *xstrdup(const char *s);
-
-struct work_queue;
-void register_util_wq(struct work_queue *wq);
-
#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a630977..697c5ba 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -13,7 +13,8 @@ libisa_a_SOURCES = $(shell find isa-l/ -type f -regex ".*\.\(c\|h\|asm\)") \
isa-l/make.inc
libsheepdog_a_SOURCES = event.c logger.c net.c util.c rbtree.c strbuf.c \
- sha1.c option.c work.c sockfd_cache.c fec.c sd_inode.c
+ sha1.c option.c work.c sockfd_cache.c fec.c \
+ sd_inode.c common.c
libsheepdog_a_LIBADD = isa-l/bin/ec_base.o \
isa-l/bin/ec_highlevel_func.o \
diff --git a/lib/common.c b/lib/common.c
new file mode 100644
index 0000000..52c6ef4
--- /dev/null
+++ b/lib/common.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2015 China Mobile Inc.
+ *
+ * Liu Yuan <liuyuan at cmss.chinamobile.com>
+ *
+ * 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/>.
+ */
+
+/* This file contains shared functionalities for libsheepdog.a */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include "util.h"
+#include "work.h"
+#include "common.h"
+
+static struct work_queue *util_wqueue;
+
+void register_util_wq(struct work_queue *wq)
+{
+ util_wqueue = wq;
+}
+
+/*
+ * If force_create is true, this function create the file even when the
+ * temporary file exists.
+ */
+int atomic_create_and_write(const char *path, const char *buf, size_t len,
+ bool force_create)
+{
+ int fd, ret;
+ char tmp_path[PATH_MAX];
+
+ snprintf(tmp_path, PATH_MAX, "%s.tmp", path);
+again:
+ fd = open(tmp_path, O_WRONLY | O_CREAT | O_SYNC | O_EXCL, sd_def_fmode);
+ if (fd < 0) {
+ if (errno == EEXIST) {
+ if (force_create) {
+ sd_debug("clean up a temporary file %s",
+ tmp_path);
+ unlink(tmp_path);
+ goto again;
+ } else
+ sd_debug("someone else is dealing with %s",
+ tmp_path);
+ } else
+ sd_err("failed to open temporal file %s, %m", tmp_path);
+ ret = -1;
+ goto end;
+ }
+
+ ret = xwrite(fd, buf, len);
+ if (unlikely(ret != len)) {
+ sd_err("failed to write %s, %m", path);
+ ret = -1;
+ goto close_fd;
+ }
+
+ ret = rename(tmp_path, path);
+ if (unlikely(ret < 0)) {
+ sd_err("failed to rename %s, %m", path);
+ ret = -1;
+ }
+
+close_fd:
+ close(fd);
+end:
+ return ret;
+}
+
+struct purge_work_unit {
+ bool is_dir;
+ char path[PATH_MAX];
+};
+
+struct purge_work {
+ struct work work;
+
+ int nr_units, units_size;
+ struct purge_work_unit *units;
+};
+
+static void purge_work_fn(struct work *work)
+{
+ struct purge_work *pw = container_of(work, struct purge_work, work);
+ int ret;
+
+ for (int i = 0 ; i < pw->nr_units; i++) {
+ struct purge_work_unit *unit;
+
+ unit = &pw->units[i];
+
+ if (unit->is_dir)
+ ret = rmdir_r(unit->path);
+ else
+ ret = unlink(unit->path);
+
+ if (ret)
+ sd_err("failed to remove %s %s: %m",
+ unit->is_dir ? "directory" : "file", unit->path);
+
+ /*
+ * We cannot check and do something even above rmdir_r() and
+ * unlink() cause error. Actually, sd_store->cleanup() (typical
+ * user of purge_directory()) call of
+ * cluster_recovery_completion() ignores its error code.
+ */
+ }
+}
+
+static void purge_work_done(struct work *work)
+{
+ struct purge_work *pw = container_of(work, struct purge_work, work);
+
+ sd_debug("purging work done, number of units: %d", pw->nr_units);
+
+ free(pw->units);
+ free(pw);
+}
+
+/* Purge directory recursively */
+static int raw_purge_directory(const char *dir_path, bool async)
+{
+ int ret = 0;
+ struct stat s;
+ DIR *dir;
+ struct dirent *d;
+ char path[PATH_MAX];
+ struct purge_work *w = NULL;
+
+ dir = opendir(dir_path);
+ if (!dir) {
+ if (errno != ENOENT)
+ sd_err("failed to open %s: %m", dir_path);
+ return -errno;
+ }
+
+ if (async && util_wqueue) {
+ /* we have workqueue for it, don't unlink in this thread */
+ w = xzalloc(sizeof(*w));
+ w->nr_units = 0;
+ w->units_size = 512; /* should this value be configurable? */
+ w->units = xcalloc(w->units_size, sizeof(w->units[0]));
+ }
+
+ while ((d = readdir(dir))) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dir_path, d->d_name);
+ ret = stat(path, &s);
+ if (ret) {
+ sd_err("failed to stat %s: %m", path);
+ goto out;
+ }
+
+ if (async && util_wqueue) {
+ struct purge_work_unit *unit;
+
+ unit = &w->units[w->nr_units++];
+
+ unit->is_dir = S_ISDIR(s.st_mode);
+ pstrcpy(unit->path, PATH_MAX, path);
+
+ if (w->nr_units == w->units_size) {
+ w->units_size *= 2;
+ w->units = xrealloc(w->units,
+ sizeof(struct purge_work_unit) *
+ w->units_size);
+ }
+ } else {
+ if (S_ISDIR(s.st_mode))
+ ret = rmdir_r(path);
+ else
+ ret = unlink(path);
+
+ if (ret != 0) {
+ sd_err("failed to remove %s %s: %m",
+ S_ISDIR(s.st_mode) ?
+ "directory" : "file",
+ path);
+ goto out;
+ }
+ }
+ }
+
+ if (async && util_wqueue) {
+ w->work.fn = purge_work_fn;
+ w->work.done = purge_work_done;
+ queue_work(util_wqueue, &w->work);
+ }
+
+out:
+ closedir(dir);
+ return ret;
+}
+
+int purge_directory(const char *dir_path)
+{
+ return raw_purge_directory(dir_path, false);
+}
+
+int purge_directory_async(const char *dir_path)
+{
+ return raw_purge_directory(dir_path, true);
+}
+
+/* remove directory recursively */
+int rmdir_r(const char *dir_path)
+{
+ int ret;
+
+ ret = purge_directory(dir_path);
+ if (ret == 0)
+ ret = rmdir(dir_path);
+
+ return ret;
+}
+
+/*
+ * If 'once' is true, the signal will be restored to the default state
+ * after 'handler' is called.
+ */
+int install_sighandler(int signum, void (*handler)(int, siginfo_t *, void *),
+ bool once)
+{
+ struct sigaction sa = {};
+
+ sa.sa_sigaction = handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (once)
+ sa.sa_flags = sa.sa_flags | SA_RESETHAND | SA_NODEFER;
+ sigemptyset(&sa.sa_mask);
+
+ return sigaction(signum, &sa, NULL);
+}
+
+int install_crash_handler(void (*handler)(int, siginfo_t *, void *))
+{
+ return install_sighandler(SIGSEGV, handler, true) ||
+ install_sighandler(SIGABRT, handler, true) ||
+ install_sighandler(SIGBUS, handler, true) ||
+ install_sighandler(SIGILL, handler, true) ||
+ install_sighandler(SIGFPE, handler, true) ||
+ install_sighandler(SIGQUIT, handler, true);
+}
+
+/*
+ * Re-raise the signal 'signo' for the default signal handler to dump
+ * a core file, and exit with 'status' if the default handler cannot
+ * terminate the process. This function is expected to be called in
+ * the installed signal handlers with install_crash_handler().
+ */
+void reraise_crash_signal(int signo, int status)
+{
+ int ret = raise(signo);
+
+ /* We won't get here normally. */
+ if (ret != 0)
+ sd_emerg("failed to re-raise signal %d (%s).",
+ signo, strsignal(signo));
+ else
+ sd_emerg("default handler for the re-raised "
+ "signal %d (%s) didn't work as expected", signo,
+ strsignal(signo));
+
+ exit(status);
+}
+
diff --git a/lib/logger.c b/lib/logger.c
index 39d3283..ffe84fc 100644
--- a/lib/logger.c
+++ b/lib/logger.c
@@ -36,6 +36,7 @@
#include <linux/limits.h>
#include "util.h"
+#include "common.h"
static bool colorize;
static const char * const log_color[] = {
diff --git a/lib/util.c b/lib/util.c
index aad6d96..af9747a 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -21,14 +21,6 @@
#include <fcntl.h>
#include "util.h"
-#include "work.h"
-
-static struct work_queue *util_wqueue;
-
-void register_util_wq(struct work_queue *wq)
-{
- util_wqueue = wq;
-}
mode_t sd_def_dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
mode_t sd_def_fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
@@ -117,7 +109,6 @@ int prealloc(int fd, uint32_t size)
int ret = xfallocate(fd, 0, 0, size);
if (ret < 0) {
if (errno != ENOSYS && errno != EOPNOTSUPP) {
- sd_err("failed to preallocate space, %m");
return ret;
}
@@ -366,155 +357,6 @@ char *chomp(char *str)
return str;
}
-struct purge_work_unit {
- bool is_dir;
- char path[PATH_MAX];
-};
-
-struct purge_work {
- struct work work;
-
- int nr_units, units_size;
- struct purge_work_unit *units;
-};
-
-static void purge_work_fn(struct work *work)
-{
- struct purge_work *pw = container_of(work, struct purge_work, work);
- int ret;
-
- for (int i = 0 ; i < pw->nr_units; i++) {
- struct purge_work_unit *unit;
-
- unit = &pw->units[i];
-
- if (unit->is_dir)
- ret = rmdir_r(unit->path);
- else
- ret = unlink(unit->path);
-
- if (ret)
- sd_err("failed to remove %s %s: %m",
- unit->is_dir ? "directory" : "file", unit->path);
-
- /*
- * We cannot check and do something even above rmdir_r() and
- * unlink() cause error. Actually, sd_store->cleanup() (typical
- * user of purge_directory()) call of
- * cluster_recovery_completion() ignores its error code.
- */
- }
-}
-
-static void purge_work_done(struct work *work)
-{
- struct purge_work *pw = container_of(work, struct purge_work, work);
-
- sd_debug("purging work done, number of units: %d", pw->nr_units);
-
- free(pw->units);
- free(pw);
-}
-
-/* Purge directory recursively */
-static int raw_purge_directory(const char *dir_path, bool async)
-{
- int ret = 0;
- struct stat s;
- DIR *dir;
- struct dirent *d;
- char path[PATH_MAX];
- struct purge_work *w = NULL;
-
- dir = opendir(dir_path);
- if (!dir) {
- if (errno != ENOENT)
- sd_err("failed to open %s: %m", dir_path);
- return -errno;
- }
-
- if (async && util_wqueue) {
- /* we have workqueue for it, don't unlink in this thread */
- w = xzalloc(sizeof(*w));
- w->nr_units = 0;
- w->units_size = 512; /* should this value be configurable? */
- w->units = xcalloc(w->units_size, sizeof(w->units[0]));
- }
-
- while ((d = readdir(dir))) {
- if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
- continue;
-
- snprintf(path, sizeof(path), "%s/%s", dir_path, d->d_name);
- ret = stat(path, &s);
- if (ret) {
- sd_err("failed to stat %s: %m", path);
- goto out;
- }
-
- if (async && util_wqueue) {
- struct purge_work_unit *unit;
-
- unit = &w->units[w->nr_units++];
-
- unit->is_dir = S_ISDIR(s.st_mode);
- strcpy(unit->path, path);
-
- if (w->nr_units == w->units_size) {
- w->units_size *= 2;
- w->units = xrealloc(w->units,
- sizeof(struct purge_work_unit) *
- w->units_size);
- }
- } else {
- if (S_ISDIR(s.st_mode))
- ret = rmdir_r(path);
- else
- ret = unlink(path);
-
- if (ret != 0) {
- sd_err("failed to remove %s %s: %m",
- S_ISDIR(s.st_mode) ?
- "directory" : "file",
- path);
- goto out;
- }
- }
- }
-
- if (async && util_wqueue) {
- w->work.fn = purge_work_fn;
- w->work.done = purge_work_done;
- queue_work(util_wqueue, &w->work);
- }
-
-out:
- closedir(dir);
- return ret;
-}
-
-int purge_directory(const char *dir_path)
-{
- return raw_purge_directory(dir_path, false);
-}
-
-int purge_directory_async(const char *dir_path)
-{
- return raw_purge_directory(dir_path, true);
-}
-
-/* remove directory recursively */
-int rmdir_r(const char *dir_path)
-{
- int ret;
-
- ret = purge_directory(dir_path);
- if (ret == 0)
- ret = rmdir(dir_path);
-
- return ret;
-}
-
bool is_numeric(const char *s)
{
const char *p = s;
@@ -546,57 +388,6 @@ const char *data_to_str(void *data, size_t data_length)
return "(not string)";
}
-/*
- * If 'once' is true, the signal will be restored to the default state
- * after 'handler' is called.
- */
-int install_sighandler(int signum, void (*handler)(int, siginfo_t *, void *),
- bool once)
-{
- struct sigaction sa = {};
-
- sa.sa_sigaction = handler;
- sa.sa_flags = SA_SIGINFO;
-
- if (once)
- sa.sa_flags = sa.sa_flags | SA_RESETHAND | SA_NODEFER;
- sigemptyset(&sa.sa_mask);
-
- return sigaction(signum, &sa, NULL);
-}
-
-int install_crash_handler(void (*handler)(int, siginfo_t *, void *))
-{
- return install_sighandler(SIGSEGV, handler, true) ||
- install_sighandler(SIGABRT, handler, true) ||
- install_sighandler(SIGBUS, handler, true) ||
- install_sighandler(SIGILL, handler, true) ||
- install_sighandler(SIGFPE, handler, true) ||
- install_sighandler(SIGQUIT, handler, true);
-}
-
-/*
- * Re-raise the signal 'signo' for the default signal handler to dump
- * a core file, and exit with 'status' if the default handler cannot
- * terminate the process. This function is expected to be called in
- * the installed signal handlers with install_crash_handler().
- */
-void reraise_crash_signal(int signo, int status)
-{
- int ret = raise(signo);
-
- /* We won't get here normally. */
- if (ret != 0)
- sd_emerg("failed to re-raise signal %d (%s).",
- signo, strsignal(signo));
- else
- sd_emerg("default handler for the re-raised "
- "signal %d (%s) didn't work as expected", signo,
- strsignal(signo));
-
- exit(status);
-}
-
pid_t gettid(void)
{
return syscall(SYS_gettid);
@@ -684,54 +475,6 @@ void make_path(char *path, size_t size, size_t nr_segs, const char **segs)
}
/*
- * If force_create is true, this function create the file even when the
- * temporary file exists.
- */
-int atomic_create_and_write(const char *path, const char *buf, size_t len,
- bool force_create)
-{
- int fd, ret;
- char tmp_path[PATH_MAX];
-
- snprintf(tmp_path, PATH_MAX, "%s.tmp", path);
-again:
- fd = open(tmp_path, O_WRONLY | O_CREAT | O_SYNC | O_EXCL, sd_def_fmode);
- if (fd < 0) {
- if (errno == EEXIST) {
- if (force_create) {
- sd_debug("clean up a temporary file %s",
- tmp_path);
- unlink(tmp_path);
- goto again;
- } else
- sd_debug("someone else is dealing with %s",
- tmp_path);
- } else
- sd_err("failed to open temporal file %s, %m", tmp_path);
- ret = -1;
- goto end;
- }
-
- ret = xwrite(fd, buf, len);
- if (unlikely(ret != len)) {
- sd_err("failed to write %s, %m", path);
- ret = -1;
- goto close_fd;
- }
-
- ret = rename(tmp_path, path);
- if (unlikely(ret < 0)) {
- sd_err("failed to rename %s, %m", path);
- ret = -1;
- }
-
-close_fd:
- close(fd);
-end:
- return ret;
-}
-
-/*
* Returns a list organized in an intermediate format suited
* to chaining of merge() calls: null-terminated, no reserved or
* sentinel head node, "prev" links not maintained.
@@ -930,31 +673,6 @@ void trim_zero_blocks(void *buf, uint64_t *poffset, uint32_t *plen)
memmove(p, p + *poffset - orig_offset, *plen);
}
-struct timespec get_time_tick(void)
-{
- struct timespec ts;
- int ret;
-
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
-
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0)
- sd_err("clock_gettime failure: %m");
-
- return ts;
-}
-
-double get_time_interval(const struct timespec *start,
- const struct timespec *end)
-{
- assert(start);
- assert(end);
-
- return ((end->tv_nsec - start->tv_nsec) * 0.000000001)
- + end->tv_sec - start->tv_sec;
-}
-
char *xstrdup(const char *s)
{
char *ret;
diff --git a/sheep/cluster.h b/sheep/cluster.h
index cc111e2..e70c8b6 100644
--- a/sheep/cluster.h
+++ b/sheep/cluster.h
@@ -22,6 +22,7 @@
#include "sheepdog_proto.h"
#include "sheep.h"
#include "config.h"
+#include "common.h"
/*
* maximum payload size sent in ->notify and ->unblock, it should be large
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index 26afa89..3876b31 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -43,6 +43,7 @@
#include "config.h"
#include "sockfd_cache.h"
#include "fec.h"
+#include "common.h"
/*
* Functions that update global info must be called in the main
diff --git a/sheepfs/core.c b/sheepfs/core.c
index 1bcbaec..473cbb5 100644
--- a/sheepfs/core.c
+++ b/sheepfs/core.c
@@ -26,6 +26,7 @@
#include "util.h"
#include "sheepfs.h"
#include "sheepdog_proto.h"
+#include "common.h"
#define SH_OP_NAME "user.sheepfs.opcode"
#define SH_OP_SIZE sizeof(uint32_t)
diff --git a/shepherd/shepherd.c b/shepherd/shepherd.c
index dc6df74..19c217c 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -33,6 +33,7 @@
#include "util.h"
#include "option.h"
#include "shepherd.h"
+#include "common.h"
#define EPOLL_SIZE SD_MAX_NODES
--
1.9.1
More information about the sheepdog
mailing list