[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PATCH] raw-posix: add 'offset' and 'size' options
From: |
Tomáš Golembiovský |
Subject: |
[Qemu-block] [PATCH] raw-posix: add 'offset' and 'size' options |
Date: |
Sun, 2 Oct 2016 21:13:29 +0200 |
Added two new options 'offset' and 'size'. This makes it possible to use
only part of the file as a device. This can be used e.g. to limit the
access only to single partition in a disk image or use a disk inside a
tar archive (like OVA).
For now this is only possible for files in read-only mode. It should be
possible to extend it later to allow read-write mode, but would probably
require that the size of the device is kept constant (i.e. no resizing).
Signed-off-by: Tomáš Golembiovský <address@hidden>
---
block/raw-posix.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 91 insertions(+), 6 deletions(-)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6ed7547..36f2712 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -136,6 +136,8 @@ typedef struct BDRVRawState {
int type;
int open_flags;
size_t buf_align;
+ uint64_t offset;
+ uint64_t assumed_size;
#ifdef CONFIG_XFS
bool is_xfs:1;
@@ -154,6 +156,7 @@ typedef struct BDRVRawReopenState {
static int fd_open(BlockDriverState *bs);
static int64_t raw_getlength(BlockDriverState *bs);
+static int64_t raw_getlength_real(BlockDriverState *bs);
typedef struct RawPosixAIOData {
BlockDriverState *bs;
@@ -399,6 +402,16 @@ static QemuOptsList raw_runtime_opts = {
.type = QEMU_OPT_STRING,
.help = "File name of the image",
},
+ {
+ .name = "offset",
+ .type = QEMU_OPT_SIZE,
+ .help = "Offset into the file"
+ },
+ {
+ .name = BLOCK_OPT_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Virtual disk size"
+ },
{ /* end of list */ }
},
};
@@ -412,6 +425,7 @@ static int raw_open_common(BlockDriverState *bs, QDict
*options,
const char *filename = NULL;
int fd, ret;
struct stat st;
+ int64_t real_size;
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
@@ -421,6 +435,17 @@ static int raw_open_common(BlockDriverState *bs, QDict
*options,
goto fail;
}
+ s->offset = qemu_opt_get_size(opts, "offset", 0);
+ s->assumed_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
+
+ if (((bs->drv != &bdrv_file) || !bs->read_only) &&
+ ((s->offset > 0) || (s->assumed_size > 0))) {
+ error_setg(errp, "offset and size options are allowed only for "
+ "files in read-only mode");
+ ret = -EINVAL;
+ goto fail;
+ }
+
filename = qemu_opt_get(opts, "filename");
ret = raw_normalize_devicepath(&filename);
@@ -443,6 +468,23 @@ static int raw_open_common(BlockDriverState *bs, QDict
*options,
}
s->fd = fd;
+ /* Check size and offset */
+ real_size = raw_getlength_real(bs);
+ if (real_size < (s->offset + s->assumed_size)) {
+ if (s->assumed_size == 0) {
+ error_setg(errp, "The offset has to be smaller than actual size "
+ "of the containing file (%ld) ",
+ real_size);
+ } else {
+ error_setg(errp, "The sum of offset (%lu) and size (%lu) has to "
+ "be smaller than actual size of the containing "
+ "file (%ld) ",
+ s->offset, s->assumed_size, real_size);
+ }
+ ret = -EINVAL;
+ goto fail;
+ }
+
#ifdef CONFIG_LINUX_AIO
if (!raw_use_aio(bdrv_flags) && (bdrv_flags & BDRV_O_NATIVE_AIO)) {
error_setg(errp, "aio=native was specified, but it requires "
@@ -1271,6 +1313,19 @@ static int coroutine_fn raw_co_preadv(BlockDriverState
*bs, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov,
int flags)
{
+ BDRVRawState *s = bs->opaque;
+ if (s->assumed_size > 0) {
+ if (offset > s->assumed_size) {
+ /* Attempt to read beyond EOF */
+ return 0;
+ } else if ((offset + bytes) > s->assumed_size) {
+ /* Trying to read more than is available */
+ bytes = s->assumed_size - offset;
+ }
+ }
+
+ offset += s->offset;
+
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_READ);
}
@@ -1348,7 +1403,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t
offset)
}
#ifdef __OpenBSD__
-static int64_t raw_getlength(BlockDriverState *bs)
+static int64_t raw_getlength_real(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -1367,7 +1422,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
return st.st_size;
}
#elif defined(__NetBSD__)
-static int64_t raw_getlength(BlockDriverState *bs)
+static int64_t raw_getlength_real(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -1392,7 +1447,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
return st.st_size;
}
#elif defined(__sun__)
-static int64_t raw_getlength(BlockDriverState *bs)
+static int64_t raw_getlength_real(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
struct dk_minfo minfo;
@@ -1423,7 +1478,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
return size;
}
#elif defined(CONFIG_BSD)
-static int64_t raw_getlength(BlockDriverState *bs)
+static int64_t raw_getlength_real(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int fd = s->fd;
@@ -1497,7 +1552,7 @@ again:
return size;
}
#else
-static int64_t raw_getlength(BlockDriverState *bs)
+static int64_t raw_getlength_real(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
int ret;
@@ -1516,6 +1571,28 @@ static int64_t raw_getlength(BlockDriverState *bs)
}
#endif
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+
+ if (s->assumed_size > 0) {
+ return (int64_t)s->assumed_size;
+ }
+
+ int64_t size = raw_getlength_real(bs);
+ if (s->offset > 0) {
+ if (s->offset > size) {
+ /* The size has changed! We didn't expect that. */
+ return -EIO;
+ }
+ size -= s->offset;
+ }
+
+ return size;
+}
+
+
+
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
{
struct stat st;
@@ -1524,7 +1601,15 @@ static int64_t
raw_get_allocated_file_size(BlockDriverState *bs)
if (fstat(s->fd, &st) < 0) {
return -errno;
}
- return (int64_t)st.st_blocks * 512;
+ uint64_t size = st.st_blocks * 512;
+ /* If the file is sparse we have no idea which part of the file is
+ * allocated and which is not. So we just make sure the returned value is
+ * not greater than what we're working with.
+ */
+ if (s->assumed_size > 0 && s->assumed_size < size) {
+ size = s->assumed_size;
+ }
+ return (int64_t)size;
}
static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
--
2.10.0
- [Qemu-block] [PATCH] raw-posix: add 'offset' and 'size' options,
Tomáš Golembiovský <=
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Daniel P. Berrange, 2016/10/03
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Tomáš Golembiovský, 2016/10/03
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Daniel P. Berrange, 2016/10/03
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Tomáš Golembiovský, 2016/10/03
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Daniel P. Berrange, 2016/10/03
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Kevin Wolf, 2016/10/04
- Re: [Qemu-block] [Qemu-devel] [PATCH] raw-posix: add 'offset' and 'size' options, Daniel P. Berrange, 2016/10/04