Commit 1a200b51 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-virtio-vsock'

parents cd356010 7e699d2a
Loading
Loading
Loading
Loading
+13 −16
Original line number Diff line number Diff line
@@ -241,21 +241,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
}

static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
					struct sk_buff *skb)
					u32 len)
{
	if (vvs->rx_bytes + skb->len > vvs->buf_alloc)
	if (vvs->rx_bytes + len > vvs->buf_alloc)
		return false;

	vvs->rx_bytes += skb->len;
	vvs->rx_bytes += len;
	return true;
}

static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs,
					struct sk_buff *skb)
					u32 len)
{
	int len;

	len = skb_headroom(skb) - sizeof(struct virtio_vsock_hdr) - skb->len;
	vvs->rx_bytes -= len;
	vvs->fwd_cnt += len;
}
@@ -367,7 +364,7 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,

	spin_lock_bh(&vvs->rx_lock);
	while (total < len && !skb_queue_empty(&vvs->rx_queue)) {
		skb = __skb_dequeue(&vvs->rx_queue);
		skb = skb_peek(&vvs->rx_queue);

		bytes = len - total;
		if (bytes > skb->len)
@@ -388,10 +385,11 @@ virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
		skb_pull(skb, bytes);

		if (skb->len == 0) {
			virtio_transport_dec_rx_pkt(vvs, skb);
			u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len);

			virtio_transport_dec_rx_pkt(vvs, pkt_len);
			__skb_unlink(skb, &vvs->rx_queue);
			consume_skb(skb);
		} else {
			__skb_queue_head(&vvs->rx_queue, skb);
		}
	}

@@ -437,17 +435,17 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,

	while (!msg_ready) {
		struct virtio_vsock_hdr *hdr;
		size_t pkt_len;

		skb = __skb_dequeue(&vvs->rx_queue);
		if (!skb)
			break;
		hdr = virtio_vsock_hdr(skb);
		pkt_len = (size_t)le32_to_cpu(hdr->len);

		if (dequeued_len >= 0) {
			size_t pkt_len;
			size_t bytes_to_copy;

			pkt_len = (size_t)le32_to_cpu(hdr->len);
			bytes_to_copy = min(user_buf_len, pkt_len);

			if (bytes_to_copy) {
@@ -466,7 +464,6 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
					dequeued_len = err;
				} else {
					user_buf_len -= bytes_to_copy;
					skb_pull(skb, bytes_to_copy);
				}

				spin_lock_bh(&vvs->rx_lock);
@@ -484,7 +481,7 @@ static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
				msg->msg_flags |= MSG_EOR;
		}

		virtio_transport_dec_rx_pkt(vvs, skb);
		virtio_transport_dec_rx_pkt(vvs, pkt_len);
		kfree_skb(skb);
	}

@@ -1040,7 +1037,7 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk,

	spin_lock_bh(&vvs->rx_lock);

	can_enqueue = virtio_transport_inc_rx_pkt(vvs, skb);
	can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
	if (!can_enqueue) {
		free_pkt = true;
		goto out;
+118 −0
Original line number Diff line number Diff line
@@ -860,6 +860,114 @@ static void test_stream_poll_rcvlowat_client(const struct test_opts *opts)
	close(fd);
}

#define INV_BUF_TEST_DATA_LEN 512

static void test_inv_buf_client(const struct test_opts *opts, bool stream)
{
	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
	ssize_t ret;
	int fd;

	if (stream)
		fd = vsock_stream_connect(opts->peer_cid, 1234);
	else
		fd = vsock_seqpacket_connect(opts->peer_cid, 1234);

	if (fd < 0) {
		perror("connect");
		exit(EXIT_FAILURE);
	}

	control_expectln("SENDDONE");

	/* Use invalid buffer here. */
	ret = recv(fd, NULL, sizeof(data), 0);
	if (ret != -1) {
		fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
		exit(EXIT_FAILURE);
	}

	if (errno != ENOMEM) {
		fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
		exit(EXIT_FAILURE);
	}

	ret = recv(fd, data, sizeof(data), MSG_DONTWAIT);

	if (stream) {
		/* For SOCK_STREAM we must continue reading. */
		if (ret != sizeof(data)) {
			fprintf(stderr, "expected recv(2) success, got %zi\n", ret);
			exit(EXIT_FAILURE);
		}
		/* Don't check errno in case of success. */
	} else {
		/* For SOCK_SEQPACKET socket's queue must be empty. */
		if (ret != -1) {
			fprintf(stderr, "expected recv(2) failure, got %zi\n", ret);
			exit(EXIT_FAILURE);
		}

		if (errno != EAGAIN) {
			fprintf(stderr, "unexpected recv(2) errno %d\n", errno);
			exit(EXIT_FAILURE);
		}
	}

	control_writeln("DONE");

	close(fd);
}

static void test_inv_buf_server(const struct test_opts *opts, bool stream)
{
	unsigned char data[INV_BUF_TEST_DATA_LEN] = {0};
	ssize_t res;
	int fd;

	if (stream)
		fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
	else
		fd = vsock_seqpacket_accept(VMADDR_CID_ANY, 1234, NULL);

	if (fd < 0) {
		perror("accept");
		exit(EXIT_FAILURE);
	}

	res = send(fd, data, sizeof(data), 0);
	if (res != sizeof(data)) {
		fprintf(stderr, "unexpected send(2) result %zi\n", res);
		exit(EXIT_FAILURE);
	}

	control_writeln("SENDDONE");

	control_expectln("DONE");

	close(fd);
}

static void test_stream_inv_buf_client(const struct test_opts *opts)
{
	test_inv_buf_client(opts, true);
}

static void test_stream_inv_buf_server(const struct test_opts *opts)
{
	test_inv_buf_server(opts, true);
}

static void test_seqpacket_inv_buf_client(const struct test_opts *opts)
{
	test_inv_buf_client(opts, false);
}

static void test_seqpacket_inv_buf_server(const struct test_opts *opts)
{
	test_inv_buf_server(opts, false);
}

static struct test_case test_cases[] = {
	{
		.name = "SOCK_STREAM connection reset",
@@ -920,6 +1028,16 @@ static struct test_case test_cases[] = {
		.run_client = test_seqpacket_bigmsg_client,
		.run_server = test_seqpacket_bigmsg_server,
	},
	{
		.name = "SOCK_STREAM test invalid buffer",
		.run_client = test_stream_inv_buf_client,
		.run_server = test_stream_inv_buf_server,
	},
	{
		.name = "SOCK_SEQPACKET test invalid buffer",
		.run_client = test_seqpacket_inv_buf_client,
		.run_server = test_seqpacket_inv_buf_server,
	},
	{},
};