From patchwork Thu Dec 24 14:14:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dexuan Cui X-Patchwork-Id: 560928 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id AEC0A140C3B for ; Thu, 24 Dec 2015 23:42:46 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754090AbbLXMk1 (ORCPT ); Thu, 24 Dec 2015 07:40:27 -0500 Received: from p3plsmtps2ded03.prod.phx3.secureserver.net ([208.109.80.60]:38536 "EHLO p3plsmtps2ded03.prod.phx3.secureserver.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752403AbbLXMkX (ORCPT ); Thu, 24 Dec 2015 07:40:23 -0500 Received: from linuxonhyperv.com ([72.167.245.219]) by : HOSTING RELAY : with SMTP id C5BuaHovndpLfC5BuaYJS2; Thu, 24 Dec 2015 05:40:23 -0700 x-originating-ip: 72.167.245.219 Received: by linuxonhyperv.com (Postfix, from userid 518) id D306B190343; Thu, 24 Dec 2015 06:14:36 -0800 (PST) From: Dexuan Cui To: gregkh@linuxfoundation.org, davem@davemloft.net, stephen@networkplumber.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, driverdev-devel@linuxdriverproject.org, olaf@aepfle.de, apw@canonical.com, jasowang@redhat.com, kys@microsoft.com Cc: pebolle@tiscali.nl, stefanha@redhat.com, vkuznets@redhat.com, dan.carpenter@oracle.com Subject: [PATCH V5 4/9] Drivers: hv: ring_buffer: enhance hv_ringbuffer_read() to support hvsock Date: Thu, 24 Dec 2015 06:14:36 -0800 Message-Id: <1450966476-13175-1-git-send-email-decui@microsoft.com> X-Mailer: git-send-email 1.7.4.1 X-CMAE-Envelope: MS4wfKSnU8X8TnRh9N13F5d3UsnZwmYdnWk6wFoJfB2gCpojDp5YiomQ8xchTWoKGpgBFLEG7KIxk4fhocLJtRtVbCFi6NCbHkiml5fNKMpEBDS5U9U3hAKT xm+BAizGMG8ypvDc8L5EPTzTjbZbD7v2WcdLBj3sB7CPDW0ESxJak5ZlbOBKqSAU5lvIUCz/bdHFdwbbwGfnoqFFuSbuoVXW/YC/1l8camDf0uGy2MWVKKRI H6aZ4KtsgoX/5bdFEn3VqvKdixJ4EATOMMtIy5EaDBJutk7ZsqfXzqodJcBl2kt/simgtudUJvRtQiVDTKqwTphVb9Jxqfd5gSphHBsI7APMlH44UeTZMVBk QxIMmx78b9PfsnugAsKlk7yI5S9b98m83AvVgsfPK7f/b454SoTHCw168CDG6E7bEZ7B4C84XWMbS4UigKrnedoGIhEVQxyKU4s/C31OtDWLP0RR4/Uqz45d vLh9UNY6TWrlOOZhQG7tvc/9XtfXaPm8BfLyBjHu2SAQ8HlZNlw/wP0GhNovK14Z7DlaF1uW3LxyCIz5JQRFgClj5kArcc/hwaegft+iPi68dzRVPSYGHuDE XyV/X9750scjftFyFypl1Dd78oQSWUS+UfqgaeEVyb14NA== Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org To get the payload of hvsock, we need raw=0 to skip the level-1 header (i.e., struct vmpacket_descriptor desc) and we also need to skip the level-2 header (i.e., struct vmpipe_proto_header pipe_hdr). NB: if the length of the hvsock payload is not aligned with the 8-byte boundeary, at most 7 padding bytes are appended, so the real hvsock payload's length must be retrieved by the pipe_hdr.data_size field. I 'upgrade' the 'raw' parameter of hv_ringbuffer_read() to a 'read_flags', trying to share the logic of the function. This patch is required by the next patch, which will introduce the hvsock send/recv APIs. Signed-off-by: Dexuan Cui Cc: Vitaly Kuznetsov --- drivers/hv/channel.c | 10 +++++---- drivers/hv/hyperv_vmbus.h | 13 +++++++++++- drivers/hv/ring_buffer.c | 54 ++++++++++++++++++++++++++++++++++++----------- include/linux/hyperv.h | 12 +++++++++++ 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index eaaa066..cc49966 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -940,13 +940,14 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer); static inline int __vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u32 *buffer_actual_len, u64 *requestid, - bool raw) + u32 read_flags) { int ret; bool signal = false; ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen, - buffer_actual_len, requestid, &signal, raw); + buffer_actual_len, requestid, &signal, + read_flags); if (signal) vmbus_setevent(channel); @@ -959,7 +960,7 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, u64 *requestid) { return __vmbus_recvpacket(channel, buffer, bufferlen, - buffer_actual_len, requestid, false); + buffer_actual_len, requestid, 0); } EXPORT_SYMBOL(vmbus_recvpacket); @@ -971,6 +972,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, u64 *requestid) { return __vmbus_recvpacket(channel, buffer, bufferlen, - buffer_actual_len, requestid, true); + buffer_actual_len, requestid, + HV_RINGBUFFER_READ_FLAG_RAW); } EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 0411b7b..46206b6 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -619,9 +619,20 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, struct kvec *kv_list, u32 kv_count, bool *signal); +/* + * By default, a read_flags of 0 means: the payload offset is + * sizeof(struct vmpacket_descriptor). + * + * If HV_RINGBUFFER_READ_FLAG_RAW is used, the payload offset is 0. + * + * If HV_RINGBUFFER_READ_FLAG_HVSOCK is used, the payload offset is + * sizeof(struct vmpacket_descriptor) + sizeof(struct vmpipe_proto_header). + */ +#define HV_RINGBUFFER_READ_FLAG_RAW (1 << 0) +#define HV_RINGBUFFER_READ_FLAG_HVSOCK (1 << 1) int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 *buffer_actual_len, - u64 *requestid, bool *signal, bool raw); + u64 *requestid, bool *signal, u32 read_flags); void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index b53702c..03a509c 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -382,32 +382,43 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 *buffer_actual_len, - u64 *requestid, bool *signal, bool raw) + u64 *requestid, bool *signal, u32 read_flags) { + bool raw = !!(read_flags & HV_RINGBUFFER_READ_FLAG_RAW); + bool hvsock = !!(read_flags & HV_RINGBUFFER_READ_FLAG_HVSOCK); + u32 bytes_avail_towrite; u32 bytes_avail_toread; u32 next_read_location = 0; u64 prev_indices = 0; unsigned long flags; - struct vmpacket_descriptor desc; + struct vmpipe_proto_header *pipe_hdr; + struct vmpacket_descriptor *desc; u32 offset; - u32 packetlen; + u32 packetlen, tot_hdrlen; int ret = 0; if (buflen <= 0) return -EINVAL; + tot_hdrlen = sizeof(*desc); + if (hvsock) + tot_hdrlen += sizeof(*pipe_hdr); + spin_lock_irqsave(&inring_info->ring_lock, flags); *buffer_actual_len = 0; - *requestid = 0; + + /* If some driver doesn't need the info, a NULL is passed in. */ + if (requestid) + *requestid = 0; hv_get_ringbuffer_availbytes(inring_info, &bytes_avail_toread, &bytes_avail_towrite); /* Make sure there is something to read */ - if (bytes_avail_toread < sizeof(desc)) { + if (bytes_avail_toread < tot_hdrlen) { /* * No error is set when there is even no header, drivers are * supposed to analyze buffer_actual_len. @@ -415,17 +426,26 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, goto out_unlock; } + if (tot_hdrlen > buflen) { + ret = -ENOBUFS; + goto out_unlock; + } + + desc = (struct vmpacket_descriptor *)buffer; + next_read_location = hv_get_next_read_location(inring_info); - next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, - sizeof(desc), + next_read_location = hv_copyfrom_ringbuffer(inring_info, desc, + tot_hdrlen, next_read_location); + offset = 0; + if (!raw) + offset += (desc->offset8 << 3); + if (hvsock) + offset += sizeof(*pipe_hdr); - offset = raw ? 0 : (desc.offset8 << 3); - packetlen = (desc.len8 << 3) - offset; - *buffer_actual_len = packetlen; - *requestid = desc.trans_id; + packetlen = (desc->len8 << 3) - offset; - if (bytes_avail_toread < packetlen + offset) { + if (bytes_avail_toread < (desc->len8 << 3)) { ret = -EAGAIN; goto out_unlock; } @@ -435,6 +455,16 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, goto out_unlock; } + if (requestid) + *requestid = desc->trans_id; + + if (!hvsock) + *buffer_actual_len = packetlen; + else { + pipe_hdr = (struct vmpipe_proto_header *)(desc + 1); + *buffer_actual_len = pipe_hdr->data_size; + } + next_read_location = hv_get_next_readlocation_withoffset(inring_info, offset); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index b835d80..e005223 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1268,4 +1268,16 @@ extern __u32 vmbus_proto_version; int vmbus_send_tl_connect_request(const uuid_le *shv_guest_servie_id, const uuid_le *shv_host_servie_id); +struct vmpipe_proto_header { + u32 pkt_type; + + union { + u32 data_size; + struct { + u16 data_size; + u16 offset; + } partial; + }; +} __packed; + #endif /* _HYPERV_H */