When creating RAW file, we don't take advantage
of clone of btrfs.
Try to do a btrfs lightweight copy, or error out.
Signed-off-by: Chen Hanxiao <chenhanxiao(a)cn.fujitsu.com>
---
include/libvirt/libvirt-storage.h | 1 +
src/storage/storage_backend.c | 43 ++++++++++++++++++++++++++++++++-------
src/storage/storage_backend_fs.c | 8 ++++++--
src/storage/storage_driver.c | 4 +++-
4 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 1f3087b..453089e 100644
--- a/include/libvirt/libvirt-storage.h
+++ b/include/libvirt/libvirt-storage.h
@@ -306,6 +306,7 @@ const char* virStorageVolGetKey
(virStorageVolPtr vol);
typedef enum {
VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA = 1 << 0,
+ VIR_STORAGE_VOL_CREATE_REFLINK = 1 << 1, /* perform a btrfs lightweight copy
*/
} virStorageVolCreateFlags;
virStorageVolPtr virStorageVolCreateXML (virStoragePoolPtr pool,
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index d2a664b..cf13704 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -185,7 +185,8 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
int fd,
unsigned long long *total,
- bool want_sparse)
+ bool want_sparse,
+ bool reflink_copy)
{
int inputfd = -1;
int amtread = -1;
@@ -224,6 +225,19 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol,
goto cleanup;
}
+ if (reflink_copy) {
+ if (btrfsCloneFile(fd, inputfd) < 0) {
+ ret = -errno;
+ virReportSystemError(errno,
+ _("failed to clone files from '%s'"),
+ inputvol->target.path);
+ goto cleanup;
+ } else {
+ VIR_DEBUG("btrfs clone findished.");
+ goto cleanup;
+ }
+ }
+
while (amtread != 0) {
int amtleft;
@@ -304,8 +318,11 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn
ATTRIBUTE_UNUSED,
struct stat st;
gid_t gid;
uid_t uid;
+ bool reflink_copy = false;
- virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
+ virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
+ VIR_STORAGE_VOL_CREATE_REFLINK,
+ -1);
if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -314,6 +331,9 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
goto cleanup;
}
+ if (flags & VIR_STORAGE_VOL_CREATE_REFLINK)
+ reflink_copy = true;
+
if ((fd = open(vol->target.path, O_RDWR)) < 0) {
virReportSystemError(errno,
_("cannot create path '%s'"),
@@ -325,7 +345,7 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
if (inputvol) {
int res = virStorageBackendCopyToFD(vol, inputvol,
- fd, &remain, false);
+ fd, &remain, false, reflink_copy);
if (res < 0)
goto cleanup;
}
@@ -370,7 +390,8 @@ virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
static int
createRawFile(int fd, virStorageVolDefPtr vol,
- virStorageVolDefPtr inputvol)
+ virStorageVolDefPtr inputvol,
+ bool reflink_copy)
{
bool need_alloc = true;
int ret = 0;
@@ -417,7 +438,8 @@ createRawFile(int fd, virStorageVolDefPtr vol,
bool want_sparse = !need_alloc ||
(vol->target.allocation < inputvol->target.capacity);
- ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain, want_sparse);
+ ret = virStorageBackendCopyToFD(vol, inputvol, fd, &remain,
+ want_sparse, reflink_copy);
if (ret < 0)
goto cleanup;
}
@@ -452,8 +474,11 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
int ret = -1;
int fd = -1;
int operation_flags;
+ bool reflink_copy = false;
- virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
+ virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
+ VIR_STORAGE_VOL_CREATE_REFLINK,
+ -1);
if (flags & VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -462,6 +487,10 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
goto cleanup;
}
+ if (flags & VIR_STORAGE_VOL_CREATE_REFLINK)
+ reflink_copy = true;
+
+
if (vol->target.encryption != NULL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("storage pool does not support encrypted volumes"));
@@ -504,7 +533,7 @@ virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
#endif
}
- if ((ret = createRawFile(fd, vol, inputvol)) < 0)
+ if ((ret = createRawFile(fd, vol, inputvol, reflink_copy)) < 0)
/* createRawFile already reported the exact error. */
ret = -1;
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index 34f2153..cf30aab 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -1105,7 +1105,9 @@ virStorageBackendFileSystemVolBuild(virConnectPtr conn,
virStorageVolDefPtr vol,
unsigned int flags)
{
- virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
+ virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
+ VIR_STORAGE_VOL_CREATE_REFLINK,
+ -1);
return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags);
}
@@ -1120,7 +1122,9 @@ virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
- virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
+ virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
+ VIR_STORAGE_VOL_CREATE_REFLINK,
+ -1);
return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags);
}
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index 66dc994..2c7af48 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -1775,7 +1775,9 @@ storageVolCreateXMLFrom(virStoragePoolPtr obj,
unsigned long long allocation;
int buildret;
- virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL);
+ virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
+ VIR_STORAGE_VOL_CREATE_REFLINK,
+ NULL);
storageDriverLock();
pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
--
2.1.0