summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/btrfs-util.c39
-rw-r--r--src/basic/btrfs-util.h4
-rw-r--r--src/import/pull-common.c12
-rw-r--r--src/nspawn/nspawn.c25
-rw-r--r--src/shared/machine-image.c16
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);