From patchwork Wed May 9 14:49:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 157981 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 479EBB6FB6 for ; Thu, 10 May 2012 00:50:33 +1000 (EST) Received: from localhost ([::1]:47274 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS8Dm-0001J1-7v for incoming@patchwork.ozlabs.org; Wed, 09 May 2012 10:50:30 -0400 Received: from eggs.gnu.org ([208.118.235.92]:48868) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS8DZ-0001Fd-28 for qemu-devel@nongnu.org; Wed, 09 May 2012 10:50:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SS8DS-00042q-Gu for qemu-devel@nongnu.org; Wed, 09 May 2012 10:50:16 -0400 Received: from mail-pz0-f45.google.com ([209.85.210.45]:33802) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SS8DS-00042O-4I for qemu-devel@nongnu.org; Wed, 09 May 2012 10:50:10 -0400 Received: by dadv2 with SMTP id v2so519464dad.4 for ; Wed, 09 May 2012 07:50:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to; bh=5v2SlZTKdhokbkhR3HwdJoG7xkFfxTal8459CQHgFOA=; b=niEPzgsQFu3yKIpULnbR3IGnClcJ/BzTqde0IXp9oDH4cE/HXExpsHVKJLAqAw7a2c gRiwNtBkLrIXIR9zROpABytH1wG1ro0iTL2KsMiTAs1nhWJPbMLqvHYY6zdaK3hqeiJY zobAHqlhWHhN+GPDs6fwJvLjNk/PdsmHo8HPVWhV2g0iZGdbeXPWkW4/ZEXHFFc8YFKU DaG7Z+woZKFkGSrJGbgOyyWJmk8fJaR1T7H+wvw2I/fmCk+uW3lCeXatgrXN7JQCvsCR qxnXjecYwLeIt788lB+BDo22+Q8T6lRZRyrPGtOmGMprbbyosns/3dJNkIcehsUbJfFF e/2g== Received: by 10.68.217.37 with SMTP id ov5mr10041086pbc.25.1336575007989; Wed, 09 May 2012 07:50:07 -0700 (PDT) Received: from yakj.usersys.redhat.com (93-34-182-16.ip50.fastwebnet.it. [93.34.182.16]) by mx.google.com with ESMTPS id vl3sm6315379pbc.44.2012.05.09.07.50.04 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 09 May 2012 07:50:06 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Wed, 9 May 2012 16:49:58 +0200 Message-Id: <1336574998-7399-1-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.7.10.1 In-reply-to: <4FAA7E10.5020206@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.210.45 Cc: kwolf@redhat.com, stefanha@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH next v2 19/22] block: implement is_allocated for raw X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 #include #include +#include +#endif +#ifdef CONFIG_FIEMAP +#include #endif #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) #include @@ -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,