summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-04-29 20:06:20 +0200
committerLennart Poettering <lennart@poettering.net>2016-05-02 11:15:30 +0200
commit9a50e3caab82f8406ecfac6048ac8e2ce98b0ab8 (patch)
tree5e7f5458a2911a7cb13a7e708fa0384b10e27cec
parenta67d68b84801dccbbc03010c679138bb9e4f91ac (diff)
machined: support non-btrfs file systems with "machinectl clone"
Fall back to a normal copy operation when the backing file system isn't btrfs, and hence doesn't support cheap snapshotting. Of course, this will be slow, but given that the execution is asynchronous now, this should be OK. Fixes: #1308
-rw-r--r--src/basic/copy.c15
-rw-r--r--src/basic/copy.h1
-rw-r--r--src/shared/machine-image.c14
3 files changed, 27 insertions, 3 deletions
diff --git a/src/basic/copy.c b/src/basic/copy.c
index 79b9a0e1a0..c3586728d0 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -423,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
}
+int copy_directory(const char *from, const char *to, bool merge) {
+ struct stat st;
+
+ assert(from);
+ assert(to);
+
+ if (lstat(from, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -ENOTDIR;
+
+ return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
_cleanup_close_ int fdf = -1;
int r;
diff --git a/src/basic/copy.h b/src/basic/copy.h
index 3e5eb52506..b5d08ebafe 100644
--- a/src/basic/copy.h
+++ b/src/basic/copy.h
@@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
+int copy_directory(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
int copy_times(int fdf, int fdt);
int copy_xattr(int fdf, int fdt);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index eb8f6ee438..66f58ecd92 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -603,12 +603,20 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_SUBVOLUME:
case IMAGE_DIRECTORY:
+ /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
+ * directory.*/
+
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
-
- /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
- if (r >= 0)
+ if (r == -EOPNOTSUPP) {
+ /* No btrfs snapshots supported, create a normal directory then. */
+
+ r = copy_directory(i->path, new_path, false);
+ if (r >= 0)
+ (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+ } else if (r >= 0)
+ /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
(void) btrfs_subvol_auto_qgroup(new_path, 0, true);
break;