diff options
author | Asias He <asias@redhat.com> | 2016-07-28 10:36:32 -0400 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-08-01 19:57:29 -0400 |
commit | 06a8fc78367d070720af960dcecec917d3ae5f3b (patch) | |
tree | cc25aed5bc98a494227f2d0ba34d7867fccfa1f9 | |
parent | 6773b7dc39f165bd9d824b50ac52cbb3f87d53c8 (diff) |
VSOCK: Introduce virtio_vsock_common.ko
This module contains the common code and header files for the following
virtio_transporto and vhost_vsock kernel modules.
Signed-off-by: Asias He <asias@redhat.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r-- | MAINTAINERS | 10 | ||||
-rw-r--r-- | include/linux/virtio_vsock.h | 154 | ||||
-rw-r--r-- | include/net/af_vsock.h | 2 | ||||
-rw-r--r-- | include/trace/events/vsock_virtio_transport_common.h | 144 | ||||
-rw-r--r-- | include/uapi/linux/Kbuild | 1 | ||||
-rw-r--r-- | include/uapi/linux/virtio_ids.h | 1 | ||||
-rw-r--r-- | include/uapi/linux/virtio_vsock.h | 94 | ||||
-rw-r--r-- | net/vmw_vsock/virtio_transport_common.c | 992 |
8 files changed, 1398 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 8c20323d1277..b49ffb86ebf0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -12138,6 +12138,16 @@ S: Maintained | |||
12138 | F: drivers/media/v4l2-core/videobuf2-* | 12138 | F: drivers/media/v4l2-core/videobuf2-* |
12139 | F: include/media/videobuf2-* | 12139 | F: include/media/videobuf2-* |
12140 | 12140 | ||
12141 | VIRTIO AND VHOST VSOCK DRIVER | ||
12142 | M: Stefan Hajnoczi <stefanha@redhat.com> | ||
12143 | L: kvm@vger.kernel.org | ||
12144 | L: virtualization@lists.linux-foundation.org | ||
12145 | L: netdev@vger.kernel.org | ||
12146 | S: Maintained | ||
12147 | F: include/linux/virtio_vsock.h | ||
12148 | F: include/uapi/linux/virtio_vsock.h | ||
12149 | F: net/vmw_vsock/virtio_transport_common.c | ||
12150 | |||
12141 | VIRTUAL SERIO DEVICE DRIVER | 12151 | VIRTUAL SERIO DEVICE DRIVER |
12142 | M: Stephen Chandler Paul <thatslyude@gmail.com> | 12152 | M: Stephen Chandler Paul <thatslyude@gmail.com> |
12143 | S: Maintained | 12153 | S: Maintained |
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h new file mode 100644 index 000000000000..9638bfeb0d1f --- /dev/null +++ b/include/linux/virtio_vsock.h | |||
@@ -0,0 +1,154 @@ | |||
1 | #ifndef _LINUX_VIRTIO_VSOCK_H | ||
2 | #define _LINUX_VIRTIO_VSOCK_H | ||
3 | |||
4 | #include <uapi/linux/virtio_vsock.h> | ||
5 | #include <linux/socket.h> | ||
6 | #include <net/sock.h> | ||
7 | #include <net/af_vsock.h> | ||
8 | |||
9 | #define VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE 128 | ||
10 | #define VIRTIO_VSOCK_DEFAULT_BUF_SIZE (1024 * 256) | ||
11 | #define VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE (1024 * 256) | ||
12 | #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4) | ||
13 | #define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL | ||
14 | #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) | ||
15 | |||
16 | enum { | ||
17 | VSOCK_VQ_RX = 0, /* for host to guest data */ | ||
18 | VSOCK_VQ_TX = 1, /* for guest to host data */ | ||
19 | VSOCK_VQ_EVENT = 2, | ||
20 | VSOCK_VQ_MAX = 3, | ||
21 | }; | ||
22 | |||
23 | /* Per-socket state (accessed via vsk->trans) */ | ||
24 | struct virtio_vsock_sock { | ||
25 | struct vsock_sock *vsk; | ||
26 | |||
27 | /* Protected by lock_sock(sk_vsock(trans->vsk)) */ | ||
28 | u32 buf_size; | ||
29 | u32 buf_size_min; | ||
30 | u32 buf_size_max; | ||
31 | |||
32 | spinlock_t tx_lock; | ||
33 | spinlock_t rx_lock; | ||
34 | |||
35 | /* Protected by tx_lock */ | ||
36 | u32 tx_cnt; | ||
37 | u32 buf_alloc; | ||
38 | u32 peer_fwd_cnt; | ||
39 | u32 peer_buf_alloc; | ||
40 | |||
41 | /* Protected by rx_lock */ | ||
42 | u32 fwd_cnt; | ||
43 | u32 rx_bytes; | ||
44 | struct list_head rx_queue; | ||
45 | }; | ||
46 | |||
47 | struct virtio_vsock_pkt { | ||
48 | struct virtio_vsock_hdr hdr; | ||
49 | struct work_struct work; | ||
50 | struct list_head list; | ||
51 | void *buf; | ||
52 | u32 len; | ||
53 | u32 off; | ||
54 | bool reply; | ||
55 | }; | ||
56 | |||
57 | struct virtio_vsock_pkt_info { | ||
58 | u32 remote_cid, remote_port; | ||
59 | struct msghdr *msg; | ||
60 | u32 pkt_len; | ||
61 | u16 type; | ||
62 | u16 op; | ||
63 | u32 flags; | ||
64 | bool reply; | ||
65 | }; | ||
66 | |||
67 | struct virtio_transport { | ||
68 | /* This must be the first field */ | ||
69 | struct vsock_transport transport; | ||
70 | |||
71 | /* Takes ownership of the packet */ | ||
72 | int (*send_pkt)(struct virtio_vsock_pkt *pkt); | ||
73 | }; | ||
74 | |||
75 | ssize_t | ||
76 | virtio_transport_stream_dequeue(struct vsock_sock *vsk, | ||
77 | struct msghdr *msg, | ||
78 | size_t len, | ||
79 | int type); | ||
80 | int | ||
81 | virtio_transport_dgram_dequeue(struct vsock_sock *vsk, | ||
82 | struct msghdr *msg, | ||
83 | size_t len, int flags); | ||
84 | |||
85 | s64 virtio_transport_stream_has_data(struct vsock_sock *vsk); | ||
86 | s64 virtio_transport_stream_has_space(struct vsock_sock *vsk); | ||
87 | |||
88 | int virtio_transport_do_socket_init(struct vsock_sock *vsk, | ||
89 | struct vsock_sock *psk); | ||
90 | u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk); | ||
91 | u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk); | ||
92 | u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk); | ||
93 | void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val); | ||
94 | void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val); | ||
95 | void virtio_transport_set_max_buffer_size(struct vsock_sock *vs, u64 val); | ||
96 | int | ||
97 | virtio_transport_notify_poll_in(struct vsock_sock *vsk, | ||
98 | size_t target, | ||
99 | bool *data_ready_now); | ||
100 | int | ||
101 | virtio_transport_notify_poll_out(struct vsock_sock *vsk, | ||
102 | size_t target, | ||
103 | bool *space_available_now); | ||
104 | |||
105 | int virtio_transport_notify_recv_init(struct vsock_sock *vsk, | ||
106 | size_t target, struct vsock_transport_recv_notify_data *data); | ||
107 | int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk, | ||
108 | size_t target, struct vsock_transport_recv_notify_data *data); | ||
109 | int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk, | ||
110 | size_t target, struct vsock_transport_recv_notify_data *data); | ||
111 | int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk, | ||
112 | size_t target, ssize_t copied, bool data_read, | ||
113 | struct vsock_transport_recv_notify_data *data); | ||
114 | int virtio_transport_notify_send_init(struct vsock_sock *vsk, | ||
115 | struct vsock_transport_send_notify_data *data); | ||
116 | int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk, | ||
117 | struct vsock_transport_send_notify_data *data); | ||
118 | int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk, | ||
119 | struct vsock_transport_send_notify_data *data); | ||
120 | int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk, | ||
121 | ssize_t written, struct vsock_transport_send_notify_data *data); | ||
122 | |||
123 | u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk); | ||
124 | bool virtio_transport_stream_is_active(struct vsock_sock *vsk); | ||
125 | bool virtio_transport_stream_allow(u32 cid, u32 port); | ||
126 | int virtio_transport_dgram_bind(struct vsock_sock *vsk, | ||
127 | struct sockaddr_vm *addr); | ||
128 | bool virtio_transport_dgram_allow(u32 cid, u32 port); | ||
129 | |||
130 | int virtio_transport_connect(struct vsock_sock *vsk); | ||
131 | |||
132 | int virtio_transport_shutdown(struct vsock_sock *vsk, int mode); | ||
133 | |||
134 | void virtio_transport_release(struct vsock_sock *vsk); | ||
135 | |||
136 | ssize_t | ||
137 | virtio_transport_stream_enqueue(struct vsock_sock *vsk, | ||
138 | struct msghdr *msg, | ||
139 | size_t len); | ||
140 | int | ||
141 | virtio_transport_dgram_enqueue(struct vsock_sock *vsk, | ||
142 | struct sockaddr_vm *remote_addr, | ||
143 | struct msghdr *msg, | ||
144 | size_t len); | ||
145 | |||
146 | void virtio_transport_destruct(struct vsock_sock *vsk); | ||
147 | |||
148 | void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt); | ||
149 | void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt); | ||
150 | void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt); | ||
151 | u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 wanted); | ||
152 | void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit); | ||
153 | |||
154 | #endif /* _LINUX_VIRTIO_VSOCK_H */ | ||
diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 3af0b224f754..f2758964ce6f 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h | |||
@@ -63,6 +63,8 @@ struct vsock_sock { | |||
63 | struct list_head accept_queue; | 63 | struct list_head accept_queue; |
64 | bool rejected; | 64 | bool rejected; |
65 | struct delayed_work dwork; | 65 | struct delayed_work dwork; |
66 | struct delayed_work close_work; | ||
67 | bool close_work_scheduled; | ||
66 | u32 peer_shutdown; | 68 | u32 peer_shutdown; |
67 | bool sent_request; | 69 | bool sent_request; |
68 | bool ignore_connecting_rst; | 70 | bool ignore_connecting_rst; |
diff --git a/include/trace/events/vsock_virtio_transport_common.h b/include/trace/events/vsock_virtio_transport_common.h new file mode 100644 index 000000000000..b7f1d6278280 --- /dev/null +++ b/include/trace/events/vsock_virtio_transport_common.h | |||
@@ -0,0 +1,144 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM vsock | ||
3 | |||
4 | #if !defined(_TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H) || \ | ||
5 | defined(TRACE_HEADER_MULTI_READ) | ||
6 | #define _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H | ||
7 | |||
8 | #include <linux/tracepoint.h> | ||
9 | |||
10 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_TYPE_STREAM); | ||
11 | |||
12 | #define show_type(val) \ | ||
13 | __print_symbolic(val, { VIRTIO_VSOCK_TYPE_STREAM, "STREAM" }) | ||
14 | |||
15 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_INVALID); | ||
16 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_REQUEST); | ||
17 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RESPONSE); | ||
18 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RST); | ||
19 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_SHUTDOWN); | ||
20 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RW); | ||
21 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_UPDATE); | ||
22 | TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_REQUEST); | ||
23 | |||
24 | #define show_op(val) \ | ||
25 | __print_symbolic(val, \ | ||
26 | { VIRTIO_VSOCK_OP_INVALID, "INVALID" }, \ | ||
27 | { VIRTIO_VSOCK_OP_REQUEST, "REQUEST" }, \ | ||
28 | { VIRTIO_VSOCK_OP_RESPONSE, "RESPONSE" }, \ | ||
29 | { VIRTIO_VSOCK_OP_RST, "RST" }, \ | ||
30 | { VIRTIO_VSOCK_OP_SHUTDOWN, "SHUTDOWN" }, \ | ||
31 | { VIRTIO_VSOCK_OP_RW, "RW" }, \ | ||
32 | { VIRTIO_VSOCK_OP_CREDIT_UPDATE, "CREDIT_UPDATE" }, \ | ||
33 | { VIRTIO_VSOCK_OP_CREDIT_REQUEST, "CREDIT_REQUEST" }) | ||
34 | |||
35 | TRACE_EVENT(virtio_transport_alloc_pkt, | ||
36 | TP_PROTO( | ||
37 | __u32 src_cid, __u32 src_port, | ||
38 | __u32 dst_cid, __u32 dst_port, | ||
39 | __u32 len, | ||
40 | __u16 type, | ||
41 | __u16 op, | ||
42 | __u32 flags | ||
43 | ), | ||
44 | TP_ARGS( | ||
45 | src_cid, src_port, | ||
46 | dst_cid, dst_port, | ||
47 | len, | ||
48 | type, | ||
49 | op, | ||
50 | flags | ||
51 | ), | ||
52 | TP_STRUCT__entry( | ||
53 | __field(__u32, src_cid) | ||
54 | __field(__u32, src_port) | ||
55 | __field(__u32, dst_cid) | ||
56 | __field(__u32, dst_port) | ||
57 | __field(__u32, len) | ||
58 | __field(__u16, type) | ||
59 | __field(__u16, op) | ||
60 | __field(__u32, flags) | ||
61 | ), | ||
62 | TP_fast_assign( | ||
63 | __entry->src_cid = src_cid; | ||
64 | __entry->src_port = src_port; | ||
65 | __entry->dst_cid = dst_cid; | ||
66 | __entry->dst_port = dst_port; | ||
67 | __entry->len = len; | ||
68 | __entry->type = type; | ||
69 | __entry->op = op; | ||
70 | __entry->flags = flags; | ||
71 | ), | ||
72 | TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x", | ||
73 | __entry->src_cid, __entry->src_port, | ||
74 | __entry->dst_cid, __entry->dst_port, | ||
75 | __entry->len, | ||
76 | show_type(__entry->type), | ||
77 | show_op(__entry->op), | ||
78 | __entry->flags) | ||
79 | ); | ||
80 | |||
81 | TRACE_EVENT(virtio_transport_recv_pkt, | ||
82 | TP_PROTO( | ||
83 | __u32 src_cid, __u32 src_port, | ||
84 | __u32 dst_cid, __u32 dst_port, | ||
85 | __u32 len, | ||
86 | __u16 type, | ||
87 | __u16 op, | ||
88 | __u32 flags, | ||
89 | __u32 buf_alloc, | ||
90 | __u32 fwd_cnt | ||
91 | ), | ||
92 | TP_ARGS( | ||
93 | src_cid, src_port, | ||
94 | dst_cid, dst_port, | ||
95 | len, | ||
96 | type, | ||
97 | op, | ||
98 | flags, | ||
99 | buf_alloc, | ||
100 | fwd_cnt | ||
101 | ), | ||
102 | TP_STRUCT__entry( | ||
103 | __field(__u32, src_cid) | ||
104 | __field(__u32, src_port) | ||
105 | __field(__u32, dst_cid) | ||
106 | __field(__u32, dst_port) | ||
107 | __field(__u32, len) | ||
108 | __field(__u16, type) | ||
109 | __field(__u16, op) | ||
110 | __field(__u32, flags) | ||
111 | __field(__u32, buf_alloc) | ||
112 | __field(__u32, fwd_cnt) | ||
113 | ), | ||
114 | TP_fast_assign( | ||
115 | __entry->src_cid = src_cid; | ||
116 | __entry->src_port = src_port; | ||
117 | __entry->dst_cid = dst_cid; | ||
118 | __entry->dst_port = dst_port; | ||
119 | __entry->len = len; | ||
120 | __entry->type = type; | ||
121 | __entry->op = op; | ||
122 | __entry->flags = flags; | ||
123 | __entry->buf_alloc = buf_alloc; | ||
124 | __entry->fwd_cnt = fwd_cnt; | ||
125 | ), | ||
126 | TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x " | ||
127 | "buf_alloc=%u fwd_cnt=%u", | ||
128 | __entry->src_cid, __entry->src_port, | ||
129 | __entry->dst_cid, __entry->dst_port, | ||
130 | __entry->len, | ||
131 | show_type(__entry->type), | ||
132 | show_op(__entry->op), | ||
133 | __entry->flags, | ||
134 | __entry->buf_alloc, | ||
135 | __entry->fwd_cnt) | ||
136 | ); | ||
137 | |||
138 | #endif /* _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H */ | ||
139 | |||
140 | #undef TRACE_INCLUDE_FILE | ||
141 | #define TRACE_INCLUDE_FILE vsock_virtio_transport_common | ||
142 | |||
143 | /* This part must be outside protection */ | ||
144 | #include <trace/define_trace.h> | ||
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index ec10cfef166a..3cf0116d9c2b 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild | |||
@@ -453,6 +453,7 @@ header-y += virtio_ring.h | |||
453 | header-y += virtio_rng.h | 453 | header-y += virtio_rng.h |
454 | header-y += virtio_scsi.h | 454 | header-y += virtio_scsi.h |
455 | header-y += virtio_types.h | 455 | header-y += virtio_types.h |
456 | header-y += virtio_vsock.h | ||
456 | header-y += vm_sockets.h | 457 | header-y += vm_sockets.h |
457 | header-y += vt.h | 458 | header-y += vt.h |
458 | header-y += wait.h | 459 | header-y += wait.h |
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 77925f587b15..3228d582234a 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h | |||
@@ -41,5 +41,6 @@ | |||
41 | #define VIRTIO_ID_CAIF 12 /* Virtio caif */ | 41 | #define VIRTIO_ID_CAIF 12 /* Virtio caif */ |
42 | #define VIRTIO_ID_GPU 16 /* virtio GPU */ | 42 | #define VIRTIO_ID_GPU 16 /* virtio GPU */ |
43 | #define VIRTIO_ID_INPUT 18 /* virtio input */ | 43 | #define VIRTIO_ID_INPUT 18 /* virtio input */ |
44 | #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ | ||
44 | 45 | ||
45 | #endif /* _LINUX_VIRTIO_IDS_H */ | 46 | #endif /* _LINUX_VIRTIO_IDS_H */ |
diff --git a/include/uapi/linux/virtio_vsock.h b/include/uapi/linux/virtio_vsock.h new file mode 100644 index 000000000000..6b011c19b50f --- /dev/null +++ b/include/uapi/linux/virtio_vsock.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so | ||
3 | * anyone can use the definitions to implement compatible drivers/servers: | ||
4 | * | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * 3. Neither the name of IBM nor the names of its contributors | ||
15 | * may be used to endorse or promote products derived from this software | ||
16 | * without specific prior written permission. | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' | ||
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE | ||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
27 | * SUCH DAMAGE. | ||
28 | * | ||
29 | * Copyright (C) Red Hat, Inc., 2013-2015 | ||
30 | * Copyright (C) Asias He <asias@redhat.com>, 2013 | ||
31 | * Copyright (C) Stefan Hajnoczi <stefanha@redhat.com>, 2015 | ||
32 | */ | ||
33 | |||
34 | #ifndef _UAPI_LINUX_VIRTIO_VSOCK_H | ||
35 | #define _UAPI_LINUX_VIRTIO_VOSCK_H | ||
36 | |||
37 | #include <linux/types.h> | ||
38 | #include <linux/virtio_ids.h> | ||
39 | #include <linux/virtio_config.h> | ||
40 | |||
41 | struct virtio_vsock_config { | ||
42 | __le64 guest_cid; | ||
43 | } __attribute__((packed)); | ||
44 | |||
45 | enum virtio_vsock_event_id { | ||
46 | VIRTIO_VSOCK_EVENT_TRANSPORT_RESET = 0, | ||
47 | }; | ||
48 | |||
49 | struct virtio_vsock_event { | ||
50 | __le32 id; | ||
51 | } __attribute__((packed)); | ||
52 | |||
53 | struct virtio_vsock_hdr { | ||
54 | __le64 src_cid; | ||
55 | __le64 dst_cid; | ||
56 | __le32 src_port; | ||
57 | __le32 dst_port; | ||
58 | __le32 len; | ||
59 | __le16 type; /* enum virtio_vsock_type */ | ||
60 | __le16 op; /* enum virtio_vsock_op */ | ||
61 | __le32 flags; | ||
62 | __le32 buf_alloc; | ||
63 | __le32 fwd_cnt; | ||
64 | } __attribute__((packed)); | ||
65 | |||
66 | enum virtio_vsock_type { | ||
67 | VIRTIO_VSOCK_TYPE_STREAM = 1, | ||
68 | }; | ||
69 | |||
70 | enum virtio_vsock_op { | ||
71 | VIRTIO_VSOCK_OP_INVALID = 0, | ||
72 | |||
73 | /* Connect operations */ | ||
74 | VIRTIO_VSOCK_OP_REQUEST = 1, | ||
75 | VIRTIO_VSOCK_OP_RESPONSE = 2, | ||
76 | VIRTIO_VSOCK_OP_RST = 3, | ||
77 | VIRTIO_VSOCK_OP_SHUTDOWN = 4, | ||
78 | |||
79 | /* To send payload */ | ||
80 | VIRTIO_VSOCK_OP_RW = 5, | ||
81 | |||
82 | /* Tell the peer our credit info */ | ||
83 | VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6, | ||
84 | /* Request the peer to send the credit info to us */ | ||
85 | VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7, | ||
86 | }; | ||
87 | |||
88 | /* VIRTIO_VSOCK_OP_SHUTDOWN flags values */ | ||
89 | enum virtio_vsock_shutdown { | ||
90 | VIRTIO_VSOCK_SHUTDOWN_RCV = 1, | ||
91 | VIRTIO_VSOCK_SHUTDOWN_SEND = 2, | ||
92 | }; | ||
93 | |||
94 | #endif /* _UAPI_LINUX_VIRTIO_VSOCK_H */ | ||
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c new file mode 100644 index 000000000000..a53b3a16b4f1 --- /dev/null +++ b/net/vmw_vsock/virtio_transport_common.c | |||
@@ -0,0 +1,992 @@ | |||
1 | /* | ||
2 | * common code for virtio vsock | ||
3 | * | ||
4 | * Copyright (C) 2013-2015 Red Hat, Inc. | ||
5 | * Author: Asias He <asias@redhat.com> | ||
6 | * Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | * | ||
8 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
9 | */ | ||
10 | #include <linux/spinlock.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ctype.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/virtio.h> | ||
15 | #include <linux/virtio_ids.h> | ||
16 | #include <linux/virtio_config.h> | ||
17 | #include <linux/virtio_vsock.h> | ||
18 | |||
19 | #include <net/sock.h> | ||
20 | #include <net/af_vsock.h> | ||
21 | |||
22 | #define CREATE_TRACE_POINTS | ||
23 | #include <trace/events/vsock_virtio_transport_common.h> | ||
24 | |||
25 | /* How long to wait for graceful shutdown of a connection */ | ||
26 | #define VSOCK_CLOSE_TIMEOUT (8 * HZ) | ||
27 | |||
28 | static const struct virtio_transport *virtio_transport_get_ops(void) | ||
29 | { | ||
30 | const struct vsock_transport *t = vsock_core_get_transport(); | ||
31 | |||
32 | return container_of(t, struct virtio_transport, transport); | ||
33 | } | ||
34 | |||
35 | struct virtio_vsock_pkt * | ||
36 | virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info, | ||
37 | size_t len, | ||
38 | u32 src_cid, | ||
39 | u32 src_port, | ||
40 | u32 dst_cid, | ||
41 | u32 dst_port) | ||
42 | { | ||
43 | struct virtio_vsock_pkt *pkt; | ||
44 | int err; | ||
45 | |||
46 | pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); | ||
47 | if (!pkt) | ||
48 | return NULL; | ||
49 | |||
50 | pkt->hdr.type = cpu_to_le16(info->type); | ||
51 | pkt->hdr.op = cpu_to_le16(info->op); | ||
52 | pkt->hdr.src_cid = cpu_to_le64(src_cid); | ||
53 | pkt->hdr.dst_cid = cpu_to_le64(dst_cid); | ||
54 | pkt->hdr.src_port = cpu_to_le32(src_port); | ||
55 | pkt->hdr.dst_port = cpu_to_le32(dst_port); | ||
56 | pkt->hdr.flags = cpu_to_le32(info->flags); | ||
57 | pkt->len = len; | ||
58 | pkt->hdr.len = cpu_to_le32(len); | ||
59 | pkt->reply = info->reply; | ||
60 | |||
61 | if (info->msg && len > 0) { | ||
62 | pkt->buf = kmalloc(len, GFP_KERNEL); | ||
63 | if (!pkt->buf) | ||
64 | goto out_pkt; | ||
65 | err = memcpy_from_msg(pkt->buf, info->msg, len); | ||
66 | if (err) | ||
67 | goto out; | ||
68 | } | ||
69 | |||
70 | trace_virtio_transport_alloc_pkt(src_cid, src_port, | ||
71 | dst_cid, dst_port, | ||
72 | len, | ||
73 | info->type, | ||
74 | info->op, | ||
75 | info->flags); | ||
76 | |||
77 | return pkt; | ||
78 | |||
79 | out: | ||
80 | kfree(pkt->buf); | ||
81 | out_pkt: | ||
82 | kfree(pkt); | ||
83 | return NULL; | ||
84 | } | ||
85 | EXPORT_SYMBOL_GPL(virtio_transport_alloc_pkt); | ||
86 | |||
87 | static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, | ||
88 | struct virtio_vsock_pkt_info *info) | ||
89 | { | ||
90 | u32 src_cid, src_port, dst_cid, dst_port; | ||
91 | struct virtio_vsock_sock *vvs; | ||
92 | struct virtio_vsock_pkt *pkt; | ||
93 | u32 pkt_len = info->pkt_len; | ||
94 | |||
95 | src_cid = vm_sockets_get_local_cid(); | ||
96 | src_port = vsk->local_addr.svm_port; | ||
97 | if (!info->remote_cid) { | ||
98 | dst_cid = vsk->remote_addr.svm_cid; | ||
99 | dst_port = vsk->remote_addr.svm_port; | ||
100 | } else { | ||
101 | dst_cid = info->remote_cid; | ||
102 | dst_port = info->remote_port; | ||
103 | } | ||
104 | |||
105 | vvs = vsk->trans; | ||
106 | |||
107 | /* we can send less than pkt_len bytes */ | ||
108 | if (pkt_len > VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE) | ||
109 | pkt_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE; | ||
110 | |||
111 | /* virtio_transport_get_credit might return less than pkt_len credit */ | ||
112 | pkt_len = virtio_transport_get_credit(vvs, pkt_len); | ||
113 | |||
114 | /* Do not send zero length OP_RW pkt */ | ||
115 | if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW) | ||
116 | return pkt_len; | ||
117 | |||
118 | pkt = virtio_transport_alloc_pkt(info, pkt_len, | ||
119 | src_cid, src_port, | ||
120 | dst_cid, dst_port); | ||
121 | if (!pkt) { | ||
122 | virtio_transport_put_credit(vvs, pkt_len); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | |||
126 | virtio_transport_inc_tx_pkt(vvs, pkt); | ||
127 | |||
128 | return virtio_transport_get_ops()->send_pkt(pkt); | ||
129 | } | ||
130 | |||
131 | static void virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, | ||
132 | struct virtio_vsock_pkt *pkt) | ||
133 | { | ||
134 | vvs->rx_bytes += pkt->len; | ||
135 | } | ||
136 | |||
137 | static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, | ||
138 | struct virtio_vsock_pkt *pkt) | ||
139 | { | ||
140 | vvs->rx_bytes -= pkt->len; | ||
141 | vvs->fwd_cnt += pkt->len; | ||
142 | } | ||
143 | |||
144 | void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt) | ||
145 | { | ||
146 | spin_lock_bh(&vvs->tx_lock); | ||
147 | pkt->hdr.fwd_cnt = cpu_to_le32(vvs->fwd_cnt); | ||
148 | pkt->hdr.buf_alloc = cpu_to_le32(vvs->buf_alloc); | ||
149 | spin_unlock_bh(&vvs->tx_lock); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt); | ||
152 | |||
153 | u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit) | ||
154 | { | ||
155 | u32 ret; | ||
156 | |||
157 | spin_lock_bh(&vvs->tx_lock); | ||
158 | ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); | ||
159 | if (ret > credit) | ||
160 | ret = credit; | ||
161 | vvs->tx_cnt += ret; | ||
162 | spin_unlock_bh(&vvs->tx_lock); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | EXPORT_SYMBOL_GPL(virtio_transport_get_credit); | ||
167 | |||
168 | void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit) | ||
169 | { | ||
170 | spin_lock_bh(&vvs->tx_lock); | ||
171 | vvs->tx_cnt -= credit; | ||
172 | spin_unlock_bh(&vvs->tx_lock); | ||
173 | } | ||
174 | EXPORT_SYMBOL_GPL(virtio_transport_put_credit); | ||
175 | |||
176 | static int virtio_transport_send_credit_update(struct vsock_sock *vsk, | ||
177 | int type, | ||
178 | struct virtio_vsock_hdr *hdr) | ||
179 | { | ||
180 | struct virtio_vsock_pkt_info info = { | ||
181 | .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE, | ||
182 | .type = type, | ||
183 | }; | ||
184 | |||
185 | return virtio_transport_send_pkt_info(vsk, &info); | ||
186 | } | ||
187 | |||
188 | static ssize_t | ||
189 | virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, | ||
190 | struct msghdr *msg, | ||
191 | size_t len) | ||
192 | { | ||
193 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
194 | struct virtio_vsock_pkt *pkt; | ||
195 | size_t bytes, total = 0; | ||
196 | int err = -EFAULT; | ||
197 | |||
198 | spin_lock_bh(&vvs->rx_lock); | ||
199 | while (total < len && !list_empty(&vvs->rx_queue)) { | ||
200 | pkt = list_first_entry(&vvs->rx_queue, | ||
201 | struct virtio_vsock_pkt, list); | ||
202 | |||
203 | bytes = len - total; | ||
204 | if (bytes > pkt->len - pkt->off) | ||
205 | bytes = pkt->len - pkt->off; | ||
206 | |||
207 | /* sk_lock is held by caller so no one else can dequeue. | ||
208 | * Unlock rx_lock since memcpy_to_msg() may sleep. | ||
209 | */ | ||
210 | spin_unlock_bh(&vvs->rx_lock); | ||
211 | |||
212 | err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); | ||
213 | if (err) | ||
214 | goto out; | ||
215 | |||
216 | spin_lock_bh(&vvs->rx_lock); | ||
217 | |||
218 | total += bytes; | ||
219 | pkt->off += bytes; | ||
220 | if (pkt->off == pkt->len) { | ||
221 | virtio_transport_dec_rx_pkt(vvs, pkt); | ||
222 | list_del(&pkt->list); | ||
223 | virtio_transport_free_pkt(pkt); | ||
224 | } | ||
225 | } | ||
226 | spin_unlock_bh(&vvs->rx_lock); | ||
227 | |||
228 | /* Send a credit pkt to peer */ | ||
229 | virtio_transport_send_credit_update(vsk, VIRTIO_VSOCK_TYPE_STREAM, | ||
230 | NULL); | ||
231 | |||
232 | return total; | ||
233 | |||
234 | out: | ||
235 | if (total) | ||
236 | err = total; | ||
237 | return err; | ||
238 | } | ||
239 | |||
240 | ssize_t | ||
241 | virtio_transport_stream_dequeue(struct vsock_sock *vsk, | ||
242 | struct msghdr *msg, | ||
243 | size_t len, int flags) | ||
244 | { | ||
245 | if (flags & MSG_PEEK) | ||
246 | return -EOPNOTSUPP; | ||
247 | |||
248 | return virtio_transport_stream_do_dequeue(vsk, msg, len); | ||
249 | } | ||
250 | EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue); | ||
251 | |||
252 | int | ||
253 | virtio_transport_dgram_dequeue(struct vsock_sock *vsk, | ||
254 | struct msghdr *msg, | ||
255 | size_t len, int flags) | ||
256 | { | ||
257 | return -EOPNOTSUPP; | ||
258 | } | ||
259 | EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue); | ||
260 | |||
261 | s64 virtio_transport_stream_has_data(struct vsock_sock *vsk) | ||
262 | { | ||
263 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
264 | s64 bytes; | ||
265 | |||
266 | spin_lock_bh(&vvs->rx_lock); | ||
267 | bytes = vvs->rx_bytes; | ||
268 | spin_unlock_bh(&vvs->rx_lock); | ||
269 | |||
270 | return bytes; | ||
271 | } | ||
272 | EXPORT_SYMBOL_GPL(virtio_transport_stream_has_data); | ||
273 | |||
274 | static s64 virtio_transport_has_space(struct vsock_sock *vsk) | ||
275 | { | ||
276 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
277 | s64 bytes; | ||
278 | |||
279 | bytes = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); | ||
280 | if (bytes < 0) | ||
281 | bytes = 0; | ||
282 | |||
283 | return bytes; | ||
284 | } | ||
285 | |||
286 | s64 virtio_transport_stream_has_space(struct vsock_sock *vsk) | ||
287 | { | ||
288 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
289 | s64 bytes; | ||
290 | |||
291 | spin_lock_bh(&vvs->tx_lock); | ||
292 | bytes = virtio_transport_has_space(vsk); | ||
293 | spin_unlock_bh(&vvs->tx_lock); | ||
294 | |||
295 | return bytes; | ||
296 | } | ||
297 | EXPORT_SYMBOL_GPL(virtio_transport_stream_has_space); | ||
298 | |||
299 | int virtio_transport_do_socket_init(struct vsock_sock *vsk, | ||
300 | struct vsock_sock *psk) | ||
301 | { | ||
302 | struct virtio_vsock_sock *vvs; | ||
303 | |||
304 | vvs = kzalloc(sizeof(*vvs), GFP_KERNEL); | ||
305 | if (!vvs) | ||
306 | return -ENOMEM; | ||
307 | |||
308 | vsk->trans = vvs; | ||
309 | vvs->vsk = vsk; | ||
310 | if (psk) { | ||
311 | struct virtio_vsock_sock *ptrans = psk->trans; | ||
312 | |||
313 | vvs->buf_size = ptrans->buf_size; | ||
314 | vvs->buf_size_min = ptrans->buf_size_min; | ||
315 | vvs->buf_size_max = ptrans->buf_size_max; | ||
316 | vvs->peer_buf_alloc = ptrans->peer_buf_alloc; | ||
317 | } else { | ||
318 | vvs->buf_size = VIRTIO_VSOCK_DEFAULT_BUF_SIZE; | ||
319 | vvs->buf_size_min = VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE; | ||
320 | vvs->buf_size_max = VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE; | ||
321 | } | ||
322 | |||
323 | vvs->buf_alloc = vvs->buf_size; | ||
324 | |||
325 | spin_lock_init(&vvs->rx_lock); | ||
326 | spin_lock_init(&vvs->tx_lock); | ||
327 | INIT_LIST_HEAD(&vvs->rx_queue); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(virtio_transport_do_socket_init); | ||
332 | |||
333 | u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk) | ||
334 | { | ||
335 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
336 | |||
337 | return vvs->buf_size; | ||
338 | } | ||
339 | EXPORT_SYMBOL_GPL(virtio_transport_get_buffer_size); | ||
340 | |||
341 | u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk) | ||
342 | { | ||
343 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
344 | |||
345 | return vvs->buf_size_min; | ||
346 | } | ||
347 | EXPORT_SYMBOL_GPL(virtio_transport_get_min_buffer_size); | ||
348 | |||
349 | u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk) | ||
350 | { | ||
351 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
352 | |||
353 | return vvs->buf_size_max; | ||
354 | } | ||
355 | EXPORT_SYMBOL_GPL(virtio_transport_get_max_buffer_size); | ||
356 | |||
357 | void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val) | ||
358 | { | ||
359 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
360 | |||
361 | if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) | ||
362 | val = VIRTIO_VSOCK_MAX_BUF_SIZE; | ||
363 | if (val < vvs->buf_size_min) | ||
364 | vvs->buf_size_min = val; | ||
365 | if (val > vvs->buf_size_max) | ||
366 | vvs->buf_size_max = val; | ||
367 | vvs->buf_size = val; | ||
368 | vvs->buf_alloc = val; | ||
369 | } | ||
370 | EXPORT_SYMBOL_GPL(virtio_transport_set_buffer_size); | ||
371 | |||
372 | void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val) | ||
373 | { | ||
374 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
375 | |||
376 | if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) | ||
377 | val = VIRTIO_VSOCK_MAX_BUF_SIZE; | ||
378 | if (val > vvs->buf_size) | ||
379 | vvs->buf_size = val; | ||
380 | vvs->buf_size_min = val; | ||
381 | } | ||
382 | EXPORT_SYMBOL_GPL(virtio_transport_set_min_buffer_size); | ||
383 | |||
384 | void virtio_transport_set_max_buffer_size(struct vsock_sock *vsk, u64 val) | ||
385 | { | ||
386 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
387 | |||
388 | if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) | ||
389 | val = VIRTIO_VSOCK_MAX_BUF_SIZE; | ||
390 | if (val < vvs->buf_size) | ||
391 | vvs->buf_size = val; | ||
392 | vvs->buf_size_max = val; | ||
393 | } | ||
394 | EXPORT_SYMBOL_GPL(virtio_transport_set_max_buffer_size); | ||
395 | |||
396 | int | ||
397 | virtio_transport_notify_poll_in(struct vsock_sock *vsk, | ||
398 | size_t target, | ||
399 | bool *data_ready_now) | ||
400 | { | ||
401 | if (vsock_stream_has_data(vsk)) | ||
402 | *data_ready_now = true; | ||
403 | else | ||
404 | *data_ready_now = false; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in); | ||
409 | |||
410 | int | ||
411 | virtio_transport_notify_poll_out(struct vsock_sock *vsk, | ||
412 | size_t target, | ||
413 | bool *space_avail_now) | ||
414 | { | ||
415 | s64 free_space; | ||
416 | |||
417 | free_space = vsock_stream_has_space(vsk); | ||
418 | if (free_space > 0) | ||
419 | *space_avail_now = true; | ||
420 | else if (free_space == 0) | ||
421 | *space_avail_now = false; | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out); | ||
426 | |||
427 | int virtio_transport_notify_recv_init(struct vsock_sock *vsk, | ||
428 | size_t target, struct vsock_transport_recv_notify_data *data) | ||
429 | { | ||
430 | return 0; | ||
431 | } | ||
432 | EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init); | ||
433 | |||
434 | int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk, | ||
435 | size_t target, struct vsock_transport_recv_notify_data *data) | ||
436 | { | ||
437 | return 0; | ||
438 | } | ||
439 | EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block); | ||
440 | |||
441 | int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk, | ||
442 | size_t target, struct vsock_transport_recv_notify_data *data) | ||
443 | { | ||
444 | return 0; | ||
445 | } | ||
446 | EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue); | ||
447 | |||
448 | int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk, | ||
449 | size_t target, ssize_t copied, bool data_read, | ||
450 | struct vsock_transport_recv_notify_data *data) | ||
451 | { | ||
452 | return 0; | ||
453 | } | ||
454 | EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue); | ||
455 | |||
456 | int virtio_transport_notify_send_init(struct vsock_sock *vsk, | ||
457 | struct vsock_transport_send_notify_data *data) | ||
458 | { | ||
459 | return 0; | ||
460 | } | ||
461 | EXPORT_SYMBOL_GPL(virtio_transport_notify_send_init); | ||
462 | |||
463 | int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk, | ||
464 | struct vsock_transport_send_notify_data *data) | ||
465 | { | ||
466 | return 0; | ||
467 | } | ||
468 | EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block); | ||
469 | |||
470 | int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk, | ||
471 | struct vsock_transport_send_notify_data *data) | ||
472 | { | ||
473 | return 0; | ||
474 | } | ||
475 | EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue); | ||
476 | |||
477 | int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk, | ||
478 | ssize_t written, struct vsock_transport_send_notify_data *data) | ||
479 | { | ||
480 | return 0; | ||
481 | } | ||
482 | EXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue); | ||
483 | |||
484 | u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk) | ||
485 | { | ||
486 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
487 | |||
488 | return vvs->buf_size; | ||
489 | } | ||
490 | EXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat); | ||
491 | |||
492 | bool virtio_transport_stream_is_active(struct vsock_sock *vsk) | ||
493 | { | ||
494 | return true; | ||
495 | } | ||
496 | EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active); | ||
497 | |||
498 | bool virtio_transport_stream_allow(u32 cid, u32 port) | ||
499 | { | ||
500 | return true; | ||
501 | } | ||
502 | EXPORT_SYMBOL_GPL(virtio_transport_stream_allow); | ||
503 | |||
504 | int virtio_transport_dgram_bind(struct vsock_sock *vsk, | ||
505 | struct sockaddr_vm *addr) | ||
506 | { | ||
507 | return -EOPNOTSUPP; | ||
508 | } | ||
509 | EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind); | ||
510 | |||
511 | bool virtio_transport_dgram_allow(u32 cid, u32 port) | ||
512 | { | ||
513 | return false; | ||
514 | } | ||
515 | EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow); | ||
516 | |||
517 | int virtio_transport_connect(struct vsock_sock *vsk) | ||
518 | { | ||
519 | struct virtio_vsock_pkt_info info = { | ||
520 | .op = VIRTIO_VSOCK_OP_REQUEST, | ||
521 | .type = VIRTIO_VSOCK_TYPE_STREAM, | ||
522 | }; | ||
523 | |||
524 | return virtio_transport_send_pkt_info(vsk, &info); | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(virtio_transport_connect); | ||
527 | |||
528 | int virtio_transport_shutdown(struct vsock_sock *vsk, int mode) | ||
529 | { | ||
530 | struct virtio_vsock_pkt_info info = { | ||
531 | .op = VIRTIO_VSOCK_OP_SHUTDOWN, | ||
532 | .type = VIRTIO_VSOCK_TYPE_STREAM, | ||
533 | .flags = (mode & RCV_SHUTDOWN ? | ||
534 | VIRTIO_VSOCK_SHUTDOWN_RCV : 0) | | ||
535 | (mode & SEND_SHUTDOWN ? | ||
536 | VIRTIO_VSOCK_SHUTDOWN_SEND : 0), | ||
537 | }; | ||
538 | |||
539 | return virtio_transport_send_pkt_info(vsk, &info); | ||
540 | } | ||
541 | EXPORT_SYMBOL_GPL(virtio_transport_shutdown); | ||
542 | |||
543 | int | ||
544 | virtio_transport_dgram_enqueue(struct vsock_sock *vsk, | ||
545 | struct sockaddr_vm *remote_addr, | ||
546 | struct msghdr *msg, | ||
547 | size_t dgram_len) | ||
548 | { | ||
549 | return -EOPNOTSUPP; | ||
550 | } | ||
551 | EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue); | ||
552 | |||
553 | ssize_t | ||
554 | virtio_transport_stream_enqueue(struct vsock_sock *vsk, | ||
555 | struct msghdr *msg, | ||
556 | size_t len) | ||
557 | { | ||
558 | struct virtio_vsock_pkt_info info = { | ||
559 | .op = VIRTIO_VSOCK_OP_RW, | ||
560 | .type = VIRTIO_VSOCK_TYPE_STREAM, | ||
561 | .msg = msg, | ||
562 | .pkt_len = len, | ||
563 | }; | ||
564 | |||
565 | return virtio_transport_send_pkt_info(vsk, &info); | ||
566 | } | ||
567 | EXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue); | ||
568 | |||
569 | void virtio_transport_destruct(struct vsock_sock *vsk) | ||
570 | { | ||
571 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
572 | |||
573 | kfree(vvs); | ||
574 | } | ||
575 | EXPORT_SYMBOL_GPL(virtio_transport_destruct); | ||
576 | |||
577 | static int virtio_transport_reset(struct vsock_sock *vsk, | ||
578 | struct virtio_vsock_pkt *pkt) | ||
579 | { | ||
580 | struct virtio_vsock_pkt_info info = { | ||
581 | .op = VIRTIO_VSOCK_OP_RST, | ||
582 | .type = VIRTIO_VSOCK_TYPE_STREAM, | ||
583 | .reply = !!pkt, | ||
584 | }; | ||
585 | |||
586 | /* Send RST only if the original pkt is not a RST pkt */ | ||
587 | if (pkt && le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) | ||
588 | return 0; | ||
589 | |||
590 | return virtio_transport_send_pkt_info(vsk, &info); | ||
591 | } | ||
592 | |||
593 | /* Normally packets are associated with a socket. There may be no socket if an | ||
594 | * attempt was made to connect to a socket that does not exist. | ||
595 | */ | ||
596 | static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt) | ||
597 | { | ||
598 | struct virtio_vsock_pkt_info info = { | ||
599 | .op = VIRTIO_VSOCK_OP_RST, | ||
600 | .type = le16_to_cpu(pkt->hdr.type), | ||
601 | .reply = true, | ||
602 | }; | ||
603 | |||
604 | /* Send RST only if the original pkt is not a RST pkt */ | ||
605 | if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) | ||
606 | return 0; | ||
607 | |||
608 | pkt = virtio_transport_alloc_pkt(&info, 0, | ||
609 | le32_to_cpu(pkt->hdr.dst_cid), | ||
610 | le32_to_cpu(pkt->hdr.dst_port), | ||
611 | le32_to_cpu(pkt->hdr.src_cid), | ||
612 | le32_to_cpu(pkt->hdr.src_port)); | ||
613 | if (!pkt) | ||
614 | return -ENOMEM; | ||
615 | |||
616 | return virtio_transport_get_ops()->send_pkt(pkt); | ||
617 | } | ||
618 | |||
619 | static void virtio_transport_wait_close(struct sock *sk, long timeout) | ||
620 | { | ||
621 | if (timeout) { | ||
622 | DEFINE_WAIT(wait); | ||
623 | |||
624 | do { | ||
625 | prepare_to_wait(sk_sleep(sk), &wait, | ||
626 | TASK_INTERRUPTIBLE); | ||
627 | if (sk_wait_event(sk, &timeout, | ||
628 | sock_flag(sk, SOCK_DONE))) | ||
629 | break; | ||
630 | } while (!signal_pending(current) && timeout); | ||
631 | |||
632 | finish_wait(sk_sleep(sk), &wait); | ||
633 | } | ||
634 | } | ||
635 | |||
636 | static void virtio_transport_do_close(struct vsock_sock *vsk, | ||
637 | bool cancel_timeout) | ||
638 | { | ||
639 | struct sock *sk = sk_vsock(vsk); | ||
640 | |||
641 | sock_set_flag(sk, SOCK_DONE); | ||
642 | vsk->peer_shutdown = SHUTDOWN_MASK; | ||
643 | if (vsock_stream_has_data(vsk) <= 0) | ||
644 | sk->sk_state = SS_DISCONNECTING; | ||
645 | sk->sk_state_change(sk); | ||
646 | |||
647 | if (vsk->close_work_scheduled && | ||
648 | (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) { | ||
649 | vsk->close_work_scheduled = false; | ||
650 | |||
651 | vsock_remove_sock(vsk); | ||
652 | |||
653 | /* Release refcnt obtained when we scheduled the timeout */ | ||
654 | sock_put(sk); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | static void virtio_transport_close_timeout(struct work_struct *work) | ||
659 | { | ||
660 | struct vsock_sock *vsk = | ||
661 | container_of(work, struct vsock_sock, close_work.work); | ||
662 | struct sock *sk = sk_vsock(vsk); | ||
663 | |||
664 | sock_hold(sk); | ||
665 | lock_sock(sk); | ||
666 | |||
667 | if (!sock_flag(sk, SOCK_DONE)) { | ||
668 | (void)virtio_transport_reset(vsk, NULL); | ||
669 | |||
670 | virtio_transport_do_close(vsk, false); | ||
671 | } | ||
672 | |||
673 | vsk->close_work_scheduled = false; | ||
674 | |||
675 | release_sock(sk); | ||
676 | sock_put(sk); | ||
677 | } | ||
678 | |||
679 | /* User context, vsk->sk is locked */ | ||
680 | static bool virtio_transport_close(struct vsock_sock *vsk) | ||
681 | { | ||
682 | struct sock *sk = &vsk->sk; | ||
683 | |||
684 | if (!(sk->sk_state == SS_CONNECTED || | ||
685 | sk->sk_state == SS_DISCONNECTING)) | ||
686 | return true; | ||
687 | |||
688 | /* Already received SHUTDOWN from peer, reply with RST */ | ||
689 | if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) { | ||
690 | (void)virtio_transport_reset(vsk, NULL); | ||
691 | return true; | ||
692 | } | ||
693 | |||
694 | if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK) | ||
695 | (void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK); | ||
696 | |||
697 | if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING)) | ||
698 | virtio_transport_wait_close(sk, sk->sk_lingertime); | ||
699 | |||
700 | if (sock_flag(sk, SOCK_DONE)) { | ||
701 | return true; | ||
702 | } | ||
703 | |||
704 | sock_hold(sk); | ||
705 | INIT_DELAYED_WORK(&vsk->close_work, | ||
706 | virtio_transport_close_timeout); | ||
707 | vsk->close_work_scheduled = true; | ||
708 | schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT); | ||
709 | return false; | ||
710 | } | ||
711 | |||
712 | void virtio_transport_release(struct vsock_sock *vsk) | ||
713 | { | ||
714 | struct sock *sk = &vsk->sk; | ||
715 | bool remove_sock = true; | ||
716 | |||
717 | lock_sock(sk); | ||
718 | if (sk->sk_type == SOCK_STREAM) | ||
719 | remove_sock = virtio_transport_close(vsk); | ||
720 | release_sock(sk); | ||
721 | |||
722 | if (remove_sock) | ||
723 | vsock_remove_sock(vsk); | ||
724 | } | ||
725 | EXPORT_SYMBOL_GPL(virtio_transport_release); | ||
726 | |||
727 | static int | ||
728 | virtio_transport_recv_connecting(struct sock *sk, | ||
729 | struct virtio_vsock_pkt *pkt) | ||
730 | { | ||
731 | struct vsock_sock *vsk = vsock_sk(sk); | ||
732 | int err; | ||
733 | int skerr; | ||
734 | |||
735 | switch (le16_to_cpu(pkt->hdr.op)) { | ||
736 | case VIRTIO_VSOCK_OP_RESPONSE: | ||
737 | sk->sk_state = SS_CONNECTED; | ||
738 | sk->sk_socket->state = SS_CONNECTED; | ||
739 | vsock_insert_connected(vsk); | ||
740 | sk->sk_state_change(sk); | ||
741 | break; | ||
742 | case VIRTIO_VSOCK_OP_INVALID: | ||
743 | break; | ||
744 | case VIRTIO_VSOCK_OP_RST: | ||
745 | skerr = ECONNRESET; | ||
746 | err = 0; | ||
747 | goto destroy; | ||
748 | default: | ||
749 | skerr = EPROTO; | ||
750 | err = -EINVAL; | ||
751 | goto destroy; | ||
752 | } | ||
753 | return 0; | ||
754 | |||
755 | destroy: | ||
756 | virtio_transport_reset(vsk, pkt); | ||
757 | sk->sk_state = SS_UNCONNECTED; | ||
758 | sk->sk_err = skerr; | ||
759 | sk->sk_error_report(sk); | ||
760 | return err; | ||
761 | } | ||
762 | |||
763 | static int | ||
764 | virtio_transport_recv_connected(struct sock *sk, | ||
765 | struct virtio_vsock_pkt *pkt) | ||
766 | { | ||
767 | struct vsock_sock *vsk = vsock_sk(sk); | ||
768 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
769 | int err = 0; | ||
770 | |||
771 | switch (le16_to_cpu(pkt->hdr.op)) { | ||
772 | case VIRTIO_VSOCK_OP_RW: | ||
773 | pkt->len = le32_to_cpu(pkt->hdr.len); | ||
774 | pkt->off = 0; | ||
775 | |||
776 | spin_lock_bh(&vvs->rx_lock); | ||
777 | virtio_transport_inc_rx_pkt(vvs, pkt); | ||
778 | list_add_tail(&pkt->list, &vvs->rx_queue); | ||
779 | spin_unlock_bh(&vvs->rx_lock); | ||
780 | |||
781 | sk->sk_data_ready(sk); | ||
782 | return err; | ||
783 | case VIRTIO_VSOCK_OP_CREDIT_UPDATE: | ||
784 | sk->sk_write_space(sk); | ||
785 | break; | ||
786 | case VIRTIO_VSOCK_OP_SHUTDOWN: | ||
787 | if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) | ||
788 | vsk->peer_shutdown |= RCV_SHUTDOWN; | ||
789 | if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) | ||
790 | vsk->peer_shutdown |= SEND_SHUTDOWN; | ||
791 | if (vsk->peer_shutdown == SHUTDOWN_MASK && | ||
792 | vsock_stream_has_data(vsk) <= 0) | ||
793 | sk->sk_state = SS_DISCONNECTING; | ||
794 | if (le32_to_cpu(pkt->hdr.flags)) | ||
795 | sk->sk_state_change(sk); | ||
796 | break; | ||
797 | case VIRTIO_VSOCK_OP_RST: | ||
798 | virtio_transport_do_close(vsk, true); | ||
799 | break; | ||
800 | default: | ||
801 | err = -EINVAL; | ||
802 | break; | ||
803 | } | ||
804 | |||
805 | virtio_transport_free_pkt(pkt); | ||
806 | return err; | ||
807 | } | ||
808 | |||
809 | static void | ||
810 | virtio_transport_recv_disconnecting(struct sock *sk, | ||
811 | struct virtio_vsock_pkt *pkt) | ||
812 | { | ||
813 | struct vsock_sock *vsk = vsock_sk(sk); | ||
814 | |||
815 | if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) | ||
816 | virtio_transport_do_close(vsk, true); | ||
817 | } | ||
818 | |||
819 | static int | ||
820 | virtio_transport_send_response(struct vsock_sock *vsk, | ||
821 | struct virtio_vsock_pkt *pkt) | ||
822 | { | ||
823 | struct virtio_vsock_pkt_info info = { | ||
824 | .op = VIRTIO_VSOCK_OP_RESPONSE, | ||
825 | .type = VIRTIO_VSOCK_TYPE_STREAM, | ||
826 | .remote_cid = le32_to_cpu(pkt->hdr.src_cid), | ||
827 | .remote_port = le32_to_cpu(pkt->hdr.src_port), | ||
828 | .reply = true, | ||
829 | }; | ||
830 | |||
831 | return virtio_transport_send_pkt_info(vsk, &info); | ||
832 | } | ||
833 | |||
834 | /* Handle server socket */ | ||
835 | static int | ||
836 | virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt) | ||
837 | { | ||
838 | struct vsock_sock *vsk = vsock_sk(sk); | ||
839 | struct vsock_sock *vchild; | ||
840 | struct sock *child; | ||
841 | |||
842 | if (le16_to_cpu(pkt->hdr.op) != VIRTIO_VSOCK_OP_REQUEST) { | ||
843 | virtio_transport_reset(vsk, pkt); | ||
844 | return -EINVAL; | ||
845 | } | ||
846 | |||
847 | if (sk_acceptq_is_full(sk)) { | ||
848 | virtio_transport_reset(vsk, pkt); | ||
849 | return -ENOMEM; | ||
850 | } | ||
851 | |||
852 | child = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL, | ||
853 | sk->sk_type, 0); | ||
854 | if (!child) { | ||
855 | virtio_transport_reset(vsk, pkt); | ||
856 | return -ENOMEM; | ||
857 | } | ||
858 | |||
859 | sk->sk_ack_backlog++; | ||
860 | |||
861 | lock_sock_nested(child, SINGLE_DEPTH_NESTING); | ||
862 | |||
863 | child->sk_state = SS_CONNECTED; | ||
864 | |||
865 | vchild = vsock_sk(child); | ||
866 | vsock_addr_init(&vchild->local_addr, le32_to_cpu(pkt->hdr.dst_cid), | ||
867 | le32_to_cpu(pkt->hdr.dst_port)); | ||
868 | vsock_addr_init(&vchild->remote_addr, le32_to_cpu(pkt->hdr.src_cid), | ||
869 | le32_to_cpu(pkt->hdr.src_port)); | ||
870 | |||
871 | vsock_insert_connected(vchild); | ||
872 | vsock_enqueue_accept(sk, child); | ||
873 | virtio_transport_send_response(vchild, pkt); | ||
874 | |||
875 | release_sock(child); | ||
876 | |||
877 | sk->sk_data_ready(sk); | ||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static bool virtio_transport_space_update(struct sock *sk, | ||
882 | struct virtio_vsock_pkt *pkt) | ||
883 | { | ||
884 | struct vsock_sock *vsk = vsock_sk(sk); | ||
885 | struct virtio_vsock_sock *vvs = vsk->trans; | ||
886 | bool space_available; | ||
887 | |||
888 | /* buf_alloc and fwd_cnt is always included in the hdr */ | ||
889 | spin_lock_bh(&vvs->tx_lock); | ||
890 | vvs->peer_buf_alloc = le32_to_cpu(pkt->hdr.buf_alloc); | ||
891 | vvs->peer_fwd_cnt = le32_to_cpu(pkt->hdr.fwd_cnt); | ||
892 | space_available = virtio_transport_has_space(vsk); | ||
893 | spin_unlock_bh(&vvs->tx_lock); | ||
894 | return space_available; | ||
895 | } | ||
896 | |||
897 | /* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex | ||
898 | * lock. | ||
899 | */ | ||
900 | void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) | ||
901 | { | ||
902 | struct sockaddr_vm src, dst; | ||
903 | struct vsock_sock *vsk; | ||
904 | struct sock *sk; | ||
905 | bool space_available; | ||
906 | |||
907 | vsock_addr_init(&src, le32_to_cpu(pkt->hdr.src_cid), | ||
908 | le32_to_cpu(pkt->hdr.src_port)); | ||
909 | vsock_addr_init(&dst, le32_to_cpu(pkt->hdr.dst_cid), | ||
910 | le32_to_cpu(pkt->hdr.dst_port)); | ||
911 | |||
912 | trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port, | ||
913 | dst.svm_cid, dst.svm_port, | ||
914 | le32_to_cpu(pkt->hdr.len), | ||
915 | le16_to_cpu(pkt->hdr.type), | ||
916 | le16_to_cpu(pkt->hdr.op), | ||
917 | le32_to_cpu(pkt->hdr.flags), | ||
918 | le32_to_cpu(pkt->hdr.buf_alloc), | ||
919 | le32_to_cpu(pkt->hdr.fwd_cnt)); | ||
920 | |||
921 | if (le16_to_cpu(pkt->hdr.type) != VIRTIO_VSOCK_TYPE_STREAM) { | ||
922 | (void)virtio_transport_reset_no_sock(pkt); | ||
923 | goto free_pkt; | ||
924 | } | ||
925 | |||
926 | /* The socket must be in connected or bound table | ||
927 | * otherwise send reset back | ||
928 | */ | ||
929 | sk = vsock_find_connected_socket(&src, &dst); | ||
930 | if (!sk) { | ||
931 | sk = vsock_find_bound_socket(&dst); | ||
932 | if (!sk) { | ||
933 | (void)virtio_transport_reset_no_sock(pkt); | ||
934 | goto free_pkt; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | vsk = vsock_sk(sk); | ||
939 | |||
940 | space_available = virtio_transport_space_update(sk, pkt); | ||
941 | |||
942 | lock_sock(sk); | ||
943 | |||
944 | /* Update CID in case it has changed after a transport reset event */ | ||
945 | vsk->local_addr.svm_cid = dst.svm_cid; | ||
946 | |||
947 | if (space_available) | ||
948 | sk->sk_write_space(sk); | ||
949 | |||
950 | switch (sk->sk_state) { | ||
951 | case VSOCK_SS_LISTEN: | ||
952 | virtio_transport_recv_listen(sk, pkt); | ||
953 | virtio_transport_free_pkt(pkt); | ||
954 | break; | ||
955 | case SS_CONNECTING: | ||
956 | virtio_transport_recv_connecting(sk, pkt); | ||
957 | virtio_transport_free_pkt(pkt); | ||
958 | break; | ||
959 | case SS_CONNECTED: | ||
960 | virtio_transport_recv_connected(sk, pkt); | ||
961 | break; | ||
962 | case SS_DISCONNECTING: | ||
963 | virtio_transport_recv_disconnecting(sk, pkt); | ||
964 | virtio_transport_free_pkt(pkt); | ||
965 | break; | ||
966 | default: | ||
967 | virtio_transport_free_pkt(pkt); | ||
968 | break; | ||
969 | } | ||
970 | release_sock(sk); | ||
971 | |||
972 | /* Release refcnt obtained when we fetched this socket out of the | ||
973 | * bound or connected list. | ||
974 | */ | ||
975 | sock_put(sk); | ||
976 | return; | ||
977 | |||
978 | free_pkt: | ||
979 | virtio_transport_free_pkt(pkt); | ||
980 | } | ||
981 | EXPORT_SYMBOL_GPL(virtio_transport_recv_pkt); | ||
982 | |||
983 | void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt) | ||
984 | { | ||
985 | kfree(pkt->buf); | ||
986 | kfree(pkt); | ||
987 | } | ||
988 | EXPORT_SYMBOL_GPL(virtio_transport_free_pkt); | ||
989 | |||
990 | MODULE_LICENSE("GPL v2"); | ||
991 | MODULE_AUTHOR("Asias He"); | ||
992 | MODULE_DESCRIPTION("common code for virtio vsock"); | ||