[CRIU] [PATCH 3/3] net: sysctl -- Make sure the sysctl entries exist before reading them

Cyrill Gorcunov gorcunov at openvz.org
Wed Apr 29 12:51:13 PDT 2015


I hit a problem: the @igmpv2_unsolicited_report_interval
and @igmpv3_unsolicited_report_interval are not present
on 3.10 kernel series, so dumping procedure failed.

Lets do a trick -- these members may vay from kernel to
kernel so we simply should check if they are exist when
dumping.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 net.c | 44 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

diff --git a/net.c b/net.c
index d4f762333c66..774756c4f07f 100644
--- a/net.c
+++ b/net.c
@@ -51,7 +51,7 @@ int read_ns_sys_file(char *path, char *buf, int len)
 	return rlen;
 }
 
-char *devconfs[] = {
+static char *devconfs_template[] = {
 	"accept_local",
 	"accept_redirects",
 	"accept_source_route",
@@ -79,10 +79,40 @@ char *devconfs[] = {
 	"shared_media",
 	"src_valid_mark",
 	"tag",
-	NULL,
 };
 
+static char *devconfs[ARRAY_SIZE(devconfs_template)];
+
 #define NET_CONF_PATH "net/ipv4/conf"
+
+static inline size_t nr_devconfs(void)
+{
+	static size_t __nr_devconfs = 0;
+	size_t i, j;
+	int dir;
+
+	BUILD_BUG_ON(sizeof(devconfs) != sizeof(devconfs_template));
+
+	if (__nr_devconfs)
+		return __nr_devconfs;
+
+	dir = open("/proc/sys/" NET_CONF_PATH "/all", O_RDONLY);
+	if (dir < 0) {
+		pr_perror("Can't open sysctl dir");
+		__nr_devconfs = ARRAY_SIZE(devconfs_template);
+		return __nr_devconfs;
+	}
+
+	for (i = 0, j = 0; i < ARRAY_SIZE(devconfs_template); i++) {
+		if (faccessat(dir, devconfs_template[i], F_OK, 0) == 0)
+			devconfs[j++] = devconfs_template[i];
+	}
+	__nr_devconfs = (j > 0 ? j - 1 : 0);
+	close(dir);
+
+	return __nr_devconfs;
+}
+
 #define MAX_CONF_OPT_PATH IFNAMSIZ+50
 
 static int ipv4_conf_op(char *tgt, int *conf, int op, NetnsEntry **netns)
@@ -91,8 +121,9 @@ static int ipv4_conf_op(char *tgt, int *conf, int op, NetnsEntry **netns)
 	int ret;
 	struct sysctl_req req[ARRAY_SIZE(devconfs) + 1];
 	char path[ARRAY_SIZE(devconfs)][MAX_CONF_OPT_PATH];
+	size_t nr_def_conf = (op == CTL_READ) ? nr_devconfs() : ARRAY_SIZE(devconfs);
 
-	for (i = 0, ri = 0; devconfs[i]; i++) {
+	for (i = 0, ri = 0; i < nr_def_conf; i++) {
 		/*
 		 * If dev conf value is the same as default skip restoring it
 		 */
@@ -107,7 +138,6 @@ static int ipv4_conf_op(char *tgt, int *conf, int op, NetnsEntry **netns)
 		req[ri].type = CTL_32;
 		ri++;
 	}
-	req[ri].name = NULL;
 
 	ret = sysctl_op(req, ri ? ri - 1 : 0, op);
 	if (ret < 0) {
@@ -149,7 +179,7 @@ static int dump_one_netdev(int type, struct ifinfomsg *ifi,
 				(int)netdev.address.len, netdev.name);
 	}
 
-	netdev.n_conf = ARRAY_SIZE(devconfs);
+	netdev.n_conf = nr_devconfs();
 	netdev.conf = xmalloc(sizeof(int) * netdev.n_conf);
 	if (!netdev.conf)
 		return -1;
@@ -556,8 +586,8 @@ static int dump_netns_conf(struct cr_imgset *fds)
 	int ret;
 	NetnsEntry netns = NETNS_ENTRY__INIT;
 
-	netns.n_def_conf = ARRAY_SIZE(devconfs);
-	netns.n_all_conf = ARRAY_SIZE(devconfs);
+	netns.n_def_conf = nr_devconfs();
+	netns.n_all_conf = nr_devconfs();
 	netns.def_conf = xmalloc(sizeof(int) * netns.n_def_conf);
 	if (!netns.def_conf)
 		return -1;
-- 
2.1.0



More information about the CRIU mailing list