[Devel] [PATCH 1/3] [RFC] user-cr: Add a basic hooks system

Dan Smith danms at us.ibm.com
Wed May 26 07:42:34 PDT 2010


In order to allow users to perform parts of the checkpoint/restore
themselves, we need a system of "hooks" for the user-cr applications to
call at various times.  This patch adds a little bit of infrastructure for
that, and defines two hooks: "checkpoint-pre" and "restart-post".  The
checkpoint-pre hook gets run before we call sys_checkpoint() and the
restart-post hook gets run after we've restored the task(s).

The infrastructure calls the hooks by name by exec'ing a shell.  The
environment is set up with information about the task at hand, with
variables prefixed by "CR_".  For now, only two are defined. CR_ROOT_PID
is the pid of the root of the checkpoint or the pid of the root of the
restored task tree.  CR_BASE_FILE is the name of the file we're
checkpointing to or restoring from (or empty if using stdio).

I think it's to be expected that any checkpointing or restarting done
by the hooks will be stored separately from the main checkpoint file,
so I expect that at least initially we'll use a permutation of the base
file's name for those.

Included are two shell scripts in the hooks/ directory which can be
modified to add the actual work to be done (and potentially some logic
to decide when and how to run some of them).

Thoughts?

Signed-off-by: Dan Smith <danms at us.ibm.com>
---
 Makefile             |    5 +-
 app-checkpoint.h     |    7 +++
 checkpoint-main.c    |    1 +
 checkpoint.c         |    7 +++
 hooks.c              |  118 ++++++++++++++++++++++++++++++++++++++++++++++++++
 hooks.h              |   21 +++++++++
 hooks/checkpoint-pre |    5 ++
 hooks/restart-post   |    5 ++
 restart-main.c       |    1 +
 restart.c            |   11 ++++-
 10 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 hooks.c
 create mode 100644 hooks.h
 create mode 100644 hooks/checkpoint-pre
 create mode 100644 hooks/restart-post

diff --git a/Makefile b/Makefile
index 6c9ff93..ea86406 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ LDLIBS = -lm
 
 all: $(PROGS)
 	@$(MAKE) -C test
+	@$(MAKE) -C hooks
 
 $(LIB_ECLONE):
 	$(AR) ruv $(LIB_ECLONE) $^
@@ -54,9 +55,9 @@ restart: CFLAGS += -D__REENTRANT -pthread
 
 $(CR_OBJS): common.h app-checkpoint.h
 
-restart: restart.o restart-main.o
+restart: restart.o restart-main.o hooks.o
 
-checkpoint: checkpoint.o checkpoint-main.o
+checkpoint: checkpoint.o checkpoint-main.o hooks.o
 
 # eclone() is architecture specific
 ifneq ($(SUBARCH),)
