[PATCH] lib/cleaner_exec.c: get process ID of cleanerd through pipe

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



After applying commit 8ce4b524a1654ece478f54fce772cc0c16e3c559
"cleanerd: call _exit(2) twice for ensuring not being a session
leader", the mount helper program of nilfs2 no longer gets proper
process ID (pid) of cleaner daemon, and umount.nilfs2 fails to kill
cleanerd.

This fixes the issue by letting cleanerd print out the pid of spawned
daemon and letting nilfs_launch_cleanerd() function read it through
pipe.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
Cc: Hitoshi Mitake <mitake.hitoshi@xxxxxxxxxxxxx>
---
 lib/cleaner_exec.c       |   84 ++++++++++++++++++++++++++++++++++++++++++----
 man/nilfs_cleanerd.8     |    3 ++
 sbin/cleanerd/cleanerd.c |    3 ++
 3 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/lib/cleaner_exec.c b/lib/cleaner_exec.c
index edc55e3..5336c32 100644
--- a/lib/cleaner_exec.c
+++ b/lib/cleaner_exec.c
@@ -114,6 +114,43 @@ static inline int process_is_alive(pid_t pid)
 	return (kill(pid, 0) == 0);
 }
 
+static int receive_pid(int fd, pid_t *ppid)
+{
+	char buf[100];
+	unsigned long pid;
+	FILE *fp;
+	int ret;
+
+	fp = fdopen(fd, "r");
+	if (!fp) {
+		nilfs_cleaner_logger(
+			LOG_ERR, _("Error: fdopen failed: %m"));
+		close(fd);
+		goto fail;
+	}
+
+	/* read process ID of cleanerd through the given fd */
+	while (fgets(buf, sizeof(buf), fp) != NULL) {
+		/*
+		 * fgets() is blocked during no child processes
+		 * respond, but it will escape returning a NULL value
+		 * and terminate the loop when all child processes
+		 * close the given pipe (fd) including call of exit().
+		 */
+		ret = sscanf(buf, "NILFS_CLEANERD_PID=%lu", &pid);
+		if (ret == 1) {
+			*ppid = pid;
+			fclose(fp); /* this also closes fd */
+			return 0;
+		}
+	}
+	fclose(fp);
+fail:
+	nilfs_cleaner_logger(
+		LOG_WARNING, _("Warning: cannot get pid of cleanerd"));
+	return -1;
+}
+
 int nilfs_launch_cleanerd(const char *device, const char *mntdir,
 			  unsigned long protperiod, pid_t *ppid)
 {
@@ -123,6 +160,7 @@ int nilfs_launch_cleanerd(const char *device, const char *mntdir,
 	int i = 0;
 	int ret;
 	char buf[256];
+	int pipes[2];
 
 	if (stat(cleanerd, &statbuf) != 0) {
 		nilfs_cleaner_logger(LOG_ERR,  _("Error: %s not found"),
@@ -130,8 +168,16 @@ int nilfs_launch_cleanerd(const char *device, const char *mntdir,
 		return -1;
 	}
 
+	ret = pipe(pipes);
+	if (ret < 0) {
+		nilfs_cleaner_logger(
+			LOG_ERR, _("Error: failed to create pipe: %m"));
+		return -1;
+	}
+
 	ret = fork();
 	if (ret == 0) {
+		/* child */
 		if (setgid(getgid()) < 0) {
 			nilfs_cleaner_logger(
 				LOG_ERR,
@@ -159,16 +205,40 @@ int nilfs_launch_cleanerd(const char *device, const char *mntdir,
 		sigdelset(&sigs, SIGSEGV);
 		sigprocmask(SIG_UNBLOCK, &sigs, NULL);
 
+		close(pipes[0]);
+		ret = dup2(pipes[1], STDOUT_FILENO);
+		if (ret < 0) {
+			nilfs_cleaner_logger(
+				LOG_ERR,
+				_("Error: failed to duplicate pipe: %m"));
+			exit(1);
+		}
+		close(pipes[1]);
+		
 		execv(cleanerd, (char **)dargs);
 		exit(1);   /* reach only if failed */
-	} else if (ret != -1) {
-		*ppid = ret;
-		return 0; /* cleanerd started */
+	} else if (ret > 0) {
+		/* parent */
+		close(pipes[1]);
+
+		/*
+		 * fork() returns a pid of the child process, but we
+		 * cannot use it because cleanerd internally fork()s
+		 * and changes pid.
+		 */
+		ret = receive_pid(pipes[0], ppid);
+		if (ret < 0)
+			*ppid = 0;
+		/*
+		 * always return a success code because cleanerd has
+		 * already started.
+		 */
+		return 0;
 	} else {
-		int errsv = errno;
-		nilfs_cleaner_logger(LOG_ERR,
-				     _("Error: could not fork: %s"),
-				     strerror(errsv));
+		nilfs_cleaner_logger(
+			LOG_ERR, _("Error: could not fork: %m"));
+		close(pipes[0]);
+		close(pipes[1]);
 	}
 	return -1;
 }
diff --git a/man/nilfs_cleanerd.8 b/man/nilfs_cleanerd.8
index 46caef2..fd1c48a 100644
--- a/man/nilfs_cleanerd.8
+++ b/man/nilfs_cleanerd.8
@@ -24,6 +24,9 @@ users are recommended to invoke \fBnilfs_cleanerd\fP through
 \fBmount.nilfs2\fP(8) or \fBmount\fP(8) and shutdown it through
 \fBumount.nilfs2\fP(8) or \fBumount\fP(8) in order to avoid state
 inconsistencies among administration tools.
+.PP
+\fBnilfs_cleanerd\fP displays its process ID (pid) to standard
+output when it started.
 .SH OPTIONS
 .TP
 \fB\-V\fR, \fB\-\-version\fR
diff --git a/sbin/cleanerd/cleanerd.c b/sbin/cleanerd/cleanerd.c
index 86dfcf7..742ab98 100644
--- a/sbin/cleanerd/cleanerd.c
+++ b/sbin/cleanerd/cleanerd.c
@@ -719,6 +719,9 @@ static int daemonize(int nochdir, int noclose)
 	if (!nochdir && (chdir(ROOTDIR) < 0))
 		return -1;
 
+	printf("NILFS_CLEANERD_PID=%lu\n", (unsigned long)getpid());
+	fflush(stdout);
+
 	if (!noclose) {
 		close(0);
 		close(1);
-- 
1.7.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux