[CRIU] [PATCH v2 3/4] RPC: Use configuration file also from RPC

Adrian Reber adrian at lisas.de
Wed May 9 20:16:49 MSK 2018


From: Adrian Reber <areber at redhat.com>

This enables the usage of configuration file values in the RPC code
path. The main change is to verify if the user has actually changed a
configuration option in the configuration file and if it has been
changed the value configured via RPC is ignored.

As it is not possible to detect if a configuration option has the
default value because it has not been changed or set by the user or if
the user actually set it to the default value a copy of the options
structure (opt_changed_by_config) is used to track if a configuration
option has been changed by the user. This structure does not contain
that actual value of the configuration option it only tracks if an
option has been set. The value is still in the original options
structure (opts).

With this it is now possible to override CRIU's behavior if started via
RPC. If the user sets a value in one of the configuration files the
value coming from RPC is ignored. This can lead to undesired behavior if
the configuration file sets something which breaks what the RPC client
wants to do. On the other hand it gives the user flexibility to change
CRIU's behavior without potentially having to change the code of the RPC
client.

Signed-off-by: Adrian Reber <areber at redhat.com>
---
 criu/cr-service.c | 135 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 76 insertions(+), 59 deletions(-)

diff --git a/criu/cr-service.c b/criu/cr-service.c
index 274ff21..94276d8 100644
--- a/criu/cr-service.c
+++ b/criu/cr-service.c
@@ -232,6 +232,29 @@ int send_criu_rpc_script(enum script_actions act, char *name, int sk, int fd)
 	return 0;
 }
 
+static void set_log_level(int config_log_level, int rpc_log_level)
+{
+	if (opt_changed_by_config.log_level) {
+		log_set_loglevel(config_log_level);
+		return;
+	}
+	log_set_loglevel(rpc_log_level);
+}
+
+static void set_opts_char(char **config, char *rpc)
+{
+	/* First check if it is already set by the configuration file. */
+	if (*config) {
+		pr_info("Overwriting RPC value %s with configuration file "
+			"value %s\n", rpc, *config);
+		return;
+	}
+
+	/* Check if a value was given via RPC and set it. */
+	if (rpc)
+		*config = rpc;
+}
+
 static char images_dir[PATH_MAX];
 
 static int setup_opts_from_req(int sk, CriuOpts *req)
@@ -260,8 +283,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 	/* open images_dir */
 	sprintf(images_dir_path, "/proc/%d/fd/%d", ids.pid, req->images_dir_fd);
 
-	if (req->parent_img)
-		opts.img_parent = req->parent_img;
+	set_opts_char(&opts.img_parent, req->parent_img);
 
 	if (open_image_dir(images_dir_path) < 0) {
 		pr_perror("Can't open images directory");
@@ -291,12 +313,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 			pr_perror("No subdirs are allowed in log_file name");
 			goto err;
 		}
+	}
+	set_opts_char(&opts.output, req->log_file);
 
-		opts.output = req->log_file;
-	} else
-		opts.output = DEFAULT_LOG_FILENAME;
+	set_log_level(opts.log_level, req->log_level);
 
-	log_set_loglevel(req->log_level);
 	if (log_init(opts.output) == -1) {
 		pr_perror("Can't initiate log");
 		goto err;
@@ -308,7 +329,8 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 	}
 
 	/* checking flags from client */
-	if (req->has_leave_running && req->leave_running)
+	if (req->has_leave_running && req->leave_running &&
+	    (opt_changed_by_config.final_state != 1))
 		opts.final_state = TASK_ALIVE;
 
 	if (!req->has_pid) {
@@ -316,7 +338,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		req->pid = ids.pid;
 	}
 
