Skip to content

Commit 9d0cd5d

Browse files
author
Paolo Abeni
committed
Merge branch 'virtio-vsock-some-updates-for-msg_peek-flag'
Arseniy Krasnov says: ==================== virtio/vsock: some updates for MSG_PEEK flag This patchset does several things around MSG_PEEK flag support. In general words it reworks MSG_PEEK test and adds support for this flag in SOCK_SEQPACKET logic. Here is per-patch description: 1) This is cosmetic change for SOCK_STREAM implementation of MSG_PEEK: 1) I think there is no need of "safe" mode walk here as there is no "unlink" of skbs inside loop (it is MSG_PEEK mode - we don't change queue). 2) Nested while loop is removed: in case of MSG_PEEK we just walk over skbs and copy data from each one. I guess this nested loop even didn't behave as loop - it always executed just for single iteration. 2) This adds MSG_PEEK support for SOCK_SEQPACKET. It could be implemented be reworking MSG_PEEK callback for SOCK_STREAM to support SOCK_SEQPACKET also, but I think it will be more simple and clear from potential bugs to implemented it as separate function thus not mixing logics for both types of socket. So I've added it as dedicated function. 3) This is reworked MSG_PEEK test for SOCK_STREAM. Previous version just sent single byte, then tried to read it with MSG_PEEK flag, then read it in normal way. New version is more complex: now sender uses buffer instead of single byte and this buffer is initialized with random values. Receiver tests several things: 1) Read empty socket with MSG_PEEK flag. 2) Read part of buffer with MSG_PEEK flag. 3) Read whole buffer with MSG_PEEK flag, then checks that it is same as buffer from 2) (limited by size of buffer from 2) of course). 4) Read whole buffer without any flags, then checks that it is same as buffer from 3). 4) This is MSG_PEEK test for SOCK_SEQPACKET. It works in the same way as for SOCK_STREAM, except it also checks combination of MSG_TRUNC and MSG_PEEK. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents bc758ad + 8a0697f commit 9d0cd5d

File tree

2 files changed

+208
-32
lines changed

2 files changed

+208
-32
lines changed

net/vmw_vsock/virtio_transport_common.c

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -348,37 +348,34 @@ virtio_transport_stream_do_peek(struct vsock_sock *vsk,
348348
size_t len)
349349
{
350350
struct virtio_vsock_sock *vvs = vsk->trans;
351-
size_t bytes, total = 0, off;
352-
struct sk_buff *skb, *tmp;
353-
int err = -EFAULT;
351+
struct sk_buff *skb;
352+
size_t total = 0;
353+
int err;
354354

355355
spin_lock_bh(&vvs->rx_lock);
356356

357-
skb_queue_walk_safe(&vvs->rx_queue, skb, tmp) {
358-
off = 0;
357+
skb_queue_walk(&vvs->rx_queue, skb) {
358+
size_t bytes;
359359

360-
if (total == len)
361-
break;
360+
bytes = len - total;
361+
if (bytes > skb->len)
362+
bytes = skb->len;
362363

363-
while (total < len && off < skb->len) {
364-
bytes = len - total;
365-
if (bytes > skb->len - off)
366-
bytes = skb->len - off;
364+
spin_unlock_bh(&vvs->rx_lock);
367365

368-
/* sk_lock is held by caller so no one else can dequeue.
369-
* Unlock rx_lock since memcpy_to_msg() may sleep.
370-
*/
371-
spin_unlock_bh(&vvs->rx_lock);
366+
/* sk_lock is held by caller so no one else can dequeue.
367+
* Unlock rx_lock since memcpy_to_msg() may sleep.
368+
*/
369+
err = memcpy_to_msg(msg, skb->data, bytes);
370+
if (err)
371+
goto out;
372372

373-
err = memcpy_to_msg(msg, skb->data + off, bytes);
374-
if (err)
375-
goto out;
373+
total += bytes;
376374

377-
spin_lock_bh(&vvs->rx_lock);
375+
spin_lock_bh(&vvs->rx_lock);
378376

379-
total += bytes;
380-
off += bytes;
381-
}
377+
if (total == len)
378+
break;
382379
}
383380

384381
spin_unlock_bh(&vvs->rx_lock);
@@ -463,6 +460,63 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
463460
return err;
464461
}
465462

463+
static ssize_t
464+
virtio_transport_seqpacket_do_peek(struct vsock_sock *vsk,
465+
struct msghdr *msg)
466+
{
467+
struct virtio_vsock_sock *vvs = vsk->trans;
468+
struct sk_buff *skb;
469+
size_t total, len;
470+
471+
spin_lock_bh(&vvs->rx_lock);
472+
473+
if (!vvs->msg_count) {
474+
spin_unlock_bh(&vvs->rx_lock);
475+
return 0;
476+
}
477+
478+
total = 0;
479+
len = msg_data_left(msg);
480+
481+
skb_queue_walk(&vvs->rx_queue, skb) {
482+
struct virtio_vsock_hdr *hdr;
483+
484+
if (total < len) {
485+
size_t bytes;
486+
int err;
487+
488+
bytes = len - total;
489+
if (bytes > skb->len)
490+
bytes = skb->len;
491+
492+
spin_unlock_bh(&vvs->rx_lock);
493+
494+
/* sk_lock is held by caller so no one else can dequeue.
495+
* Unlock rx_lock since memcpy_to_msg() may sleep.
496+
*/
497+
err = memcpy_to_msg(msg, skb->data, bytes);
498+
if (err)
499+
return err;
500+
501+
spin_lock_bh(&vvs->rx_lock);
502+
}
503+
504+
total += skb->len;
505+
hdr = virtio_vsock_hdr(skb);
506+
507+
if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) {
508+
if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR)
509+
msg->msg_flags |= MSG_EOR;
510+
511+
break;
512+
}
513+
}
514+
515+
spin_unlock_bh(&vvs->rx_lock);
516+
517+
return total;
518+
}
519+
466520
static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
467521
struct msghdr *msg,
468522
int flags)
@@ -557,9 +611,9 @@ virtio_transport_seqpacket_dequeue(struct vsock_sock *vsk,
557611
int flags)
558612
{
559613
if (flags & MSG_PEEK)
560-
return -EOPNOTSUPP;
561-
562-
return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags);
614+
return virtio_transport_seqpacket_do_peek(vsk, msg);
615+
else
616+
return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags);
563617
}
564618
EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_dequeue);
565619

