[libvirt] [PATCH 2/2] storage: try to perform btrfs COW copy if possible

Chen Hanxiao chenhanxiao at cn.fujitsu.com
Tue Jan 13 08:18:29 UTC 2015


We don't take advantage of clone of btrfs.

So
a)try to do a btrfs lightweight copy

b)fall back to a standard copy
  if COW copy not supported.

Signed-off-by: Chen Hanxiao <chenhanxiao at cn.fujitsu.com>
---
 include/libvirt/libvirt-storage.h |  1 +
 src/storage/storage_backend.c     | 39 ++++++++++++++++++++++++++++++++-------
 src/storage/storage_backend_fs.c  |  8 ++++++--
 src/storage/storage_driver.c      |  4 +++-
 4 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 1f3087b..4ae42e1 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,
 } virStorageVolCreateFlags;
 
 virStorageVolPtr        virStorageVolCreateXML          (virStoragePoolPtr pool,
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index 5ce3566..838398e 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -187,7 +187,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;
@@ -226,6 +227,15 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol,
         goto cleanup;
     }
 
+    if (reflink_copy) {
+        if (btrfsCloneFile(fd, inputfd) == -1) {
+            VIR_DEBUG("btrfs clone not supported, try another way.");
+        } else {
+            VIR_DEBUG("btrfs clone findished.");
+            goto cleanup;
+        }
+    }
+
     while (amtread != 0) {
         int amtleft;
 
@@ -306,8 +316,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",
@@ -316,6 +329,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'"),
@@ -327,7 +343,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;
     }
@@ -372,7 +388,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;
@@ -419,7 +436,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;
     }
@@ -454,8 +472,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",
@@ -464,6 +485,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"));
@@ -506,7 +531,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);
-- 
1.9.3




More information about the libvir-list mailing list