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>
This commit is contained in:
Pavel Tikhomirov 2021-07-29 14:57:17 +03:00 committed by Andrei Vagin
parent 2bd709664f
commit ce5ce285a8
4 changed files with 48 additions and 0 deletions

View file

@ -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 },
};

View file

@ -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;

View file

@ -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__ */

View file

@ -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();