From patchwork Sat Mar 28 06:37:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 455645 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 44F2E140140 for ; Sat, 28 Mar 2015 17:37:51 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="verification failed; unprotected key" header.d=gmail.com header.i=@gmail.com header.b=vke6fNCt; dkim-adsp=none (unprotected policy); dkim-atps=neutral Received: from localhost ([::1]:52926 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YbkNQ-0004iV-QZ for incoming@patchwork.ozlabs.org; Sat, 28 Mar 2015 02:37:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47827) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YbkNA-0004Ro-J2 for qemu-devel@nongnu.org; Sat, 28 Mar 2015 02:37:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YbkN6-0006S5-IL for qemu-devel@nongnu.org; Sat, 28 Mar 2015 02:37:32 -0400 Received: from mail-wg0-x236.google.com ([2a00:1450:400c:c00::236]:34816) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YbkN6-0006Rx-7y; Sat, 28 Mar 2015 02:37:28 -0400 Received: by wgdm6 with SMTP id m6so120103452wgd.2; Fri, 27 Mar 2015 23:37:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id; bh=5Jl/QtwfICtfjtEOZEwGSWD6H8DBbmo6uu8S4uapwt4=; b=vke6fNCt9yQCpcCG+Esm3dnjaZLIYY+is1w7/yTPxv2Lk39qLLFGZJVz53wFPl6e9F 2YHJE3OP/+Bk/9InG5awgbw6WylPxM3vBMQ4Ux/zcOB+RmDaBzWcOKeXRsDmwEkmevie h9HLFHpXTixFMgKebWQQe5Db3DMEa6JmFMZ0aVsw7AxutiVJXdjbF+B8/UWIU/yQC6Bk KFg+r+SkFwWONtPZzoinMXKxL0Pa0+wb8CbzZPP91GGQea84zmmHfG6EUMlGZNFYp2wz mf8DdmN9Oe9iDOOhS0E9MDQtELHrP1Ede8ZsYsxz6ELgpTKjiCMDMgKktf/8nxcmR2Rb aMTA== X-Received: by 10.194.176.4 with SMTP id ce4mr44487313wjc.75.1427524647574; Fri, 27 Mar 2015 23:37:27 -0700 (PDT) Received: from donizetti.station (net-93-66-123-41.cust.vodafonedsl.it. [93.66.123.41]) by mx.google.com with ESMTPSA id dx11sm5884791wjb.23.2015.03.27.23.37.25 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 27 Mar 2015 23:37:25 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Sat, 28 Mar 2015 07:37:18 +0100 Message-Id: <1427524638-28157-1-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 2.3.4 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c00::236 Cc: qemu-block@nongnu.org Subject: [Qemu-devel] [PATCH] block: avoid unnecessary bottom halves X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org bdrv_aio_* APIs can use coroutines to achieve asynchronicity. However, the coroutine may terminate without having yielded back to the caller (for example because of something that invokes a nested event loop, or because the coroutine is doing nothing at all). In this case, the bdrv_aio_* API must delay the completion to the next iteration of the main loop, because bdrv_aio_* will never invoke the callback before returning. This can be done with a bottom half, and indeed bdrv_aio_* is always using one for simplicity. It is possible to gain some performance (~3%) by avoiding this in the common case. A new field in the BlockAIOCBCoroutine struct is set to true until the first time the corotine has yielded to its creator, and completion goes through a new function bdrv_co_complete. If the flag is false, bdrv_co_complete invokes the callback immediately. If it is true, the caller will notice that the coroutine has completed and schedule the bottom half itself. Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi --- block.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/block.c b/block.c index 0fe97de..3fe0642 100644 --- a/block.c +++ b/block.c @@ -4789,6 +4789,7 @@ typedef struct BlockAIOCBCoroutine { BlockAIOCB common; BlockRequest req; bool is_write; + bool need_bh; bool *done; QEMUBH* bh; } BlockAIOCBCoroutine; @@ -4797,14 +4798,32 @@ static const AIOCBInfo bdrv_em_co_aiocb_info = { .aiocb_size = sizeof(BlockAIOCBCoroutine), }; +static void bdrv_co_complete(BlockAIOCBCoroutine *acb) +{ + if (!acb->need_bh) { + acb->common.cb(acb->common.opaque, acb->req.error); + qemu_aio_unref(acb); + } +} + static void bdrv_co_em_bh(void *opaque) { BlockAIOCBCoroutine *acb = opaque; - acb->common.cb(acb->common.opaque, acb->req.error); - + assert(!acb->need_bh); qemu_bh_delete(acb->bh); - qemu_aio_unref(acb); + bdrv_co_complete(acb); +} + +static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb) +{ + acb->need_bh = false; + if (acb->req.error != -EINPROGRESS) { + BlockDriverState *bs = acb->common.bs; + + acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); + qemu_bh_schedule(acb->bh); + } } /* Invoke bdrv_co_do_readv/bdrv_co_do_writev */ @@ -4821,8 +4840,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); - qemu_bh_schedule(acb->bh); + bdrv_co_complete(acb); } static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, @@ -4838,6 +4856,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, BlockAIOCBCoroutine *acb; acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); + acb->need_bh = true; + acb->req.error = -EINPROGRESS; acb->req.sector = sector_num; acb->req.nb_sectors = nb_sectors; acb->req.qiov = qiov; @@ -4847,6 +4867,7 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, co = qemu_coroutine_create(bdrv_co_do_rw); qemu_coroutine_enter(co, acb); + bdrv_co_maybe_schedule_bh(acb); return &acb->common; } @@ -4856,8 +4877,7 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque) BlockDriverState *bs = acb->common.bs; acb->req.error = bdrv_co_flush(bs); - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); - qemu_bh_schedule(acb->bh); + bdrv_co_complete(acb); } BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs, @@ -4869,10 +4889,13 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs, BlockAIOCBCoroutine *acb; acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); + acb->need_bh = true; + acb->req.error = -EINPROGRESS; co = qemu_coroutine_create(bdrv_aio_flush_co_entry); qemu_coroutine_enter(co, acb); + bdrv_co_maybe_schedule_bh(acb); return &acb->common; } @@ -4882,8 +4905,7 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) BlockDriverState *bs = acb->common.bs; acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors); - acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb); - qemu_bh_schedule(acb->bh); + bdrv_co_complete(acb); } BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs, @@ -4896,11 +4918,14 @@ BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs, trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque); acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque); + acb->need_bh = true; + acb->req.error = -EINPROGRESS; acb->req.sector = sector_num; acb->req.nb_sectors = nb_sectors; co = qemu_coroutine_create(bdrv_aio_discard_co_entry); qemu_coroutine_enter(co, acb); + bdrv_co_maybe_schedule_bh(acb); return &acb->common; }