-	if (req->has_ext_unix_sk) {
+	if (req->has_ext_unix_sk && !opt_changed_by_config.ext_unix_sk) {
 		opts.ext_unix_sk = req->ext_unix_sk;
 		for (i = 0; i < req->n_unix_sk_ino; i++) {
 			if (unix_sk_id_add((unsigned int)req->unix_sk_ino[i]->inode) < 0)
@@ -324,10 +346,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		}
 	}
 
-	if (req->root)
-		opts.root = req->root;
+	set_opts_char(&opts.root, req->root);
 
-	if (req->has_rst_sibling) {
+	if (req->has_rst_sibling && !opt_changed_by_config.restore_sibling) {
 		if (!opts.swrk_restore) {
 			pr_err("rst_sibling is not allowed in standalone service\n");
 			goto err;
@@ -336,35 +357,35 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		opts.restore_sibling = req->rst_sibling;
 	}
 
-	if (req->has_tcp_established)
-		opts.tcp_established_ok = req->tcp_established;
+#define _REALLY_USE_RPC_VALUE(option, rpc) do { \
+	if (req->has_##rpc && !opt_changed_by_config.option) { \
+		opts.option = req->rpc; \
+	} \
+	if (opt_changed_by_config.option) \
+		pr_info("Using %s from configuration file\n", #option); \
+} while (0)
+
+#define REALLY_USE_RPC_VALUE(option) _REALLY_USE_RPC_VALUE(option, option)
 
-	if (req->has_tcp_skip_in_flight)
-		opts.tcp_skip_in_flight = req->tcp_skip_in_flight;
+	_REALLY_USE_RPC_VALUE(tcp_established_ok, tcp_established);
 
-	if (req->has_weak_sysctls)
-		opts.weak_sysctls = req->weak_sysctls;
+	REALLY_USE_RPC_VALUE(tcp_skip_in_flight);
 
-	if (req->has_evasive_devices)
-		opts.evasive_devices = req->evasive_devices;
+	REALLY_USE_RPC_VALUE(weak_sysctls);
 
-	if (req->has_shell_job)
-		opts.shell_job = req->shell_job;
+	REALLY_USE_RPC_VALUE(evasive_devices);
 
-	if (req->has_file_locks)
-		opts.handle_file_locks = req->file_locks;
+	REALLY_USE_RPC_VALUE(shell_job);
 
-	if (req->has_track_mem)
-		opts.track_mem = req->track_mem;
+	_REALLY_USE_RPC_VALUE(handle_file_locks, file_locks);
 
-	if (req->has_link_remap)
-		opts.link_remap_ok = req->link_remap;
+	REALLY_USE_RPC_VALUE(track_mem);
 
-	if (req->has_auto_dedup)
-		opts.auto_dedup = req->auto_dedup;
+	_REALLY_USE_RPC_VALUE(link_remap_ok, link_remap);
 
-	if (req->has_force_irmap)
-		opts.force_irmap = req->force_irmap;
+	REALLY_USE_RPC_VALUE(auto_dedup);
+
+	REALLY_USE_RPC_VALUE(force_irmap);
 
 	if (req->n_exec_cmd > 0) {
 		opts.exec_cmd = xmalloc((req->n_exec_cmd + 1) * sizeof(char *));
@@ -372,16 +393,16 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		opts.exec_cmd[req->n_exec_cmd] = NULL;
 	}
 
-	if (req->has_lazy_pages) {
-		opts.lazy_pages = req->lazy_pages;
-	}
+	REALLY_USE_RPC_VALUE(lazy_pages);
 
-	if (req->ps) {
-		opts.port = (short)req->ps->port;
+	if (req->ps || opts.use_page_server) {
+		if (!opt_changed_by_config.port)
+			opts.port = (short)req->ps->port;
 
 		if (!opts.lazy_pages) {
 			opts.use_page_server = true;
-			opts.addr = req->ps->address;
+			if (!opt_changed_by_config.addr)
+				opts.addr = req->ps->address;
 
 			if (req->ps->has_fd) {
 				if (!opts.swrk_restore)
@@ -439,8 +460,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 			goto err;
 	}
 
-	if (req->has_cpu_cap)
-		opts.cpu_cap = req->cpu_cap;
+	REALLY_USE_RPC_VALUE(cpu_cap);
 
 	/*
 	 * FIXME: For backward compatibility we setup
@@ -448,11 +468,11 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 	 * other modes as well via separate option
 	 * probably.
 	 */
-	if (req->has_manage_cgroups)
+	if (req->has_manage_cgroups && !opt_changed_by_config.manage_cgroups)
 		opts.manage_cgroups = req->manage_cgroups ? CG_MODE_SOFT : CG_MODE_IGNORE;
 
 	/* Override the manage_cgroup if mode is set explicitly */
-	if (req->has_manage_cgroups_mode) {
+	if (req->has_manage_cgroups_mode && !opt_changed_by_config.manage_cgroups) {
 		unsigned int mode;
 
 		switch (req->manage_cgroups_mode) {
@@ -484,36 +504,33 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		opts.manage_cgroups = mode;
 	}
 
-	if (req->freeze_cgroup)
-		opts.freeze_cgroup = req->freeze_cgroup;
+	set_opts_char(&opts.freeze_cgroup, req->freeze_cgroup);
 
-	if (req->has_timeout)
-		opts.timeout = req->timeout;
+	REALLY_USE_RPC_VALUE(timeout);
 
-	if (req->cgroup_props)
-		opts.cgroup_props = req->cgroup_props;
+	set_opts_char(&opts.cgroup_props, req->cgroup_props);
 
-	if (req->cgroup_props_file)
-		opts.cgroup_props_file = req->cgroup_props_file;
+	set_opts_char(&opts.cgroup_props_file, req->cgroup_props_file);
 
 	for (i = 0; i < req->n_cgroup_dump_controller; i++) {
 		if (!cgp_add_dump_controller(req->cgroup_dump_controller[i]))
 			goto err;
 	}
 
-	if (req->has_auto_ext_mnt)
-		opts.autodetect_ext_mounts = req->auto_ext_mnt;
+	_REALLY_USE_RPC_VALUE(autodetect_ext_mounts, auto_ext_mnt);
+
+	_REALLY_USE_RPC_VALUE(enable_external_sharing, ext_sharing);
+
+	_REALLY_USE_RPC_VALUE(enable_external_masters, ext_masters);
 
-	if (req->has_ext_sharing)
-		opts.enable_external_sharing = req->ext_sharing;
+	_REALLY_USE_RPC_VALUE(enable_external_masters, ext_masters);
 
-	if (req->has_ext_masters)
-		opts.enable_external_masters = req->ext_masters;
+	REALLY_USE_RPC_VALUE(ghost_limit);
 
-	if (req->has_ghost_limit)
-		opts.ghost_limit = req->ghost_limit;
+#undef REALLY_USE_RPC_VALUE
+#undef _REALLY_USE_RPC_VALUE
 
-	if (req->has_empty_ns) {
+	if (req->has_empty_ns && !opt_changed_by_config.empty_ns) {
 		opts.empty_ns = req->empty_ns;
 		if (req->empty_ns & ~(CLONE_NEWNET))
 			goto err;
@@ -526,7 +543,7 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
 		}
 	}
 
-	if (req->has_status_fd) {
+	if (req->has_status_fd && !opt_changed_by_config.status_fd) {
 		sprintf(status_fd, "/proc/%d/fd/%d", ids.pid, req->status_fd);
 		opts.status_fd = open(status_fd, O_WRONLY);
 		if (opts.status_fd < 0)
-- 
1.8.3.1



More information about the CRIU mailing list