From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:40961) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S5gww-0005Vd-8j for qemu-devel@nongnu.org; Thu, 08 Mar 2012 12:16:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S5gwg-0004tQ-C8 for qemu-devel@nongnu.org; Thu, 08 Mar 2012 12:16:21 -0500 Received: from mail-iy0-f173.google.com ([209.85.210.173]:47906) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S5gwg-0004n5-4p for qemu-devel@nongnu.org; Thu, 08 Mar 2012 12:16:06 -0500 Received: by mail-iy0-f173.google.com with SMTP id j26so1015616iaf.4 for ; Thu, 08 Mar 2012 09:16:05 -0800 (PST) Sender: Paolo Bonzini From: Paolo Bonzini Date: Thu, 8 Mar 2012 18:15:17 +0100 Message-Id: <1331226917-6658-18-git-send-email-pbonzini@redhat.com> In-Reply-To: <1331226917-6658-1-git-send-email-pbonzini@redhat.com> References: <1331226917-6658-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [RFC PATCH 17/17] raw: implement is_allocated List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 --- 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