tools/testing/vsock/vsock_test.c

Lines changed: 129 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,35 +255,142 @@ static void test_stream_multiconn_server(const struct test_opts *opts)
255255
close(fds[i]);
256256
}
257257

258-
static void test_stream_msg_peek_client(const struct test_opts *opts)
258+
#define MSG_PEEK_BUF_LEN 64
259+
260+
static void test_msg_peek_client(const struct test_opts *opts,
261+
bool seqpacket)
259262
{
263+
unsigned char buf[MSG_PEEK_BUF_LEN];
264+
ssize_t send_size;
260265
int fd;
266+
int i;
267+
268+
if (seqpacket)
269+
fd = vsock_seqpacket_connect(opts->peer_cid, 1234);
270+
else
271+
fd = vsock_stream_connect(opts->peer_cid, 1234);
261272

262-
fd = vsock_stream_connect(opts->peer_cid, 1234);
263273
if (fd < 0) {
264274
perror("connect");
265275
exit(EXIT_FAILURE);
266276
}
267277

268-
send_byte(fd, 1, 0);
278+
for (i = 0; i < sizeof(buf); i++)
279+
buf[i] = rand() & 0xFF;
280+
281+
control_expectln("SRVREADY");
282+
283+
send_size = send(fd, buf, sizeof(buf), 0);
284+
285+
if (send_size < 0) {
286+
perror("send");
287+
exit(EXIT_FAILURE);
288+
}
289+
290+
if (send_size != sizeof(buf)) {
291+
fprintf(stderr, "Invalid send size %zi\n", send_size);
292+
exit(EXIT_FAILURE);
293+
}
294+
269295
close(fd);
270296
}
271297

272-
static void test_stream_msg_peek_server(const struct test_opts *opts)
298+
static void test_msg_peek_server(const struct test_opts *opts,
299+
bool seqpacket)
273300
{
301+
unsigned char buf_half[MSG_PEEK_BUF_LEN / 2];
302+
unsigned char buf_normal[MSG_PEEK_BUF_LEN];
303+
unsigned char buf_peek[MSG_PEEK_BUF_LEN];
304+
ssize_t res;
274305
int fd;
275306

276-
fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
307+
if (seqpacket)
308+
fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);
309+
else
310+
fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
311+
277312
if (fd < 0) {
278313
perror("accept");
279314
exit(EXIT_FAILURE);
280315
}
281316

