]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zfs_vnops.c
Allow block cloning across encrypted datasets
[mirror_zfs.git] / module / zfs / zfs_vnops.c
index 635d17455981b820dc1d47d04151df009c2cadfb..b2b7e36645b5597f37270ed9e68ecfe7ac1773af 100644 (file)
@@ -47,6 +47,7 @@
 #include <sys/fs/zfs.h>
 #include <sys/dmu.h>
 #include <sys/dmu_objset.h>
+#include <sys/dsl_crypt.h>
 #include <sys/spa.h>
 #include <sys/txg.h>
 #include <sys/dbuf.h>
@@ -1097,6 +1098,16 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
                return (SET_ERROR(EXDEV));
        }
 
+       /*
+        * Cloning across encrypted datasets is possible only if they
+        * share the same master key.
+        */
+       if (inos != outos && inos->os_encrypted &&
+           !dmu_objset_crypto_key_equal(inos, outos)) {
+               zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
+               return (SET_ERROR(EXDEV));
+       }
+
        error = zfs_verify_zp(inzp);
        if (error == 0)
                error = zfs_verify_zp(outzp);
@@ -1280,20 +1291,6 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
                         */
                        break;
                }
-               /*
-                * Encrypted data is fine as long as it comes from the same
-                * dataset.
-                * TODO: We want to extend it in the future to allow cloning to
-                * datasets with the same keys, like clones or to be able to
-                * clone a file from a snapshot of an encrypted dataset into the
-                * dataset itself.
-                */
-               if (BP_IS_PROTECTED(&bps[0])) {
-                       if (inzfsvfs != outzfsvfs) {
-                               error = SET_ERROR(EXDEV);
-                               break;
-                       }
-               }
 
                /*
                 * Start a transaction.
@@ -1327,7 +1324,7 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
                }
 
                error = dmu_brt_clone(outos, outzp->z_id, outoff, size, tx,
-                   bps, nbps, B_FALSE);
+                   bps, nbps);
                if (error != 0) {
                        dmu_tx_commit(tx);
                        break;
@@ -1461,7 +1458,7 @@ zfs_clone_range_replay(znode_t *zp, uint64_t off, uint64_t len, uint64_t blksz,
        if (zp->z_blksz < blksz)
                zfs_grow_blocksize(zp, blksz, tx);
 
-       dmu_brt_clone(zfsvfs->z_os, zp->z_id, off, len, tx, bps, nbps, B_TRUE);
+       dmu_brt_clone(zfsvfs->z_os, zp->z_id, off, len, tx, bps, nbps);
 
        zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);