From patchwork Tue Nov 15 04:14:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Cody X-Patchwork-Id: 694835 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tHvXj41sdz9t26 for ; Tue, 15 Nov 2016 15:28:53 +1100 (AEDT) Received: from localhost ([::1]:44120 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c6VMY-0005RQ-RN for incoming@patchwork.ozlabs.org; Mon, 14 Nov 2016 23:28:50 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50778) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c6V9Y-0002Y2-BP for qemu-devel@nongnu.org; Mon, 14 Nov 2016 23:15:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1c6V9X-00007s-0K for qemu-devel@nongnu.org; Mon, 14 Nov 2016 23:15:24 -0500 Received: from mx1.redhat.com ([209.132.183.28]:33556) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1c6V9S-0008TX-Sy; Mon, 14 Nov 2016 23:15:19 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 36FED8051B; Tue, 15 Nov 2016 04:15:18 +0000 (UTC) Received: from localhost (ovpn-112-50.phx2.redhat.com [10.3.112.50]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uAF4FGSF015312 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 14 Nov 2016 23:15:17 -0500 From: Jeff Cody To: qemu-block@nongnu.org Date: Mon, 14 Nov 2016 23:14:50 -0500 Message-Id: <1479183291-14086-13-git-send-email-jcody@redhat.com> In-Reply-To: <1479183291-14086-1-git-send-email-jcody@redhat.com> References: <1479183291-14086-1-git-send-email-jcody@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 15 Nov 2016 04:15:18 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL for-2.8 12/13] block/curl: Do not wait for data beyond EOF X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, jcody@redhat.com, qemu-devel@nongnu.org, stefanha@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Max Reitz libcurl will only give us as much data as there is, not more. The block layer will deny requests beyond the end of file for us; but since this block driver is still using a sector-based interface, we can still get in trouble if the file size is not a multiple of 512. While we have already made sure not to attempt transfers beyond the end of the file, we are currently still trying to receive data from there if the original request exceeds the file size. This patch fixes this issue and invokes qemu_iovec_memset() on the iovec's tail. Cc: qemu-stable@nongnu.org Signed-off-by: Max Reitz Message-id: 20161025025431.24714-5-mreitz@redhat.com Signed-off-by: Jeff Cody --- block/curl.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/block/curl.c b/block/curl.c index 273f329..0404c1b 100644 --- a/block/curl.c +++ b/block/curl.c @@ -252,8 +252,17 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque) continue; if ((s->buf_off >= acb->end)) { + size_t request_length = acb->nb_sectors * BDRV_SECTOR_SIZE; + qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start, acb->end - acb->start); + + if (acb->end - acb->start < request_length) { + size_t offset = acb->end - acb->start; + qemu_iovec_memset(acb->qiov, offset, 0, + request_length - offset); + } + acb->common.cb(acb->common.opaque, 0); qemu_aio_unref(acb); s->acb[i] = NULL; @@ -270,6 +279,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len, { int i; size_t end = start + len; + size_t clamped_end = MIN(end, s->len); + size_t clamped_len = clamped_end - start; for (i=0; istates[i]; @@ -284,12 +295,15 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len, // Does the existing buffer cover our section? if ((start >= state->buf_start) && (start <= buf_end) && - (end >= state->buf_start) && - (end <= buf_end)) + (clamped_end >= state->buf_start) && + (clamped_end <= buf_end)) { char *buf = state->orig_buf + (start - state->buf_start); - qemu_iovec_from_buf(acb->qiov, 0, buf, len); + qemu_iovec_from_buf(acb->qiov, 0, buf, clamped_len); + if (clamped_len < len) { + qemu_iovec_memset(acb->qiov, clamped_len, 0, len - clamped_len); + } acb->common.cb(acb->common.opaque, 0); return FIND_RET_OK; @@ -299,13 +313,13 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len, if (state->in_use && (start >= state->buf_start) && (start <= buf_fend) && - (end >= state->buf_start) && - (end <= buf_fend)) + (clamped_end >= state->buf_start) && + (clamped_end <= buf_fend)) { int j; acb->start = start - state->buf_start; - acb->end = acb->start + len; + acb->end = acb->start + clamped_len; for (j=0; jacb[j]) { @@ -798,13 +812,13 @@ static void curl_readv_bh_cb(void *p) } acb->start = 0; - acb->end = (acb->nb_sectors * BDRV_SECTOR_SIZE); + acb->end = MIN(acb->nb_sectors * BDRV_SECTOR_SIZE, s->len - start); state->buf_off = 0; g_free(state->orig_buf); state->buf_start = start; - state->buf_len = acb->end + s->readahead_size; - end = MIN(start + state->buf_len, s->len) - 1; + state->buf_len = MIN(acb->end + s->readahead_size, s->len - start); + end = start + state->buf_len - 1; state->orig_buf = g_try_malloc(state->buf_len); if (state->buf_len && state->orig_buf == NULL) { curl_clean_state(state);