Skip to content

Commit 7ba89d2

Browse files
committed
io_uring: ensure recv and recvmsg handle MSG_WAITALL correctly
We currently don't attempt to get the full asked for length even if MSG_WAITALL is set, if we get a partial receive. If we do see a partial receive, then just note how many bytes we did and return -EAGAIN to get it retried. The iov is advanced appropriately for the vector based case, and we manually bump the buffer and remainder for the non-vector case. Cc: [email protected] Reported-by: Constantine Gavrilov <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 4d55f23 commit 7ba89d2

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

fs/io_uring.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ struct io_sr_msg {
612612
int msg_flags;
613613
int bgid;
614614
size_t len;
615+
size_t done_io;
615616
};
616617

617618
struct io_open {
@@ -5417,12 +5418,21 @@ static int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
54175418
if (req->ctx->compat)
54185419
sr->msg_flags |= MSG_CMSG_COMPAT;
54195420
#endif
5421+
sr->done_io = 0;
54205422
return 0;
54215423
}
54225424

5425+
static bool io_net_retry(struct socket *sock, int flags)
5426+
{
5427+
if (!(flags & MSG_WAITALL))
5428+
return false;
5429+
return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET;
5430+
}
5431+
54235432
static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
54245433
{
54255434
struct io_async_msghdr iomsg, *kmsg;
5435+
struct io_sr_msg *sr = &req->sr_msg;
54265436
struct socket *sock;
54275437
struct io_buffer *kbuf;
54285438
unsigned flags;
@@ -5465,6 +5475,10 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
54655475
return io_setup_async_msg(req, kmsg);
54665476
if (ret == -ERESTARTSYS)
54675477
ret = -EINTR;
5478+
if (ret > 0 && io_net_retry(sock, flags)) {
5479+
sr->done_io += ret;
5480+
return io_setup_async_msg(req, kmsg);
5481+
}
54685482
req_set_fail(req);
54695483
} else if ((flags & MSG_WAITALL) && (kmsg->msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
54705484
req_set_fail(req);
@@ -5474,6 +5488,10 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
54745488
if (kmsg->free_iov)
54755489
kfree(kmsg->free_iov);
54765490
req->flags &= ~REQ_F_NEED_CLEANUP;
5491+
if (ret >= 0)
5492+
ret += sr->done_io;
5493+
else if (sr->done_io)
5494+
ret = sr->done_io;
54775495
__io_req_complete(req, issue_flags, ret, io_put_kbuf(req, issue_flags));
54785496
return 0;
54795497
}
@@ -5524,12 +5542,22 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
55245542
return -EAGAIN;
55255543
if (ret == -ERESTARTSYS)
55265544
ret = -EINTR;
5545+
if (ret > 0 && io_net_retry(sock, flags)) {
5546+
sr->len -= ret;
5547+
sr->buf += ret;
5548+
sr->done_io += ret;
5549+
return -EAGAIN;
5550+
}
55275551
req_set_fail(req);
55285552
} else if ((flags & MSG_WAITALL) && (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
55295553
out_free:
55305554
req_set_fail(req);
55315555
}
55325556

5557+
if (ret >= 0)
5558+
ret += sr->done_io;
5559+
else if (sr->done_io)
5560+
ret = sr->done_io;
55335561
__io_req_complete(req, issue_flags, ret, io_put_kbuf(req, issue_flags));
55345562
return 0;
55355563
}

0 commit comments

Comments
 (0)