qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, stefanha@linux.vnet.ibm.com
Subject: [Qemu-devel] [PATCH next v2 19/22] block: implement is_allocated for raw
Date: Wed,  9 May 2012 16:49:58 +0200	[thread overview]
Message-ID: <1336574998-7399-1-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <4FAA7E10.5020206@redhat.com>

Either FIEMAP, or SEEK_DATA+SEEK_HOLE can be used to implement the
is_allocated callback for raw files.  On Linux ext4, btrfs and XFS
all support it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
        v1->v2: rely on headers (unistd.h or fcntl.h) to define
        SEEK_DATA and SEEK_HOLE.  Removed 1.1 from subject too.

 block/raw-posix.c |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 block/raw.c       |    8 +++++
 2 files changed, 106 insertions(+)

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 03fcfcc..bf7700a 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -52,6 +52,10 @@
 #include <sys/param.h>
 #include <linux/cdrom.h>
 #include <linux/fd.h>
+#include <linux/fs.h>
+#endif
+#ifdef CONFIG_FIEMAP
+#include <linux/fiemap.h>
 #endif
 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <sys/disk.h>
@@ -583,6 +587,99 @@ 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)
+{
+    BDRVRawState *s = bs->opaque;
+    off_t start, data, hole;
+    int ret;
+
+    ret = fd_open(bs);
+    if (ret < 0) {
+        return ret;
+    }
+
+    start = sector_num * BDRV_SECTOR_SIZE;
+#ifdef CONFIG_FIEMAP
+    struct {
+        struct fiemap fm;
+        struct fiemap_extent fe;
+    } f;
+    f.fm.fm_start = start;
+    f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
+    f.fm.fm_flags = 0;
+    f.fm.fm_extent_count = 1;
+    f.fm.fm_reserved = 0;
+    if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
+        /* Assume everything is allocated.  */
+        *pnum = nb_sectors;
+        return 1;
+    }
+
+    if (f.fm.fm_mapped_extents == 0) {
+        /* No extents found, data is beyond f.fm.fm_start + f.fm.fm_length.
+         * f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
+         */
+        off_t length = lseek(s->fd, 0, SEEK_END);
+        hole = f.fm.fm_start;
+        data = MIN(f.fm.fm_start + f.fm.fm_length, length);
+    } else {
+        data = f.fe.fe_logical;
+        hole = f.fe.fe_logical + f.fe.fe_length;
+    }
+#elif defined SEEK_HOLE && defined SEEK_DATA
+    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.  */
+        *pnum = nb_sectors;
+        return 1;
+    }
+
+    if (hole > start) {
+        data = start;
+    } else {
+        /* On a hole.  We need another syscall to find its end.  */
+        data = lseek(s->fd, start, SEEK_DATA);
+        if (data == -1) {
+            data = lseek(s->fd, 0, SEEK_END);
+        }
+    }
+#else
+    *pnum = nb_sectors;
+    return 1;
+#endif
+
+    if (data <= start) {
+        /* On a data extent, compute sectors to the end of the extent.  */
+        *pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE);
+        return 1;
+    } else {
+        /* On a hole, compute sectors to the beginning of the next extent.  */
+        *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE);
+        return 0;
+    }
+}
+
 #ifdef CONFIG_XFS
 static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors)
 {
@@ -634,6 +731,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 7086e31..09d9b48 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -25,6 +25,13 @@ static void raw_close(BlockDriverState *bs)
 {
 }
 
+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);
@@ -108,6 +115,7 @@ static BlockDriver bdrv_raw = {
 
     .bdrv_co_readv          = raw_co_readv,
     .bdrv_co_writev         = raw_co_writev,
+    .bdrv_co_is_allocated   = raw_co_is_allocated,
     .bdrv_co_discard        = raw_co_discard,
 
     .bdrv_probe         = raw_probe,
-- 
1.7.10.1

  reply	other threads:[~2012-05-09 14:50 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-08 14:51 [Qemu-devel] [PATCH 1.1 00/22] Rebased queue of block patches Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 01/22] block: fix snapshot on QED Paolo Bonzini
2012-05-09 12:15   ` Kevin Wolf
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 02/22] block: another bdrv_append fix Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 03/22] block: do not reuse the backing file across bdrv_close/bdrv_open Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 04/22] block: fully delete bs->file when closing Paolo Bonzini
2012-05-09 12:22   ` Kevin Wolf
2012-05-09 12:59     ` Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 05/22] block: add block_job_sleep_ns Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 06/22] block: wait for job callback in block_job_cancel_sync Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 07/22] block: simplify path_is_absolute Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 08/22] block: protect path_has_protocol from filenames with colons Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 09/22] block: move field reset from bdrv_open_common to bdrv_close Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 10/22] qemu-img: make "info" backing file output correct and easier to use Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 11/22] qemu-io: correctly print non-integer values as decimals Paolo Bonzini
2012-05-09 12:46   ` Kevin Wolf
2012-05-09 12:48     ` Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 12/22] qemu-io: fix the alloc command Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 13/22] stream: fix sectors not allocated test Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 14/22] stream: add testcase for partial streaming Paolo Bonzini
2012-05-09 12:59   ` Kevin Wolf
2012-05-09 13:05     ` [Qemu-devel] [PATCH 1.1 v2 " Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 15/22] stream: pass new base image format to bdrv_change_backing_file Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 16/22] stream: fix HMP block_job_set_speed Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 17/22] stream: fix ratelimiting corner case Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 18/22] stream: do not copy unallocated sectors from the base Paolo Bonzini
2012-05-08 14:51 ` [Qemu-devel] [PATCH 1.1 19/22] block: implement is_allocated for raw Paolo Bonzini
2012-05-09 13:40   ` Kevin Wolf
2012-05-09 14:05     ` Paolo Bonzini
2012-05-09 14:10       ` Kevin Wolf
2012-05-09 14:24         ` Paolo Bonzini
2012-05-09 14:49           ` Paolo Bonzini [this message]
2012-05-08 14:52 ` [Qemu-devel] [PATCH 1.1 20/22] stream: tweak usage of bdrv_co_is_allocated Paolo Bonzini
2012-05-08 14:52 ` [Qemu-devel] [PATCH 1.1 21/22] stream: move is_allocated_above to block.c Paolo Bonzini
2012-05-08 14:52 ` [Qemu-devel] [PATCH 1.1 22/22] stream: move rate limiting to a separate header file Paolo Bonzini
2012-05-09 13:52   ` Kevin Wolf
2012-05-09 14:09     ` [Qemu-devel] [PATCH 1.1 v2 " Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1336574998-7399-1-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).