[libvirt] [PATCHv2 2/2] storage: try to perform btrfs clone if possible

Chen Hanxiao chenhanxiao at cn.fujitsu.com
Fri Jan 23 10:22:35 UTC 2015


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 at 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




More information about the libvir-list mailing list