diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-04-29 20:06:20 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-05-02 11:15:30 +0200 |
commit | 9a50e3caab82f8406ecfac6048ac8e2ce98b0ab8 (patch) | |
tree | 5e7f5458a2911a7cb13a7e708fa0384b10e27cec | |
parent | a67d68b84801dccbbc03010c679138bb9e4f91ac (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.c | 15 | ||||
-rw-r--r-- | src/basic/copy.h | 1 | ||||
-rw-r--r-- | src/shared/machine-image.c | 14 |
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; |