Commit 4dc3e53e authored by Pavel Emelyanov's avatar Pavel Emelyanov

tcp: Try harder to restore recv queue

On restore we try to put data back into recv queue with quite
big chunks. However the kernel doesn't try hard to split the
data into packets in repair mode for this queue and just
allocates the linear skb of the given size. If the size is
moderately big, the allocation is subject to fail, slab doesn't
reliably allocates memory over 4k.

So, when failing with big chunk on recv queue -- shrink the
chunk and try again.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
Acked-by: 's avatarAndrew Vagin <avagin@virtuozzo.com>
parent afc11b6a
...@@ -461,7 +461,7 @@ static int restore_tcp_seqs(int sk, TcpStreamEntry *tse) ...@@ -461,7 +461,7 @@ static int restore_tcp_seqs(int sk, TcpStreamEntry *tse)
static int __send_tcp_queue(int sk, int queue, u32 len, struct cr_img *img) static int __send_tcp_queue(int sk, int queue, u32 len, struct cr_img *img)
{ {
int ret, err = -1; int ret, err = -1, max_chunk;
int off; int off;
char *buf; char *buf;
...@@ -472,17 +472,32 @@ static int __send_tcp_queue(int sk, int queue, u32 len, struct cr_img *img) ...@@ -472,17 +472,32 @@ static int __send_tcp_queue(int sk, int queue, u32 len, struct cr_img *img)
if (read_img_buf(img, buf, len) < 0) if (read_img_buf(img, buf, len) < 0)
goto err; goto err;
max_chunk = (queue == TCP_RECV_QUEUE ? kdat.tcp_max_rshare : len);
off = 0; off = 0;
while (len) { while (len) {
int chunk = len; int chunk = len;
if (queue == TCP_RECV_QUEUE && len > kdat.tcp_max_rshare) if (chunk > max_chunk)
chunk = kdat.tcp_max_rshare; chunk = max_chunk;
ret = send(sk, buf + off, chunk, 0); ret = send(sk, buf + off, chunk, 0);
if (ret <= 0) { if (ret <= 0) {
pr_perror("Can't restore %d queue data (%d), want (%d:%d)", if ((queue == TCP_RECV_QUEUE) && (max_chunk > 1024) && (errno == ENOMEM)) {
queue, ret, chunk, len); /*
* When restoring recv queue in repair mode
* kernel doesn't try hard and just allocates
* a linear skb with the size we pass to the
* system call. Thus, if the size is too big
* for slab allocator, the send just fails
* with ENOMEM. Try smaller chunk, hopefully
* there's still enough memory in the system.
*/
max_chunk >>= 1;
continue;
}
pr_perror("Can't restore %d queue data (%d), want (%d:%d:%d)",
queue, ret, chunk, len, max_chunk);
goto err; goto err;
} }
off += ret; off += ret;
......
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