Commit a99b7c1b authored by Pavel Emelyanov's avatar Pavel Emelyanov

page-server: Allow blocking on socket

When splicing page server data from UNIX socket we may get
error (EAGAIN) from splice if no data is available on the
socket yet. This is because the SPLICE_F_NONBLOCK flag is
checked by af_unix.c in the kernel to decide whether or
not to do blocking read.

This is not symmetrical with TCP sockets, which only check
for the socket's O_NONBLOCK flag for the same decicion.

Dropping the SPLICE_F_NONBLOCK flag is not possible too, as
otherwise we'll block on the pipe when trying to put data
into it. Even if part of the data fits into it kernel would
block anyway untill full buffer is in. And there will be
no read() from the pipe, as it should happen one step later
in the same task.

So to untie this, we need to wait for the data explicitly
with poll().
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent aabeb8e4
......@@ -12,6 +12,7 @@
#include <sys/statfs.h>
#include <sys/sysmacros.h>
#include <dirent.h>
#include <poll.h>
#include "int.h"
#include "common/compiler.h"
......@@ -263,6 +264,12 @@ int fd_has_data(int lfd);
int make_yard(char *path);
static inline int sk_wait_data(int sk)
{
struct pollfd pfd = {sk, POLLIN, 0};
return poll(&pfd, 1, -1);
}
void tcp_nodelay(int sk, bool on);
void tcp_cork(int sk, bool on);
......
......@@ -557,6 +557,20 @@ static int page_server_add(int sk, struct page_server_iov *pi)
if (chunk > cxfer.pipe_size)
chunk = cxfer.pipe_size;
/*
* Splicing into a pipe may end up blocking if pipe is "full",
* and we need the SPLICE_F_NONBLOCK flag here. At the same time
* splcing from UNIX socket with this flag aborts splice with
* the EAGAIN if there's no data in it (TCP looks at the socket
* O_NONBLOCK flag _only_ and waits for data), so before doing
* the non-blocking splice we need to explicitly wait.
*/
if (sk_wait_data(sk) < 0) {
pr_perror("Can't poll socket");
return -1;
}
chunk = splice(sk, NULL, cxfer.p[1], NULL, chunk, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
if (chunk < 0) {
pr_perror("Can't read from socket");
......
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