2 * VMware vSockets Driver
4 * Copyright (C) 2009-2013 VMware, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation version 2 and no later version.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 #include <linux/types.h>
17 #include <linux/socket.h>
18 #include <linux/stddef.h>
21 #include "vmci_transport_notify.h"
23 #define PKT_FIELD(vsk, field_name) \
24 (vmci_trans(vsk)->notify.pkt_q_state.field_name)
26 static bool vmci_transport_notify_waiting_write(struct vsock_sock
*vsk
)
31 if (!PKT_FIELD(vsk
, peer_waiting_write
))
34 /* When the sender blocks, we take that as a sign that the sender is
35 * faster than the receiver. To reduce the transmit rate of the sender,
36 * we delay the sending of the read notification by decreasing the
37 * write_notify_window. The notification is delayed until the number of
38 * bytes used in the queue drops below the write_notify_window.
41 if (!PKT_FIELD(vsk
, peer_waiting_write_detected
)) {
42 PKT_FIELD(vsk
, peer_waiting_write_detected
) = true;
43 if (PKT_FIELD(vsk
, write_notify_window
) < PAGE_SIZE
) {
44 PKT_FIELD(vsk
, write_notify_window
) =
45 PKT_FIELD(vsk
, write_notify_min_window
);
47 PKT_FIELD(vsk
, write_notify_window
) -= PAGE_SIZE
;
48 if (PKT_FIELD(vsk
, write_notify_window
) <
49 PKT_FIELD(vsk
, write_notify_min_window
))
50 PKT_FIELD(vsk
, write_notify_window
) =
51 PKT_FIELD(vsk
, write_notify_min_window
);
55 notify_limit
= vmci_trans(vsk
)->consume_size
-
56 PKT_FIELD(vsk
, write_notify_window
);
58 /* The notify_limit is used to delay notifications in the case where
59 * flow control is enabled. Below the test is expressed in terms of
60 * free space in the queue: if free_space > ConsumeSize -
61 * write_notify_window then notify An alternate way of expressing this
62 * is to rewrite the expression to use the data ready in the receive
63 * queue: if write_notify_window > bufferReady then notify as
64 * free_space == ConsumeSize - bufferReady.
67 retval
= vmci_qpair_consume_free_space(vmci_trans(vsk
)->qpair
) >
71 /* Once we notify the peer, we reset the detected flag so the
72 * next wait will again cause a decrease in the window size.
75 PKT_FIELD(vsk
, peer_waiting_write_detected
) = false;
81 vmci_transport_handle_read(struct sock
*sk
,
82 struct vmci_transport_packet
*pkt
,
84 struct sockaddr_vm
*dst
, struct sockaddr_vm
*src
)
86 sk
->sk_write_space(sk
);
90 vmci_transport_handle_wrote(struct sock
*sk
,
91 struct vmci_transport_packet
*pkt
,
93 struct sockaddr_vm
*dst
, struct sockaddr_vm
*src
)
95 sk
->sk_data_ready(sk
, 0);
98 static void vsock_block_update_write_window(struct sock
*sk
)
100 struct vsock_sock
*vsk
= vsock_sk(sk
);
102 if (PKT_FIELD(vsk
, write_notify_window
) < vmci_trans(vsk
)->consume_size
)
103 PKT_FIELD(vsk
, write_notify_window
) =
104 min(PKT_FIELD(vsk
, write_notify_window
) + PAGE_SIZE
,
105 vmci_trans(vsk
)->consume_size
);
108 static int vmci_transport_send_read_notification(struct sock
*sk
)
110 struct vsock_sock
*vsk
;
112 unsigned int retries
;
120 if (vmci_transport_notify_waiting_write(vsk
)) {
121 /* Notify the peer that we have read, retrying the send on
122 * failure up to our maximum value. XXX For now we just log
123 * the failure, but later we should schedule a work item to
124 * handle the resend until it succeeds. That would require
125 * keeping track of work items in the vsk and cleaning them up
128 while (!(vsk
->peer_shutdown
& RCV_SHUTDOWN
) &&
130 retries
< VMCI_TRANSPORT_MAX_DGRAM_RESENDS
) {
131 err
= vmci_transport_send_read(sk
);
138 if (retries
>= VMCI_TRANSPORT_MAX_DGRAM_RESENDS
&& !sent_read
)
139 pr_err("%p unable to send read notification to peer\n",
142 PKT_FIELD(vsk
, peer_waiting_write
) = false;
148 static void vmci_transport_notify_pkt_socket_init(struct sock
*sk
)
150 struct vsock_sock
*vsk
= vsock_sk(sk
);
152 PKT_FIELD(vsk
, write_notify_window
) = PAGE_SIZE
;
153 PKT_FIELD(vsk
, write_notify_min_window
) = PAGE_SIZE
;
154 PKT_FIELD(vsk
, peer_waiting_write
) = false;
155 PKT_FIELD(vsk
, peer_waiting_write_detected
) = false;
158 static void vmci_transport_notify_pkt_socket_destruct(struct vsock_sock
*vsk
)
160 PKT_FIELD(vsk
, write_notify_window
) = PAGE_SIZE
;
161 PKT_FIELD(vsk
, write_notify_min_window
) = PAGE_SIZE
;
162 PKT_FIELD(vsk
, peer_waiting_write
) = false;
163 PKT_FIELD(vsk
, peer_waiting_write_detected
) = false;
167 vmci_transport_notify_pkt_poll_in(struct sock
*sk
,
168 size_t target
, bool *data_ready_now
)
170 struct vsock_sock
*vsk
= vsock_sk(sk
);
172 if (vsock_stream_has_data(vsk
)) {
173 *data_ready_now
= true;
175 /* We can't read right now because there is nothing in the
176 * queue. Ask for notifications when there is something to
179 if (sk
->sk_state
== SS_CONNECTED
)
180 vsock_block_update_write_window(sk
);
181 *data_ready_now
= false;
188 vmci_transport_notify_pkt_poll_out(struct sock
*sk
,
189 size_t target
, bool *space_avail_now
)
191 s64 produce_q_free_space
;
192 struct vsock_sock
*vsk
= vsock_sk(sk
);
194 produce_q_free_space
= vsock_stream_has_space(vsk
);
195 if (produce_q_free_space
> 0) {
196 *space_avail_now
= true;
198 } else if (produce_q_free_space
== 0) {
199 /* This is a connected socket but we can't currently send data.
200 * Nothing else to do.
202 *space_avail_now
= false;
209 vmci_transport_notify_pkt_recv_init(
212 struct vmci_transport_recv_notify_data
*data
)
214 struct vsock_sock
*vsk
= vsock_sk(sk
);
216 data
->consume_head
= 0;
217 data
->produce_tail
= 0;
218 data
->notify_on_block
= false;
220 if (PKT_FIELD(vsk
, write_notify_min_window
) < target
+ 1) {
221 PKT_FIELD(vsk
, write_notify_min_window
) = target
+ 1;
222 if (PKT_FIELD(vsk
, write_notify_window
) <
223 PKT_FIELD(vsk
, write_notify_min_window
)) {
224 /* If the current window is smaller than the new
225 * minimal window size, we need to reevaluate whether
226 * we need to notify the sender. If the number of ready
227 * bytes are smaller than the new window, we need to
228 * send a notification to the sender before we block.
231 PKT_FIELD(vsk
, write_notify_window
) =
232 PKT_FIELD(vsk
, write_notify_min_window
);
233 data
->notify_on_block
= true;
241 vmci_transport_notify_pkt_recv_pre_block(
244 struct vmci_transport_recv_notify_data
*data
)
248 vsock_block_update_write_window(sk
);
250 if (data
->notify_on_block
) {
251 err
= vmci_transport_send_read_notification(sk
);
254 data
->notify_on_block
= false;
261 vmci_transport_notify_pkt_recv_post_dequeue(
266 struct vmci_transport_recv_notify_data
*data
)
268 struct vsock_sock
*vsk
;
270 bool was_full
= false;
280 vmci_qpair_consume_free_space(vmci_trans(vsk
)->qpair
);
281 was_full
= free_space
== copied
;
284 PKT_FIELD(vsk
, peer_waiting_write
) = true;
286 err
= vmci_transport_send_read_notification(sk
);
290 /* See the comment in
291 * vmci_transport_notify_pkt_send_post_enqueue().
293 sk
->sk_data_ready(sk
, 0);
300 vmci_transport_notify_pkt_send_init(
302 struct vmci_transport_send_notify_data
*data
)
304 data
->consume_head
= 0;
305 data
->produce_tail
= 0;
311 vmci_transport_notify_pkt_send_post_enqueue(
314 struct vmci_transport_send_notify_data
*data
)
317 struct vsock_sock
*vsk
;
318 bool sent_wrote
= false;
327 vmci_qpair_produce_buf_ready(vmci_trans(vsk
)->qpair
) == written
;
329 while (!(vsk
->peer_shutdown
& RCV_SHUTDOWN
) &&
331 retries
< VMCI_TRANSPORT_MAX_DGRAM_RESENDS
) {
332 err
= vmci_transport_send_wrote(sk
);
340 if (retries
>= VMCI_TRANSPORT_MAX_DGRAM_RESENDS
&& !sent_wrote
) {
341 pr_err("%p unable to send wrote notification to peer\n",
350 vmci_transport_notify_pkt_handle_pkt(
352 struct vmci_transport_packet
*pkt
,
354 struct sockaddr_vm
*dst
,
355 struct sockaddr_vm
*src
, bool *pkt_processed
)
357 bool processed
= false;
360 case VMCI_TRANSPORT_PACKET_TYPE_WROTE
:
361 vmci_transport_handle_wrote(sk
, pkt
, bottom_half
, dst
, src
);
364 case VMCI_TRANSPORT_PACKET_TYPE_READ
:
365 vmci_transport_handle_read(sk
, pkt
, bottom_half
, dst
, src
);
371 *pkt_processed
= processed
;
374 static void vmci_transport_notify_pkt_process_request(struct sock
*sk
)
376 struct vsock_sock
*vsk
= vsock_sk(sk
);
378 PKT_FIELD(vsk
, write_notify_window
) = vmci_trans(vsk
)->consume_size
;
379 if (vmci_trans(vsk
)->consume_size
<
380 PKT_FIELD(vsk
, write_notify_min_window
))
381 PKT_FIELD(vsk
, write_notify_min_window
) =
382 vmci_trans(vsk
)->consume_size
;
385 static void vmci_transport_notify_pkt_process_negotiate(struct sock
*sk
)
387 struct vsock_sock
*vsk
= vsock_sk(sk
);
389 PKT_FIELD(vsk
, write_notify_window
) = vmci_trans(vsk
)->consume_size
;
390 if (vmci_trans(vsk
)->consume_size
<
391 PKT_FIELD(vsk
, write_notify_min_window
))
392 PKT_FIELD(vsk
, write_notify_min_window
) =
393 vmci_trans(vsk
)->consume_size
;
397 vmci_transport_notify_pkt_recv_pre_dequeue(
400 struct vmci_transport_recv_notify_data
*data
)
402 return 0; /* NOP for QState. */
406 vmci_transport_notify_pkt_send_pre_block(
408 struct vmci_transport_send_notify_data
*data
)
410 return 0; /* NOP for QState. */
414 vmci_transport_notify_pkt_send_pre_enqueue(
416 struct vmci_transport_send_notify_data
*data
)
418 return 0; /* NOP for QState. */
421 /* Socket always on control packet based operations. */
422 struct vmci_transport_notify_ops vmci_transport_notify_pkt_q_state_ops
= {
423 vmci_transport_notify_pkt_socket_init
,
424 vmci_transport_notify_pkt_socket_destruct
,
425 vmci_transport_notify_pkt_poll_in
,
426 vmci_transport_notify_pkt_poll_out
,
427 vmci_transport_notify_pkt_handle_pkt
,
428 vmci_transport_notify_pkt_recv_init
,
429 vmci_transport_notify_pkt_recv_pre_block
,
430 vmci_transport_notify_pkt_recv_pre_dequeue
,
431 vmci_transport_notify_pkt_recv_post_dequeue
,
432 vmci_transport_notify_pkt_send_init
,
433 vmci_transport_notify_pkt_send_pre_block
,
434 vmci_transport_notify_pkt_send_pre_enqueue
,
435 vmci_transport_notify_pkt_send_post_enqueue
,
436 vmci_transport_notify_pkt_process_request
,
437 vmci_transport_notify_pkt_process_negotiate
,