diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/btrfs-util.c | 39 | ||||
-rw-r--r-- | src/basic/btrfs-util.h | 4 | ||||
-rw-r--r-- | src/import/pull-common.c | 12 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 25 | ||||
-rw-r--r-- | src/shared/machine-image.c | 16 |
5 files changed, 65 insertions, 31 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 656bb13719..5f9e21dcba 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -20,6 +20,7 @@ #include <errno.h> #include <fcntl.h> #include <inttypes.h> +#include <linux/fs.h> #include <linux/loop.h> #include <stddef.h> #include <stdio.h> @@ -38,6 +39,7 @@ #include "alloc-util.h" #include "btrfs-ctree.h" #include "btrfs-util.h" +#include "chattr-util.h" #include "copy.h" #include "fd-util.h" #include "fileio.h" @@ -45,6 +47,7 @@ #include "macro.h" #include "missing.h" #include "path-util.h" +#include "rm-rf.h" #include "selinux-util.h" #include "smack-util.h" #include "sparse-endian.h" @@ -1718,28 +1721,46 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag if (r < 0) return r; if (r == 0) { + bool plain_directory = false; + + /* If the source isn't a proper subvolume, fail unless fallback is requested */ if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY)) return -EISDIR; r = btrfs_subvol_make(new_path); - if (r < 0) + if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) { + /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */ + if (mkdir(new_path, 0755) < 0) + return r; + + plain_directory = true; + } else if (r < 0) return r; r = copy_directory_fd(old_fd, new_path, true); - if (r < 0) { - (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); - return r; - } + if (r < 0) + goto fallback_fail; if (flags & BTRFS_SNAPSHOT_READ_ONLY) { - r = btrfs_subvol_set_read_only(new_path, true); - if (r < 0) { - (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); - return r; + + if (plain_directory) { + /* Plain directories have no recursive read-only flag, but something pretty close to + * it: the IMMUTABLE bit. Let's use this here, if this is requested. */ + + if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE) + (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL); + } else { + r = btrfs_subvol_set_read_only(new_path, true); + if (r < 0) + goto fallback_fail; } } return 0; + + fallback_fail: + (void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); + return r; } r = extract_subvolume_name(new_path, &subvolume); diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 1d852d502c..04a2e1274b 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -45,10 +45,12 @@ typedef struct BtrfsQuotaInfo { } BtrfsQuotaInfo; typedef enum BtrfsSnapshotFlags { - BTRFS_SNAPSHOT_FALLBACK_COPY = 1, + BTRFS_SNAPSHOT_FALLBACK_COPY = 1, /* If the source isn't a subvolume, reflink everything */ BTRFS_SNAPSHOT_READ_ONLY = 2, BTRFS_SNAPSHOT_RECURSIVE = 4, BTRFS_SNAPSHOT_QUOTA = 8, + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 16, /* If the destination doesn't support subvolumes, reflink/copy instead */ + BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 32, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */ } BtrfsSnapshotFlags; typedef enum BtrfsRemoveFlags { diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 2ae2a4174c..5ddc0c56f4 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -144,12 +144,12 @@ int pull_make_local_copy(const char *final, const char *image_root, const char * if (force_local) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA); - if (r == -ENOTTY) { - r = copy_tree(final, p, false); - if (r < 0) - return log_error_errno(r, "Failed to copy image: %m"); - } else if (r < 0) + r = btrfs_subvol_snapshot(final, p, + BTRFS_SNAPSHOT_QUOTA| + BTRFS_SNAPSHOT_FALLBACK_COPY| + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY| + BTRFS_SNAPSHOT_RECURSIVE); + if (r < 0) return log_error_errno(r, "Failed to create local image: %m"); log_info("Created new local image '%s'.", local); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 29755a9e36..2770770cd0 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4070,7 +4070,7 @@ int main(int argc, char *argv[]) { _cleanup_fdset_free_ FDSet *fds = NULL; int r, n_fd_passed, loop_nr = -1, ret = EXIT_SUCCESS; char veth_name[IFNAMSIZ] = ""; - bool secondary = false, remove_subvol = false, remove_image = false; + bool secondary = false, remove_directory = false, remove_image = false; pid_t pid = 0; union in_addr_union exposed = {}; _cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; @@ -4152,7 +4152,12 @@ int main(int argc, char *argv[]) { goto finish; } - r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); + r = btrfs_subvol_snapshot(arg_directory, np, + (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | + BTRFS_SNAPSHOT_FALLBACK_COPY | + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | + BTRFS_SNAPSHOT_RECURSIVE | + BTRFS_SNAPSHOT_QUOTA); if (r < 0) { log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory); goto finish; @@ -4162,7 +4167,7 @@ int main(int argc, char *argv[]) { arg_directory = np; np = NULL; - remove_subvol = true; + remove_directory = true; } else { r = image_path_lock(arg_directory, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock); @@ -4176,7 +4181,13 @@ int main(int argc, char *argv[]) { } if (arg_template) { - r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); + r = btrfs_subvol_snapshot(arg_template, arg_directory, + (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | + BTRFS_SNAPSHOT_FALLBACK_COPY | + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | + BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE | + BTRFS_SNAPSHOT_RECURSIVE | + BTRFS_SNAPSHOT_QUOTA); if (r == -EEXIST) { if (!arg_quiet) log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); @@ -4359,12 +4370,12 @@ finish: loop_remove(loop_nr, &image_fd); - if (remove_subvol && arg_directory) { + if (remove_directory && arg_directory) { int k; - k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); + k = rm_rf(arg_directory, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); if (k < 0) - log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory); + log_warning_errno(k, "Cannot remove '%s', ignoring: %m", arg_directory); } if (remove_image && arg_image) { diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index baf8713242..712aff65b9 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -609,14 +609,14 @@ int image_clone(Image *i, const char *new_name, bool read_only) { 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); - 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) + r = btrfs_subvol_snapshot(i->path, new_path, + (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | + BTRFS_SNAPSHOT_FALLBACK_COPY | + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | + BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE | + BTRFS_SNAPSHOT_RECURSIVE | + BTRFS_SNAPSHOT_QUOTA); + 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); |