From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1O3qAs-0001aL-UE for qemu-devel@nongnu.org; Mon, 19 Apr 2010 08:34:03 -0400 Received: from [140.186.70.92] (port=57363 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1O3qAo-0001Yp-87 for qemu-devel@nongnu.org; Mon, 19 Apr 2010 08:34:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1O3qAl-0000LX-Cv for qemu-devel@nongnu.org; Mon, 19 Apr 2010 08:33:57 -0400 Received: from mtagate3.uk.ibm.com ([194.196.100.163]:46191) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1O3qAl-0000L5-4d for qemu-devel@nongnu.org; Mon, 19 Apr 2010 08:33:55 -0400 Received: from d06nrmr1707.portsmouth.uk.ibm.com (d06nrmr1707.portsmouth.uk.ibm.com [9.149.39.225]) by mtagate3.uk.ibm.com (8.13.1/8.13.1) with ESMTP id o3JCXqOt018487 for ; Mon, 19 Apr 2010 12:33:52 GMT Received: from d06av04.portsmouth.uk.ibm.com (d06av04.portsmouth.uk.ibm.com [9.149.37.216]) by d06nrmr1707.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o3JCXqZV614540 for ; Mon, 19 Apr 2010 13:33:52 +0100 Received: from d06av04.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av04.portsmouth.uk.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id o3JCXpK3005625 for ; Mon, 19 Apr 2010 13:33:52 +0100 From: Stefan Hajnoczi Date: Mon, 19 Apr 2010 13:34:12 +0100 Message-Id: <1271680452-24121-2-git-send-email-stefanha@linux.vnet.ibm.com> In-Reply-To: <1271680452-24121-1-git-send-email-stefanha@linux.vnet.ibm.com> References: <1271680452-24121-1-git-send-email-stefanha@linux.vnet.ibm.com> Subject: [Qemu-devel] [PATCH 2/2] block: Cache total_sectors to reduce bdrv_getlength calls List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Jan Kiszka , Christoph Hellwig , Stefan Hajnoczi The BlockDriver bdrv_getlength function is called from the I/O code path when checking that the request falls within the device. Unfortunately this involves an lseek system call in the raw protocol; every read or write request will incur this lseek cost. Jan Kiszka identified this issue and its latency overhead. This patch caches device length in the existing total_sectors variable so lseek calls can be avoided for fixed size devices. Growable devices fall back to the full bdrv_getlength code path because I have not added logic to detect extending the size of the device in a write. Signed-off-by: Stefan Hajnoczi --- block.c | 28 ++++++++++++++++++++++------ 1 files changed, 22 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index def3400..d5a3ba7 100644 --- a/block.c +++ b/block.c @@ -363,6 +363,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename, assert(drv != NULL); bs->file = NULL; + bs->total_sectors = 0; bs->is_temporary = 0; bs->encrypted = 0; bs->valid_key = 0; @@ -416,9 +417,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename, } bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR); - if (drv->bdrv_getlength) { - bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; - } + bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; #ifndef _WIN32 if (bs->is_temporary) { unlink(filename); @@ -959,13 +958,26 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, int bdrv_truncate(BlockDriverState *bs, int64_t offset) { BlockDriver *drv = bs->drv; + int ret; if (!drv) return -ENOMEDIUM; if (!drv->bdrv_truncate) return -ENOTSUP; if (bs->read_only) return -EACCES; - return drv->bdrv_truncate(bs, offset); + ret = drv->bdrv_truncate(bs, offset); + if (ret < 0) { + return ret; + } + + /* refresh total sectors */ + if (drv->bdrv_getlength) { + bs->total_sectors = 0; /* discard cached value */ + bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; + } else { + bs->total_sectors = offset >> BDRV_SECTOR_BITS; + } + return ret; } /** @@ -976,8 +988,12 @@ int64_t bdrv_getlength(BlockDriverState *bs) BlockDriver *drv = bs->drv; if (!drv) return -ENOMEDIUM; - if (!drv->bdrv_getlength) { - /* legacy mode */ + + /* Fixed size devices use the total_sectors value for speed instead of + issuing a length query (like lseek) on each call. Also, legacy block + drivers don't provide a bdrv_getlength function and must use + total_sectors. */ + if ((bs->total_sectors && !bs->growable) || !drv->bdrv_getlength) { return bs->total_sectors * BDRV_SECTOR_SIZE; } return drv->bdrv_getlength(bs); -- 1.7.0