Commit 664659a0 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

inet: tcp -- Find size of max memory allowed to restore TCP data

The maximal size which may be used in the kernel for sending TCP data
on restore is varies depending on how many memory installed on the
system, moreover the memory allocated for "read queue" is bigger than
used for "write queue". Thus when we checkpointed a big slab of data
we need to figure out which size is allowed for sending data on restore.

For this we read /proc/sys/net/ipv4/tcp_[wmem|rmem] on restore and calculate
the size needed, then we simply chop data to segements and send it
in a loop.

Typical output on restore is something like

 | (00.013001)  30110: TCP queue memory limits are 2097152:3145728

https://bugzilla.openvz.org/show_bug.cgi?id=2751

[xemul: moved stuff to kerndat.c]
Reported-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 249ee5f7
...@@ -13,4 +13,7 @@ int kerndat_get_dirty_track(void); ...@@ -13,4 +13,7 @@ int kerndat_get_dirty_track(void);
extern dev_t kerndat_shmem_dev; extern dev_t kerndat_shmem_dev;
extern bool kerndat_has_dirty_track; extern bool kerndat_has_dirty_track;
extern int tcp_max_wshare;
extern int tcp_max_rshare;
#endif #endif
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "log.h" #include "log.h"
#include "kerndat.h" #include "kerndat.h"
#include "mem.h" #include "mem.h"
#include "compiler.h"
#include "sysctl.h"
#include "asm/types.h" #include "asm/types.h"
dev_t kerndat_shmem_dev; dev_t kerndat_shmem_dev;
...@@ -100,6 +102,47 @@ int kerndat_get_dirty_track(void) ...@@ -100,6 +102,47 @@ int kerndat_get_dirty_track(void)
return 0; return 0;
} }
/*
* Strictly speaking, if there is a machine with huge amount
* of memory, we're allowed to send up to 4M and read up to
* 6M of tcp data at once. But we will figure out precise size
* of a limit a bit later when restore starts.
*
* Meanwhile set it up to 2M and 3M, which is safe enough to
* proceed without errors.
*/
int tcp_max_wshare = 2U << 20;
int tcp_max_rshare = 3U << 20;
static int tcp_read_sysctl_limits(void)
{
u32 vect[2][3] = { };
int ret;
struct sysctl_req req[] = {
{ "net/ipv4/tcp_wmem", &vect[0], CTL_U32A(ARRAY_SIZE(vect[0])) },
{ "net/ipv4/tcp_rmem", &vect[1], CTL_U32A(ARRAY_SIZE(vect[1])) },
{ },
};
/*
* Lets figure out which exactly amount of memory is
* availabe for send/read queues on restore.
*/
ret = sysctl_op(req, CTL_READ);
if (ret)
return ret;
tcp_max_wshare = min(tcp_max_wshare, (int)vect[0][2]);
tcp_max_rshare = min(tcp_max_rshare, (int)vect[1][2]);
if (tcp_max_wshare < 128 || tcp_max_rshare < 128)
pr_warn("The memory limits for TCP queues are suspiciously small\n");
pr_debug("TCP queue memory limits are %d:%d\n", tcp_max_wshare, tcp_max_rshare);
return 0;
}
int kerndat_init(void) int kerndat_init(void)
{ {
int ret; int ret;
...@@ -107,6 +150,13 @@ int kerndat_init(void) ...@@ -107,6 +150,13 @@ int kerndat_init(void)
ret = kerndat_get_shmemdev(); ret = kerndat_get_shmemdev();
if (!ret) if (!ret)
ret = kerndat_get_dirty_track(); ret = kerndat_get_dirty_track();
if (!ret)
/*
* Read TCP sysctls before anything else,
* since the limits we're interested in are
* not available inside namespaces.
*/
ret = tcp_read_sysctl_limits();
return ret; return ret;
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "xmalloc.h" #include "xmalloc.h"
#include "config.h" #include "config.h"
#include "cr-show.h" #include "cr-show.h"
#include "kerndat.h"
#include "protobuf.h" #include "protobuf.h"
#include "protobuf/tcp-stream.pb-c.h" #include "protobuf/tcp-stream.pb-c.h"
...@@ -444,6 +445,7 @@ static int restore_tcp_seqs(int sk, TcpStreamEntry *tse) ...@@ -444,6 +445,7 @@ static int restore_tcp_seqs(int sk, TcpStreamEntry *tse)
static int send_tcp_queue(int sk, int queue, u32 len, int imgfd) static int send_tcp_queue(int sk, int queue, u32 len, int imgfd)
{ {
int ret, err = -1; int ret, err = -1;
int off, max;
char *buf; char *buf;
pr_debug("\tRestoring TCP %d queue data %u bytes\n", queue, len); pr_debug("\tRestoring TCP %d queue data %u bytes\n", queue, len);
...@@ -460,11 +462,19 @@ static int send_tcp_queue(int sk, int queue, u32 len, int imgfd) ...@@ -460,11 +462,19 @@ static int send_tcp_queue(int sk, int queue, u32 len, int imgfd)
if (read_img_buf(imgfd, buf, len) < 0) if (read_img_buf(imgfd, buf, len) < 0)
goto err; goto err;
ret = send(sk, buf, len, 0); max = (queue == TCP_SEND_QUEUE) ? tcp_max_wshare : tcp_max_rshare;
if (ret != len) { off = 0;
pr_perror("Can't restore %d queue data (%d), want %d", while (len) {
queue, ret, len); int chunk = (len > max ? max : len);
goto err;
ret = send(sk, buf + off, chunk, 0);
if (ret != chunk) {
pr_perror("Can't restore %d queue data (%d), want (%d:%d)",
queue, ret, chunk, len);
goto err;
}
off += chunk;
len -= chunk;
} }
err = 0; err = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment