* [Qemu-devel] [PATCH v2] block: Cache total_sectors to reduce bdrv_getlength calls
@ 2010-04-19 15:56 Stefan Hajnoczi
2010-04-20 8:35 ` [Qemu-devel] " Kevin Wolf
0 siblings, 1 reply; 2+ messages in thread
From: Stefan Hajnoczi @ 2010-04-19 15:56 UTC (permalink / raw)
To: qemu-devel; +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 <jan.kiszka@siemens.com> 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 <stefanha@linux.vnet.ibm.com>
---
v2:
- Introduced refresh_total_sectors() to clean up total_sectors updates
- Added error handling for refresh_total_sectors() callers
block.c | 43 ++++++++++++++++++++++++++++++++++++++-----
1 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/block.c b/block.c
index def3400..31e42c2 100644
--- a/block.c
+++ b/block.c
@@ -352,6 +352,26 @@ static BlockDriver *find_image_format(const char *filename)
return drv;
}
+/**
+ * Set the current 'total_sectors' value
+ */
+static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
+{
+ BlockDriver *drv = bs->drv;
+
+ /* query actual device if possible, otherwise just trust the hint */
+ if (drv->bdrv_getlength) {
+ int64_t length = drv->bdrv_getlength(bs);
+ if (length < 0) {
+ return length;
+ }
+ hint = length >> BDRV_SECTOR_BITS;
+ }
+
+ bs->total_sectors = hint;
+ return 0;
+}
+
/*
* Common part for opening disk images and files
*/
@@ -363,6 +383,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 +437,12 @@ 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;
+
+ ret = refresh_total_sectors(bs, bs->total_sectors);
+ if (ret < 0) {
+ goto free_and_fail;
}
+
#ifndef _WIN32
if (bs->is_temporary) {
unlink(filename);
@@ -959,13 +983,18 @@ 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) {
+ ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
+ }
+ return ret;
}
/**
@@ -976,8 +1005,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->growable || !drv->bdrv_getlength) {
return bs->total_sectors * BDRV_SECTOR_SIZE;
}
return drv->bdrv_getlength(bs);
--
1.7.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [Qemu-devel] Re: [PATCH v2] block: Cache total_sectors to reduce bdrv_getlength calls
2010-04-19 15:56 [Qemu-devel] [PATCH v2] block: Cache total_sectors to reduce bdrv_getlength calls Stefan Hajnoczi
@ 2010-04-20 8:35 ` Kevin Wolf
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Wolf @ 2010-04-20 8:35 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: Jan Kiszka, qemu-devel, Christoph Hellwig
Am 19.04.2010 17:56, schrieb 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 <jan.kiszka@siemens.com> 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 <stefanha@linux.vnet.ibm.com>
> ---
> v2:
> - Introduced refresh_total_sectors() to clean up total_sectors updates
> - Added error handling for refresh_total_sectors() callers
Looks good, applied to the block branch.
Kevin
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2010-04-20 8:35 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-19 15:56 [Qemu-devel] [PATCH v2] block: Cache total_sectors to reduce bdrv_getlength calls Stefan Hajnoczi
2010-04-20 8:35 ` [Qemu-devel] " Kevin Wolf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).