[sheepdog] [PATCH v3] sheep: implement a correct mutex of a base directory

Hitoshi Mitake mitake.hitoshi at gmail.com
Sun Apr 28 16:28:53 CEST 2013


sheep employes lockf() for mutex of lock_base_dir() now. But the
lockf() is not suitable for sheep bacause sheep calls daemon(3) after
the lockf(). daemon(3) forks internally and a parent process exits
immediately. In a case of sheep, daemon() must be called after locking
base dir so the lock owner, parent process, exits and the lock will be
released even though the child process is running. This is the reason
current lock_base_dir() doesn't work well. And it causes writing logs
to sheep.log from multiple sheeps. This phenomenon is very confusing
and should be avoided.

This patch implement custom function for daemonizing, daemonize(). And
mutex of base directory is done in it. daemonize() does mutex between
fork() and closing fd 0, 1, and 2, so it can report the failure of
mutexing base directory to stderr.

Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
v3: implement custom function for daemonizing and do mutex in it

v2: call exit_handler() from crash_handler() too

 sheep/sheep.c      |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 sheep/sheep_priv.h |    1 +
 sheep/store.c      |    4 ++--
 3 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/sheep/sheep.c b/sheep/sheep.c
index 95bfa9a..1e4eb59 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -390,6 +390,60 @@ static void check_host_env(void)
 			   r.rlim_cur);
 }
 
+static int daemonize(const char *base_dir)
+{
+	int ret, devnull_fd;
+
+	switch (fork()) {
+	case 0:
+		break;
+	case -1:
+		panic("fork() failed during daemonize: %m");
+		break;
+	default:
+		exit(0);
+		break;
+	}
+
+	if (setsid() == -1)
+		panic("becoming a leader of a new session failed: %m");
+
+	switch (fork()) {
+	case 0:
+		break;
+	case -1:
+		panic("fork() failed during daemonize: %m");
+		break;
+	default:
+		exit(0);
+		break;
+	}
+
+	if (chdir("/"))
+		panic("chdir to / failed: %m");
+
+	devnull_fd = open("/dev/null", O_RDWR);
+	if (devnull_fd < 0)
+		panic("opening /dev/null failed: %m");
+
+	ret = lock_base_dir(base_dir);
+	if (ret < 0) {
+		sd_eprintf("locking directory: %s failed", base_dir);
+		return -1;
+	}
+
+	/*
+	 * now we can use base_dir/sheep.log for logging error messages,
+	 * we can close 0, 1, and 2 safely
+	 */
+	dup2(devnull_fd, 0);
+	dup2(devnull_fd, 1);
+	dup2(devnull_fd, 2);
+	close(devnull_fd);
+
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int ch, longindex, ret, port = SD_LISTEN_PORT, io_port = SD_LISTEN_PORT;
@@ -582,7 +636,7 @@ int main(int argc, char **argv)
 
 	srandom(port);
 
-	if (is_daemon && daemon(0, 0))
+	if (is_daemon && daemonize(dirp))
 		exit(1);
 
 	ret = log_init(program_name, LOG_SPACE_SIZE, to_stdout, log_level,
diff --git a/sheep/sheep_priv.h b/sheep/sheep_priv.h
index b9d6f97..89247a9 100644
--- a/sheep/sheep_priv.h
+++ b/sheep/sheep_priv.h
@@ -250,6 +250,7 @@ int init_store_driver(bool is_gateway);
 int init_global_pathnames(const char *d, char *);
 int init_base_path(const char *dir);
 int init_disk_space(const char *d);
+int lock_base_dir(const char *d);
 
 int fill_vdi_copy_list(void *data);
 int get_vdi_copy_number(uint32_t vid);
diff --git a/sheep/store.c b/sheep/store.c
index ec3451c..6590664 100644
--- a/sheep/store.c
+++ b/sheep/store.c
@@ -185,7 +185,7 @@ uint32_t get_latest_epoch(void)
 	return epoch;
 }
 
-static int lock_base_dir(const char *d)
+int lock_base_dir(const char *d)
 {
 #define LOCK_PATH "/lock"
 	char *lock_path;
@@ -224,7 +224,7 @@ int init_base_path(const char *d)
 		return -1;
 	}
 
-	return lock_base_dir(d);
+	return 0;
 }
 
 /*
-- 
1.7.10.rc0.41.gfa678




More information about the sheepdog mailing list