aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorChunyan Liu <cyliu@suse.com>2014-06-30 14:29:58 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2014-07-01 10:15:12 +0200
commit4ab1559085d688dddf4de77f1ead3102e243e668 (patch)
treec02aaa834a94aace2ef773462cea3b4829cc48a9 /block
parent8698e110f8aa1cdf8ba1afdda8f2658333a4ab01 (diff)
qemu-img create: add 'nocow' option
Add 'nocow' option so that users could have a chance to set NOCOW flag to newly created files. It's useful on btrfs file system to enhance performance. Btrfs has low performance when hosting VM images, even more when the guest in those VM are also using btrfs as file system. One way to mitigate this bad performance is to turn off COW attributes on VM files. Generally, there are two ways to turn off NOCOW on btrfs: a) by mounting fs with nodatacow, then all newly created files will be NOCOW. b) per file. Add the NOCOW file attribute. It could only be done to empty or new files. This patch tries the second way, according to the option, it could add NOCOW per file. For most block drivers, since the create file step is in raw-posix.c, so we can do setting NOCOW flag ioctl in raw-posix.c only. But there are some exceptions, like block/vpc.c and block/vdi.c, they are creating file by calling qemu_open directly. For them, do the same setting NOCOW flag ioctl work in them separately. [Fixed up 082.out due to the new 'nocow' creation option --Stefan] Signed-off-by: Chunyan Liu <cyliu@suse.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/qed.c6
-rw-r--r--block/raw-posix.c25
-rw-r--r--block/vdi.c29
-rw-r--r--block/vmdk.c6
-rw-r--r--block/vpc.c29
5 files changed, 89 insertions, 6 deletions
diff --git a/block/qed.c b/block/qed.c
index eddae929eb..b69374b6a2 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -567,7 +567,7 @@ static void bdrv_qed_close(BlockDriverState *bs)
static int qed_create(const char *filename, uint32_t cluster_size,
uint64_t image_size, uint32_t table_size,
const char *backing_file, const char *backing_fmt,
- Error **errp)
+ QemuOpts *opts, Error **errp)
{
QEDHeader header = {
.magic = QED_MAGIC,
@@ -586,7 +586,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
int ret = 0;
BlockDriverState *bs;
- ret = bdrv_create_file(filename, NULL, &local_err);
+ ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return ret;
@@ -682,7 +682,7 @@ static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp)
}
ret = qed_create(filename, cluster_size, image_size, table_size,
- backing_file, backing_fmt, errp);
+ backing_file, backing_fmt, opts, errp);
finish:
g_free(backing_file);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index dacf4fbbc8..825a0c878f 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -55,6 +55,9 @@
#include <linux/cdrom.h>
#include <linux/fd.h>
#include <linux/fs.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
#endif
#ifdef CONFIG_FIEMAP
#include <linux/fiemap.h>
@@ -1278,12 +1281,14 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
int fd;
int result = 0;
int64_t total_size = 0;
+ bool nocow = false;
strstart(filename, "file:", &filename);
/* Read out options */
total_size =
qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
+ nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
0644);
@@ -1291,6 +1296,21 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
result = -errno;
error_setg_errno(errp, -result, "Could not create file");
} else {
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
+ * will be ignored since any failure of this operation should not
+ * block the left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
result = -errno;
error_setg_errno(errp, -result, "Could not resize file");
@@ -1477,6 +1497,11 @@ static QemuOptsList raw_create_opts = {
.type = QEMU_OPT_SIZE,
.help = "Virtual disk size"
},
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
{ /* end of list */ }
}
};
diff --git a/block/vdi.c b/block/vdi.c
index 01fe22ebe8..197bd77c97 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -53,6 +53,13 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
+#ifdef __linux__
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
+#endif
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
@@ -683,6 +690,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
VdiHeader header;
size_t i;
size_t bmap_size;
+ bool nocow = false;
logout("\n");
@@ -699,6 +707,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
image_type = VDI_TYPE_STATIC;
}
#endif
+ nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
if (bytes > VDI_DISK_SIZE_MAX) {
result = -ENOTSUP;
@@ -716,6 +725,21 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
goto exit;
}
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
+ * be ignored since any failure of this operation should not block the
+ * left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
/* We need enough blocks to store the given disk size,
so always round up. */
blocks = (bytes + block_size - 1) / block_size;
@@ -818,6 +842,11 @@ static QemuOptsList vdi_create_opts = {
.def_value_str = "off"
},
#endif
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
/* TODO: An additional option to set UUID values might be useful. */
{ /* end of list */ }
}
diff --git a/block/vmdk.c b/block/vmdk.c
index d0de0193fc..27a78daa02 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1529,7 +1529,7 @@ static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs,
static int vmdk_create_extent(const char *filename, int64_t filesize,
bool flat, bool compress, bool zeroed_grain,
- Error **errp)
+ QemuOpts *opts, Error **errp)
{
int ret, i;
BlockDriverState *bs = NULL;
@@ -1539,7 +1539,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
uint32_t *gd_buf = NULL;
int gd_buf_size;
- ret = bdrv_create_file(filename, NULL, &local_err);
+ ret = bdrv_create_file(filename, opts, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto exit;
@@ -1845,7 +1845,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
path, desc_filename);
if (vmdk_create_extent(ext_filename, size,
- flat, compress, zeroed_grain, errp)) {
+ flat, compress, zeroed_grain, opts, errp)) {
ret = -EINVAL;
goto exit;
}
diff --git a/block/vpc.c b/block/vpc.c
index 798d8540db..8b376a40be 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -29,6 +29,13 @@
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#endif
+#ifdef __linux__
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
+#endif
/**************************************************************/
@@ -751,6 +758,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
int64_t total_size;
int disk_type;
int ret = -EIO;
+ bool nocow = false;
/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
@@ -767,6 +775,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
} else {
disk_type = VHD_DYNAMIC;
}
+ nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
/* Create the file */
fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
@@ -775,6 +784,21 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
goto out;
}
+ if (nocow) {
+#ifdef __linux__
+ /* Set NOCOW flag to solve performance issue on fs like btrfs.
+ * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
+ * be ignored since any failure of this operation should not block the
+ * left work.
+ */
+ int attr;
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
+ attr |= FS_NOCOW_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &attr);
+ }
+#endif
+ }
+
/*
* Calculate matching total_size and geometry. Increase the number of
* sectors requested until we get enough (or fail). This ensures that
@@ -884,6 +908,11 @@ static QemuOptsList vpc_create_opts = {
"Type of virtual hard disk format. Supported formats are "
"{dynamic (default) | fixed} "
},
+ {
+ .name = BLOCK_OPT_NOCOW,
+ .type = QEMU_OPT_BOOL,
+ .help = "Turn off copy-on-write (valid only on btrfs)"
+ },
{ /* end of list */ }
}
};