From c030e495ed3b5e59acd8c7bdcad8baea1697b909 Mon Sep 17 00:00:00 2001
From: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Date: Thu, 29 Jul 2021 14:57:17 +0300
Subject: [PATCH 032/245] kerndat: check for set/getsockopt SO_BUF_LOCK
availability
This is a new kernel feature to let criu restore sockets with kernel
auto-adjusted buffer sizes.
Reviewed-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
criu/cr-check.c | 10 ++++++++++
criu/include/kerndat.h | 1 +
criu/include/sockets.h | 4 ++++
criu/kerndat.c | 33 +++++++++++++++++++++++++++++++++
4 files changed, 48 insertions(+)
diff --git a/criu/cr-check.c b/criu/cr-check.c
index 3575fb3b3..3e268c439 100644
--- a/criu/cr-check.c
+++ b/criu/cr-check.c
@@ -1372,6 +1372,14 @@ static int check_network_lock_nftables(void)
return 0;
}
+static int check_sockopt_buf_lock(void)
+{
+ if (!kdat.has_sockopt_buf_lock)
+ return -1;
+
+ return 0;
+}
+
static int (*chk_feature)(void);
/*
@@ -1490,6 +1498,7 @@ int cr_check(void)
ret |= check_ns_pid();
ret |= check_apparmor_stacking();
ret |= check_network_lock_nftables();
+ ret |= check_sockopt_buf_lock();
}
/*
@@ -1602,6 +1611,7 @@ static struct feature_list feature_list[] = {
{ "ns_pid", check_ns_pid },
{ "apparmor_stacking", check_apparmor_stacking },
{ "network_lock_nftables", check_network_lock_nftables },
+ { "sockopt_buf_lock", check_sockopt_buf_lock },
{ NULL, NULL },
};
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 80bad7f11..2ded7d1da 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -74,6 +74,7 @@ struct kerndat_s {
bool has_pidfd_getfd;
bool has_nspid;
bool has_nftables_concat;
+ bool has_sockopt_buf_lock;
};
extern struct kerndat_s kdat;
diff --git a/criu/include/sockets.h b/criu/include/sockets.h
index 3e8f3d601..399d38664 100644
--- a/criu/include/sockets.h
+++ b/criu/include/sockets.h
@@ -123,4 +123,8 @@ extern const char *socket_proto_name(unsigned int proto, char *nm, size_t size);
#define ___socket_family_name(family) __socket_info_helper(socket_family_name, family)
#define ___socket_proto_name(proto) __socket_info_helper(socket_proto_name, proto)
+#ifndef SO_BUF_LOCK
+#define SO_BUF_LOCK 72
+#endif
+
#endif /* __CR_SOCKETS_H__ */
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 0e88ba43e..9f6a6ec42 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -816,6 +816,35 @@ static int kerndat_x86_has_ptrace_fpu_xsave_bug(void)
return 0;
}
+int kerndat_sockopt_buf_lock(void)
+{
+ int exit_code = -1;
+ socklen_t len;
+ u32 buf_lock;
+ int sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock < 0) {
+ pr_perror("Unable to create a socket");
+ return -1;
+ }
+
+ len = sizeof(buf_lock);
+ if (getsockopt(sock, SOL_SOCKET, SO_BUF_LOCK, &buf_lock, &len)) {
+ if (errno != ENOPROTOOPT) {
+ pr_perror("Unable to get SO_BUF_LOCK with getsockopt");
+ goto err;
+ }
+ kdat.has_sockopt_buf_lock = false;
+ } else
+ kdat.has_sockopt_buf_lock = true;
+
+ exit_code = 0;
+err:
+ close(sock);
+ return exit_code;
+}
+
#define KERNDAT_CACHE_FILE KDAT_RUNDIR "/criu.kdat"
#define KERNDAT_CACHE_FILE_TMP KDAT_RUNDIR "/.criu.kdat"
@@ -1359,6 +1388,10 @@ int kerndat_init(void)
pr_err("kerndat_has_nftables_concat failed when initializing kerndat.\n");
ret = -1;
}
+ if (!ret && kerndat_sockopt_buf_lock()) {
+ pr_err("kerndat_sockopt_buf_lock failed when initializing kerndat.\n");
+ ret = -1;
+ }
kerndat_lsm();
kerndat_mmap_min_addr();
--
2.35.1