/* For recv, we use the VMBus in-place packet iterator APIs to directly copy *datafromtheringbufferintotheuserspacebuffer.
*/ struct hvs_recv_buf { /* The header before the payload data */ struct vmpipe_proto_header hdr;
/* The payload */
u8 data[HVS_MTU_SIZE];
};
/* We can send up to HVS_MTU_SIZE bytes of payload to the host, but let's use *asmallersize,i.e.HVS_SEND_BUF_SIZE,tomaximizeconcurrencybetweenthe *guestandthehostprocessingasoneVMBUSpacketisthesmallestprocessing *unit. * *Note:thebuffercanbeeliminatedinthefuturewhenweaddnewVMBus *ringbufferAPIsthatallowustodirectlycopydatafromuserspacebuffer *toVMBusringbuffer.
*/ #define HVS_SEND_BUF_SIZE \
(HV_HYP_PAGE_SIZE - sizeof(struct vmpipe_proto_header))
struct hvs_send_buf { /* The header before the payload data */ struct vmpipe_proto_header hdr;
if (readable > HVS_PKT_LEN(0)) { /* At least we have 1 byte to read. We don't need to return *theexactreadablebytes:seevsock_stream_recvmsg()-> *vsock_stream_has_data().
*/ return1;
}
if (readable == HVS_PKT_LEN(0)) { /* 0-size payload means FIN */ return0;
}
/* The ringbuffer mustn't be 100% full, and we should reserve a *zero-length-payloadpacketfortheFIN:seehv_ringbuffer_write() *andhvs_shutdown().
*/ if (writeable <= HVS_PKT_LEN(1) + HVS_PKT_LEN(0)) return0;
ret = writeable - HVS_PKT_LEN(1) - HVS_PKT_LEN(0);
/* Remote peer is always the host */
vsock_addr_init(&vnew->remote_addr,
VMADDR_CID_HOST, VMADDR_PORT_ANY);
vnew->remote_addr.svm_port = get_port_by_srv_id(if_instance);
ret = vsock_assign_transport(vnew, vsock_sk(sk)); /* Transport assigned (looking at remote_addr) must be the *samewherewereceivedtherequest.
*/ if (ret || !hvs_check_transport(vnew)) {
sock_put(new); goto out;
}
hvs_new = vnew->trans;
hvs_new->chan = chan;
} else {
hvs = vsock_sk(sk)->trans;
hvs->chan = chan;
}
set_channel_read_mode(chan, HV_CALL_DIRECT);
/* Use the socket buffer sizes as hints for the VMBUS ring size. For *serversidesockets,'sk'istheparentsocketandthus,thiswill *allowthechildsocketstoinheritthesizefromtheparent.Keep *theminstothedefaultvalueandaligntopagesizeasperVMBUS *requirements. *Forthemax,thesocketcorelibrarywilllimitthesocketbuffer *sizethatcanbesetbytheuser,but,sincecurrently,thehv_sock *VMBUSringbufferisphysicallycontiguousallocation,restrictit *further. *Olderversionsofhv_sockhostsidecodecannothandlebiggerVMBUS *ringbuffersize.Usetheversionnumbertolimitthechangetonewer *versions.
*/ if (vmbus_proto_version < VERSION_WIN10_V5) {
sndbuf = RINGBUFFER_HVS_SND_SIZE;
rcvbuf = RINGBUFFER_HVS_RCV_SIZE;
} else {
sndbuf = max_t(int, sk->sk_sndbuf, RINGBUFFER_HVS_SND_SIZE);
sndbuf = min_t(int, sndbuf, RINGBUFFER_HVS_MAX_SIZE);
sndbuf = ALIGN(sndbuf, HV_HYP_PAGE_SIZE);
rcvbuf = max_t(int, sk->sk_rcvbuf, RINGBUFFER_HVS_RCV_SIZE);
rcvbuf = min_t(int, rcvbuf, RINGBUFFER_HVS_MAX_SIZE);
rcvbuf = ALIGN(rcvbuf, HV_HYP_PAGE_SIZE);
}
chan->max_pkt_size = HVS_MAX_PKT_SIZE;
ret = vmbus_open(chan, sndbuf, rcvbuf, NULL, 0, hvs_channel_cb,
conn_from_host ? new : sk); if (ret != 0) { if (conn_from_host) {
hvs_new->chan = NULL;
sock_put(new);
} else {
hvs->chan = NULL;
} goto out;
}
set_per_channel_state(chan, conn_from_host ? new : sk);
/* This reference will be dropped by hvs_close_connection(). */
sock_hold(conn_from_host ? new : sk);
vmbus_set_chn_rescind_callback(chan, hvs_close_connection);
/* Set the pending send size to max packet size to always get *notificationsfromthehostwhenthereisenoughwritablespace. *Thehostisoptimizedtosendnotificationsonlywhenthepending *sizeboundaryiscrossed,andnotalways.
*/
hvs_set_channel_pending_send_size(chan);
if (conn_from_host) { new->sk_state = TCP_ESTABLISHED;
sk_acceptq_added(sk);
/* Returns true, if it is safe to remove socket; false otherwise */ staticbool hvs_close_lock_held(struct vsock_sock *vsk)
{ struct sock *sk = sk_vsock(vsk);
if (!(sk->sk_state == TCP_ESTABLISHED ||
sk->sk_state == TCP_CLOSING)) returntrue;
if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
hvs_shutdown_lock_held(vsk->trans, SHUTDOWN_MASK);
if (sock_flag(sk, SOCK_DONE)) returntrue;
/* This reference will be dropped by the delayed close routine */
sock_hold(sk);
INIT_DELAYED_WORK(&vsk->close_work, hvs_close_timeout);
vsk->close_work_scheduled = true;
schedule_delayed_work(&vsk->close_work, HVS_CLOSE_TIMEOUT); returnfalse;
}
if (need_refill) {
hvs->recv_desc = hv_pkt_iter_first(hvs->chan); if (!hvs->recv_desc) return -ENOBUFS;
ret = hvs_update_recv_data(hvs); if (ret) return ret;
}
send_buf = kmalloc(sizeof(*send_buf), GFP_KERNEL); if (!send_buf) return -ENOMEM;
/* Reader(s) could be draining data from the channel as we write. *Maximizebandwidth,byiteratinguntilthechannelisfoundtobe *full.
*/ while (len) {
max_writable = hvs_channel_writable_bytes(chan); if (!max_writable) break;
to_write = min_t(ssize_t, len, max_writable);
to_write = min_t(ssize_t, to_write, HVS_SEND_BUF_SIZE); /* memcpy_from_msg is safe for loop as it advances the offsets *withinthemessageiterator.
*/
ret = memcpy_from_msg(send_buf->data, msg, to_write); if (ret < 0) goto out;
ret = hvs_send_data(hvs->chan, send_buf, to_write); if (ret < 0) goto out;
bytes_written += to_write;
len -= to_write;
}
out: /* If any data has been sent, return that */ if (bytes_written)
ret = bytes_written;
kfree(send_buf); return ret;
}
/* hv_sock connections can not persist across hibernation, and all the hv_sock *channelsareforcedtoberescindedbeforehibernation:see *vmbus_bus_suspend().Herethedummyhvs_suspend()andhvs_resume() *areonlyneededbecausehibernationrequiresthateveryvmbusdevice's *drivershouldhavea.suspendand.resumecallback:seevmbus_suspend().
*/ staticint hvs_suspend(struct hv_device *hv_dev)
{ /* Dummy */ return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.