282-
recv_byte(fd, 1, MSG_PEEK);
283-
recv_byte(fd, 1, 0);
317+
/* Peek from empty socket. */
318+
res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK | MSG_DONTWAIT);
319+
if (res != -1) {
320+
fprintf(stderr, "expected recv(2) failure, got %zi\n", res);
321+
exit(EXIT_FAILURE);
322+
}
323+
324+
if (errno != EAGAIN) {
325+
perror("EAGAIN expected");
326+
exit(EXIT_FAILURE);
327+
}
328+
329+
control_writeln("SRVREADY");
330+
331+
/* Peek part of data. */
332+
res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK);
333+
if (res != sizeof(buf_half)) {
334+
fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
335+
sizeof(buf_half), res);
336+
exit(EXIT_FAILURE);
337+
}
338+
339+
/* Peek whole data. */
340+
res = recv(fd, buf_peek, sizeof(buf_peek), MSG_PEEK);
341+
if (res != sizeof(buf_peek)) {
342+
fprintf(stderr, "recv(2) + MSG_PEEK, expected %zu, got %zi\n",
343+
sizeof(buf_peek), res);
344+
exit(EXIT_FAILURE);
345+
}
346+
347+
/* Compare partial and full peek. */
348+
if (memcmp(buf_half, buf_peek, sizeof(buf_half))) {
349+
fprintf(stderr, "Partial peek data mismatch\n");
350+
exit(EXIT_FAILURE);
351+
}
352+
353+
if (seqpacket) {
354+
/* This type of socket supports MSG_TRUNC flag,
355+
* so check it with MSG_PEEK. We must get length
356+
* of the message.
357+
*/
358+
res = recv(fd, buf_half, sizeof(buf_half), MSG_PEEK |
359+
MSG_TRUNC);
360+
if (res != sizeof(buf_peek)) {
361+
fprintf(stderr,
362+
"recv(2) + MSG_PEEK | MSG_TRUNC, exp %zu, got %zi\n",
363+
sizeof(buf_half), res);
364+
exit(EXIT_FAILURE);
365+
}
366+
}
367+
368+
res = recv(fd, buf_normal, sizeof(buf_normal), 0);
369+
if (res != sizeof(buf_normal)) {
370+
fprintf(stderr, "recv(2), expected %zu, got %zi\n",
371+
sizeof(buf_normal), res);
372+
exit(EXIT_FAILURE);
373+
}
374+
375+
/* Compare full peek and normal read. */
376+
if (memcmp(buf_peek, buf_normal, sizeof(buf_peek))) {
377+
fprintf(stderr, "Full peek data mismatch\n");
378+
exit(EXIT_FAILURE);
379+
}
380+
284381
close(fd);
285382
}
286383

384+
static void test_stream_msg_peek_client(const struct test_opts *opts)
385+
{
386+
return test_msg_peek_client(opts, false);
387+
}
388+
389+
static void test_stream_msg_peek_server(const struct test_opts *opts)
390+
{
391+
return test_msg_peek_server(opts, false);
392+
}
393+
287394
#define SOCK_BUF_SIZE (2 * 1024 * 1024)
288395
#define MAX_MSG_SIZE (32 * 1024)
289396

@@ -1053,6 +1160,16 @@ static void test_stream_virtio_skb_merge_server(const struct test_opts *opts)
10531160
close(fd);
10541161
}
10551162

1163+
static void test_seqpacket_msg_peek_client(const struct test_opts *opts)
1164+
{
1165+
return test_msg_peek_client(opts, true);
1166+
}
1167+
1168+
static void test_seqpacket_msg_peek_server(const struct test_opts *opts)
1169+
{
1170+
return test_msg_peek_server(opts, true);
1171+
}
1172+
10561173
static struct test_case test_cases[] = {
10571174
{
10581175
.name = "SOCK_STREAM connection reset",
@@ -1128,6 +1245,11 @@ static struct test_case test_cases[] = {
11281245
.run_client = test_stream_virtio_skb_merge_client,
11291246
.run_server = test_stream_virtio_skb_merge_server,
11301247
},
1248+
{
1249+
.name = "SOCK_SEQPACKET MSG_PEEK",
1250+
.run_client = test_seqpacket_msg_peek_client,
1251+
.run_server = test_seqpacket_msg_peek_server,
1252+
},
11311253
{},
11321254
};
11331255

0 commit comments

Comments
 (0)