diff --git a/app-checkpoint.h b/app-checkpoint.h
index 8c8ebbb..fe08560 100644
--- a/app-checkpoint.h
+++ b/app-checkpoint.h
@@ -1,8 +1,12 @@
+#ifndef __APP_CHECKPOINT_H
+#define __APP_CHECKPOINT_H
+
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
 struct app_checkpoint_args {
 	int outfd;
+	char *output;
 	int logfd;
 	int uerrfd;
 	int container;
@@ -24,6 +28,7 @@ struct app_restart_args {
 	char *freezer;
 	int keep_frozen;
 	int infd;
+	char *input;
 	int klogfd;
 	int ulogfd;
 	int uerrfd;
@@ -44,3 +49,5 @@ extern int app_checkpoint(int pid, unsigned long flags,
 				struct app_checkpoint_args *args);
 
 extern int app_restart(struct app_restart_args *args);
+
+#endif
diff --git a/checkpoint-main.c b/checkpoint-main.c
index 24d89eb..1329f84 100644
--- a/checkpoint-main.c
+++ b/checkpoint-main.c
@@ -131,6 +131,7 @@ static void parse_args(struct app_checkpoint_args *args, int argc, char *argv[])
 			ckpt_perror("open output file");
 			exit(1);
 		}
+		args->output = output;
 	}
 
 	if (logfile && args->logfd >= 0) {
diff --git a/checkpoint.c b/checkpoint.c
index e0290c9..2a36df0 100644
--- a/checkpoint.c
+++ b/checkpoint.c
@@ -23,6 +23,7 @@
 
 #include "app-checkpoint.h"
 #include "common.h"
+#include "hooks.h"
 
 static int global_uerrfd = -1;
 
@@ -36,6 +37,12 @@ int app_checkpoint(int pid, unsigned long flags,
 {
 	int ret;
 
+	ret = call_checkpoint_hook("pre", pid, args);
+	if (ret) {
+		ckpt_err("Hook checkpoint-pre failed: %i\n", ret);
+		return ret;
+	}
+
 	global_uerrfd = args->uerrfd;
 
 	/* output file descriptor (default: stdout) */
diff --git a/hooks.c b/hooks.c
new file mode 100644
index 0000000..c55c211
--- /dev/null
+++ b/hooks.c
@@ -0,0 +1,118 @@
+/*
+ *  hooks.c: implementation of standard hook-calling mechanism
+ *
+ *  Copyright 2010 IBM Corporation
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "app-checkpoint.h"
+
+static int call_hook(const char *hook, char *const env[])
+{
+	int pid;
+	int ret;
+	int status;
+
+	pid = fork();
+	if (!pid) {
+		ret = execle("/bin/sh", "/bin/sh", "-c", hook, NULL, env);
+		perror("execle");
+		exit(ret);
+	}
+
+	ret = waitpid(pid, &status, 0);
+	if (ret < 0)
+		return ret;
+
+	return WEXITSTATUS(status);
+}
+
+#define RESTART_HOOK_ENV_LEN 3
+
+int call_restart_hook(const char *hook, int root_pid,
+		      struct app_restart_args *args)
+{
+	char *env[RESTART_HOOK_ENV_LEN+1];
+	char *hook_cmd = NULL;
+	int ret;
+	int i = 0;
+
+	ret = asprintf(&env[i++], "PATH=%s", getenv("PATH"));
+	if (ret < 0)
+		goto err;
+
+	ret = asprintf(&env[i++], "CR_ROOT_PID=%i", root_pid);
+	if (ret < 0)
+		goto err;
+
+	ret = asprintf(&env[i++], "CR_BASE_FILE=%s",
+		       args->input ? args->input : "");
+	if (ret < 0)
+		goto err;
+
+	env[RESTART_HOOK_ENV_LEN] = NULL;
+
+	ret = asprintf(&hook_cmd, "restart-%s", hook);
+	if (ret < 0)
+		goto err;
+
+	return call_hook(hook_cmd, env);
+ err:
+	for (i = 0; i < RESTART_HOOK_ENV_LEN; i++)
+		free(env[i]);
+
+	free(hook_cmd);
+
+	return -ENOMEM;
+}
+
+#define CHECKPOINT_HOOK_ENV_LEN 3
+
+int call_checkpoint_hook(const char *hook, int root_pid,
+			 struct app_checkpoint_args *args)
+{
+	char *env[CHECKPOINT_HOOK_ENV_LEN+1];
+	char *hook_cmd = NULL;
+	int ret;
+	int i = 0;
+
+	ret = asprintf(&env[i++], "PATH=%s", getenv("PATH"));
+	if (ret < 0)
+		goto err;
+
+	ret = asprintf(&env[i++], "CR_ROOT_PID=%i", root_pid);
+	if (ret < 0)
+		goto err;
+
+	ret = asprintf(&env[i++], "CR_BASE_FILE=%s",
+		       args->output ? args->output : "");
+	if (ret < 0)
+		goto err;
+
+	env[CHECKPOINT_HOOK_ENV_LEN] = NULL;
+
+	ret = asprintf(&hook_cmd, "checkpoint-%s", hook);
+	if (ret < 0)
+		goto err;
+
+	return call_hook(hook_cmd, env);
+ err:
+	for (i = 0; i < CHECKPOINT_HOOK_ENV_LEN; i++)
+		free(env[i]);
+
+	free(hook_cmd);
+
+	return -ENOMEM;
+}
diff --git a/hooks.h b/hooks.h
new file mode 100644
index 0000000..132d60e
--- /dev/null
+++ b/hooks.h
@@ -0,0 +1,21 @@
+/*
+ *  hooks.h: interfaces for calling hooks
+ *
+ *  Copyright 2010 IBM Corporation
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ */
+
+#ifndef __HOOKS_H
+#define __HOOKS_H
+
+#include "app-checkpoint.h"
+
+int call_restart_hook(const char *hook, int root_pid,
+		      struct app_restart_args *args);
+int call_checkpoint_hook(const char *hook, int root_pid,
+			 struct app_checkpoint_args *args);
+
+#endif
diff --git a/hooks/checkpoint-pre b/hooks/checkpoint-pre
new file mode 100644
index 0000000..c586275
--- /dev/null
+++ b/hooks/checkpoint-pre
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo "========= CHECKPOINT PRE HOOK ============"
+
+echo "========= CHECKPOINT PRE HOOK ============"
diff --git a/hooks/restart-post b/hooks/restart-post
new file mode 100644
index 0000000..dbce024
--- /dev/null
+++ b/hooks/restart-post
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo "========= RESTART POST HOOK ============"
+
+echo "========= RESTART POST HOOK ============"
diff --git a/restart-main.c b/restart-main.c
index 656d49f..a019bc3 100644
--- a/restart-main.c
+++ b/restart-main.c
@@ -279,6 +279,7 @@ static void parse_args(struct app_restart_args *args, int argc, char *argv[])
 			ckpt_perror("open input file");
 			exit(1);
 		}
+		args->input = strdup(input);
 	}
 
 	if (klogfile && args->klogfd >= 0) {
diff --git a/restart.c b/restart.c
index c5c65a2..c29206a 100644
--- a/restart.c
+++ b/restart.c
@@ -42,6 +42,7 @@
 #include "compat.h"
 #include "app-checkpoint.h"
 #include "common.h"
+#include "hooks.h"
 
 /*
  * By default, 'restart' creates a new pid namespace in which the
@@ -877,8 +878,10 @@ static int ckpt_coordinator_pidns(struct ckpt_ctx *ctx)
 	ctx->args->copy_status = copy;
 
 	ret = ckpt_coordinator_status(ctx);
+	if (ret != 0)
+		return ret;
 
-	if (ret == 0 && ctx->args->wait)
+	if (ctx->args->wait)
 		ret = ckpt_collect_child(ctx);
 
 	return ret;
@@ -928,6 +931,12 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)
 		exit(1);
 	}
 
+	ret = call_restart_hook("post", root_pid, ctx->args);
+	if (ret < 0) {
+		printf("Hook restart-post failed: %i\n", ret);
+		return ret;
+	}
+
 	ckpt_verbose("Success\n");
 	ckpt_dbg("restart succeeded\n");
 
-- 
1.7.0.4

_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list