Add host_device support to qemu-img. (Nolan Leake)

This patch allows the use a host_device as the destination for "qemu-img
convert".

I added a ->bdrv_create function host_device.  It merely verifies that
the device exists and is large enough.

A check is needed in the qemu-img convert loop to ensure that we write
out all 0 sectors to the host_device.  Otherwise they end up with stale
garbage where all zero sectors were expected.

I also made the check against bdrv_is_allocated enabled for everything
_except_ host devices, since there is no point in making the block
backend write a bunch of zeros just so that we can memcmp them
immediately afterwards.  Host devices can't benefit from this because
there is no way to differentiate between a sector being unallocated
because it was never written, or because it was written with all zeros
and then made a trip through qemu-img convert.

Finally, there is an unrelated fix for a typo in the error message
printed if the destination device does not support ->bdrv_create.

Signed-off-by: Nolan Leake <nolan <at> sigbus.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6978 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
aliguori 2009-04-05 17:40:43 +00:00
parent f8de16605c
commit 93c65b47a6
2 changed files with 55 additions and 15 deletions

View File

@ -1378,11 +1378,47 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
} }
#endif /* !linux && !FreeBSD */ #endif /* !linux && !FreeBSD */
#if defined(__linux__) || defined(__FreeBSD__)
static int hdev_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
int fd;
int ret = 0;
struct stat stat_buf;
if (flags || backing_file)
return -ENOTSUP;
fd = open(filename, O_WRONLY | O_BINARY);
if (fd < 0)
return -EIO;
if (fstat(fd, &stat_buf) < 0)
ret = -EIO;
else if (!S_ISBLK(stat_buf.st_mode))
ret = -EIO;
else if (lseek(fd, 0, SEEK_END) < total_size * 512)
ret = -ENOSPC;
close(fd);
return ret;
}
#else /* !(linux || freebsd) */
static int hdev_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
return -ENOTSUP;
}
#endif
BlockDriver bdrv_host_device = { BlockDriver bdrv_host_device = {
.format_name = "host_device", .format_name = "host_device",
.instance_size = sizeof(BDRVRawState), .instance_size = sizeof(BDRVRawState),
.bdrv_open = hdev_open, .bdrv_open = hdev_open,
.bdrv_close = raw_close, .bdrv_close = raw_close,
.bdrv_create = hdev_create,
.bdrv_flush = raw_flush, .bdrv_flush = raw_flush,
#ifdef CONFIG_AIO #ifdef CONFIG_AIO

View File

@ -493,7 +493,7 @@ static int img_convert(int argc, char **argv)
ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags); ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
if (ret < 0) { if (ret < 0) {
if (ret == -ENOTSUP) { if (ret == -ENOTSUP) {
error("Formatting not supported for file format '%s'", fmt); error("Formatting not supported for file format '%s'", out_fmt);
} else { } else {
error("Error while formatting '%s'", out_filename); error("Error while formatting '%s'", out_filename);
} }
@ -592,18 +592,17 @@ static int img_convert(int argc, char **argv)
if (n > bs_offset + bs_sectors - sector_num) if (n > bs_offset + bs_sectors - sector_num)
n = bs_offset + bs_sectors - sector_num; n = bs_offset + bs_sectors - sector_num;
/* If the output image is being created as a copy on write image, if (drv != &bdrv_host_device) {
assume that sectors which are unallocated in the input image if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
are present in both the output's and input's base images (no n, &n1)) {
need to copy them). */
if (out_baseimg) {
if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
sector_num += n1; sector_num += n1;
continue; continue;
} }
/* The next 'n1' sectors are allocated in the input image. Copy /* The next 'n1' sectors are allocated in the input image. Copy
only those as they may be followed by unallocated sectors. */ only those as they may be followed by unallocated sectors. */
n = n1; n = n1;
} else {
n1 = n;
} }
if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
@ -615,8 +614,13 @@ static int img_convert(int argc, char **argv)
while (n > 0) { while (n > 0) {
/* If the output image is being created as a copy on write image, /* If the output image is being created as a copy on write image,
copy all sectors even the ones containing only NUL bytes, copy all sectors even the ones containing only NUL bytes,
because they may differ from the sectors in the base image. */ because they may differ from the sectors in the base image.
if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
If the output is to a host device, we also write out
sectors that are entirely 0, since whatever data was
already there is garbage, not 0s. */
if (drv == &bdrv_host_device || out_baseimg ||
is_allocated_sectors(buf1, n, &n1)) {
if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
error("error while writing"); error("error while writing");
} }