qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 17/17] raw: implement is_allocated


From: Paolo Bonzini
Subject: [Qemu-devel] [RFC PATCH 17/17] raw: implement is_allocated
Date: Thu, 8 Mar 2012 18:15:17 +0100

SEEK_DATA and SEEK_HOLE can be used to implement the is_allocated
callback for raw files.  These currently work on btrfs, with an XFS
implementation also coming soon.

Signed-off-by: Paolo Bonzini <address@hidden>
---
 block/raw-posix.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 block/raw.c       |    8 ++++++
 2 files changed, 70 insertions(+), 0 deletions(-)

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 56aabc7..c0b32e1 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -105,6 +105,13 @@
 #define O_DIRECT O_DSYNC
 #endif
 
+#ifndef SEEK_DATA
+#define SEEK_DATA 3
+#endif
+#ifndef SEEK_HOLE
+#define SEEK_HOLE 4
+#endif
+
 #define FTYPE_FILE   0
 #define FTYPE_CD     1
 #define FTYPE_FD     2
@@ -583,6 +590,60 @@ static int raw_create(const char *filename, 
QEMUOptionParameter *options)
     return result;
 }
 
+/*
+ * Returns true iff the specified sector is present in the disk image. Drivers
+ * not implementing the functionality are assumed to not support backing files,
+ * hence all their sectors are reported as allocated.
+ *
+ * If 'sector_num' is beyond the end of the disk image the return value is 0
+ * and 'pnum' is set to 0.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the specified sector) that are known to be in the same
+ * allocated/unallocated state.
+ *
+ * 'nb_sectors' is the max value 'pnum' should be set to.  If nb_sectors goes
+ * beyond the end of the disk image it will be clamped.
+ */
+static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            int nb_sectors, int *pnum)
+{
+    off_t start, data, hole;
+    int ret, num;
+    BDRVRawState *s = bs->opaque;
+
+    ret = fd_open(bs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    start = sector_num * BDRV_SECTOR_SIZE;
+    hole = lseek(s->fd, start, SEEK_HOLE);
+    if (hole == -1) {
+        /* -ENXIO indicates that sector_num was past the end of the file.
+         * There is a virtual hole there.  */
+        assert(errno != -ENXIO);
+
+        /* Most likely EINVAL.  Assume everything is allocated.  */
+        return 1;
+    }
+
+    if (hole == start) {
+        /* On a hole.  We need another syscall to find its end.  */
+        data = lseek(s->fd, start, SEEK_DATA);
+        assert (data != -1);
+        num = (data - start) / BDRV_SECTOR_SIZE;
+    } else {
+        data = start;
+        num = (hole - start) / BDRV_SECTOR_SIZE;
+    }
+
+    /* Clamping to the file size is done by the kernel.  */
+    *pnum = MIN(nb_sectors, num);
+    return data == start;
+}
+
 #ifdef CONFIG_XFS
 static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 {
@@ -661,6 +722,7 @@ static BlockDriver bdrv_file = {
     .bdrv_close = raw_close,
     .bdrv_create = raw_create,
     .bdrv_co_discard = raw_co_discard,
+    .bdrv_co_is_allocated = raw_co_is_allocated,
 
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
diff --git a/block/raw.c b/block/raw.c
index 3618c2d..e433bf2 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -30,6 +30,13 @@ static int coroutine_fn raw_co_flush(BlockDriverState *bs)
     return bdrv_co_flush(bs->file);
 }
 
+static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
+                                            int64_t sector_num,
+                                            int nb_sectors, int *pnum)
+{
+    return bdrv_co_is_allocated(bs->file, sector_num, nb_sectors, pnum);
+}
+
 static int64_t raw_getlength(BlockDriverState *bs)
 {
     return bdrv_getlength(bs->file);
@@ -119,6 +126,7 @@ static BlockDriver bdrv_raw = {
     .bdrv_co_readv          = raw_co_readv,
     .bdrv_co_writev         = raw_co_writev,
     .bdrv_co_flush_to_disk  = raw_co_flush,
+    .bdrv_co_is_allocated   = raw_co_is_allocated,
     .bdrv_co_discard        = raw_co_discard,
 
     .bdrv_probe         = raw_probe,
-- 
1.7.7.6




reply via email to

[Prev in Thread] Current Thread [Next in Thread]