From ce5ce285a81d45a62355301cd68085bb236667fd Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 29 Jul 2021 14:57:17 +0300 Subject: [PATCH] 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 Signed-off-by: Pavel Tikhomirov --- 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();