From fab4ef72625c067683bace339ad7ac208a330918 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 1 Jun 2023 14:59:59 +0200 Subject: [PATCH] btrfs-util: Add btrfs_subvol_snapshot_at() --- src/import/export-tar.c | 2 +- src/import/import-fs.c | 6 ++-- src/import/pull-tar.c | 6 ++-- src/nspawn/nspawn.c | 30 ++++++++-------- src/shared/btrfs-util.c | 71 +++++++++++++++---------------------- src/shared/btrfs-util.h | 11 ++---- src/shared/discover-image.c | 14 ++++---- src/test/test-btrfs.c | 12 ++++--- 8 files changed, 68 insertions(+), 84 deletions(-) diff --git a/src/import/export-tar.c b/src/import/export-tar.c index 4aa8204983a..2f54cd81148 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -293,7 +293,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType return r; /* Let's try to make a snapshot, if we can, so that the export is atomic */ - r = btrfs_subvol_snapshot_fd(sfd, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot_at(sfd, NULL, AT_FDCWD, e->temp_path, BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_RECURSIVE); if (r < 0) { log_debug_errno(r, "Couldn't create snapshot %s of %s, not exporting atomically: %m", e->temp_path, path); e->temp_path = mfree(e->temp_path); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index 221febea19c..fd79c8f01a0 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -194,9 +194,9 @@ static int import_fs(int argc, char *argv[], void *userdata) { BLOCK_SIGNALS(SIGINT, SIGTERM); if (arg_btrfs_subvol) - r = btrfs_subvol_snapshot_fd_full( - fd, - dest, + r = btrfs_subvol_snapshot_at_full( + fd, NULL, + AT_FDCWD, dest, BTRFS_SNAPSHOT_FALLBACK_COPY| BTRFS_SNAPSHOT_FALLBACK_DIRECTORY| BTRFS_SNAPSHOT_RECURSIVE| diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index f22eb0e3a33..e474dffa72e 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -237,9 +237,9 @@ static int tar_pull_make_local_copy(TarPull *i) { return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p); if (i->flags & PULL_BTRFS_SUBVOL) - r = btrfs_subvol_snapshot( - i->final_path, - t, + r = btrfs_subvol_snapshot_at( + AT_FDCWD, i->final_path, + AT_FDCWD, t, (i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)| BTRFS_SNAPSHOT_FALLBACK_COPY| BTRFS_SNAPSHOT_FALLBACK_DIRECTORY| diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index f54e955caea..ab61184d9f9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -5564,13 +5564,13 @@ static int run(int argc, char *argv[]) { { BLOCK_SIGNALS(SIGINT); - 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 | - BTRFS_SNAPSHOT_SIGINT); + r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np, + (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | + BTRFS_SNAPSHOT_FALLBACK_COPY | + BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | + BTRFS_SNAPSHOT_RECURSIVE | + BTRFS_SNAPSHOT_QUOTA | + BTRFS_SNAPSHOT_SIGINT); } if (r == -EINTR) { log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np); @@ -5605,14 +5605,14 @@ static int run(int argc, char *argv[]) { { BLOCK_SIGNALS(SIGINT); - 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 | - BTRFS_SNAPSHOT_SIGINT); + r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_template, AT_FDCWD, 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 | + BTRFS_SNAPSHOT_SIGINT); } if (r == -EEXIST) log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index a3e175768b1..429e5afe117 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -1506,22 +1506,37 @@ static int subvol_snapshot_children( return 0; } -int btrfs_subvol_snapshot_fd_full( - int old_fd, - const char *new_path, +int btrfs_subvol_snapshot_at_full( + int dir_fdf, + const char *from, + int dir_fdt, + const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata) { _cleanup_free_ char *subvolume = NULL; - _cleanup_close_ int new_fd = -EBADF; + _cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF; int r; - assert(old_fd >= 0); - assert(new_path); + assert(dir_fdf >= 0 || dir_fdf == AT_FDCWD); + assert(dir_fdt >= 0 || dir_fdt == AT_FDCWD); + assert(to); + + old_fd = xopenat(dir_fdf, from, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY, /* xopen_flags = */ 0, /* mode = */ 0); + if (old_fd < 0) + return old_fd; - r = btrfs_is_subvol_fd(old_fd); + new_fd = chase_and_openat(dir_fdt, to, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_CLOEXEC, &subvolume); + if (new_fd < 0) + return new_fd; + + r = validate_subvolume_name(subvolume); + if (r < 0) + return r; + + r = btrfs_is_subvol_at(dir_fdf, from); if (r < 0) return r; if (r == 0) { @@ -1531,10 +1546,10 @@ int btrfs_subvol_snapshot_fd_full( if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY)) return -EISDIR; - r = btrfs_subvol_make(new_path); + r = btrfs_subvol_make_fd(new_fd, subvolume); if (ERRNO_IS_NOT_SUPPORTED(r) && (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) + if (mkdirat(new_fd, subvolume, 0755) < 0) return -errno; plain_directory = true; @@ -1542,8 +1557,8 @@ int btrfs_subvol_snapshot_fd_full( return r; r = copy_directory_at_full( - old_fd, NULL, - AT_FDCWD, new_path, + dir_fdf, from, + new_fd, subvolume, COPY_MERGE_EMPTY| COPY_REFLINK| COPY_SAME_MOUNT| @@ -1564,9 +1579,9 @@ int btrfs_subvol_snapshot_fd_full( * 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, NULL); + (void) chattr_at(new_fd, subvolume, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL); } else { - r = btrfs_subvol_set_read_only(new_path, true); + r = btrfs_subvol_set_read_only_at(new_fd, subvolume, true); if (r < 0) goto fallback_fail; } @@ -1575,41 +1590,13 @@ int btrfs_subvol_snapshot_fd_full( return 0; fallback_fail: - (void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); + (void) rm_rf_at(new_fd, subvolume, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); return r; } - r = extract_subvolume_name(new_path, &subvolume); - if (r < 0) - return r; - - new_fd = open_parent(new_path, O_CLOEXEC, 0); - if (new_fd < 0) - return new_fd; - return subvol_snapshot_children(old_fd, new_fd, subvolume, 0, flags); } -int btrfs_subvol_snapshot_full( - const char *old_path, - const char *new_path, - BtrfsSnapshotFlags flags, - copy_progress_path_t progress_path, - copy_progress_bytes_t progress_bytes, - void *userdata) { - - _cleanup_close_ int old_fd = -EBADF; - - assert(old_path); - assert(new_path); - - old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); - if (old_fd < 0) - return -errno; - - return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, progress_path, progress_bytes, userdata); -} - int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) { struct btrfs_ioctl_search_args args = { diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h index 56a0169027c..de38f1e45c3 100644 --- a/src/shared/btrfs-util.h +++ b/src/shared/btrfs-util.h @@ -74,14 +74,9 @@ int btrfs_subvol_make_fd(int fd, const char *subvolume); int btrfs_subvol_make_fallback(const char *path, mode_t); -int btrfs_subvol_snapshot_fd_full(int old_fd, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); -static inline int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags) { - return btrfs_subvol_snapshot_fd_full(old_fd, new_path, flags, NULL, NULL, NULL); -} - -int btrfs_subvol_snapshot_full(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); -static inline int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags) { - return btrfs_subvol_snapshot_full(old_path, new_path, flags, NULL, NULL, NULL); +int btrfs_subvol_snapshot_at_full(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata); +static inline int btrfs_subvol_snapshot_at(int dir_fdf, const char *from, int dir_fdt, const char *to, BtrfsSnapshotFlags flags) { + return btrfs_subvol_snapshot_at_full(dir_fdf, from, dir_fdt, to, flags, NULL, NULL, NULL); } int btrfs_subvol_remove_at(int dir_fd, const char *path, BtrfsRemoveFlags flags); diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 198c975c443..d93a1cc74c2 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -923,13 +923,13 @@ 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_FALLBACK_DIRECTORY | - BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE | - BTRFS_SNAPSHOT_RECURSIVE | - BTRFS_SNAPSHOT_QUOTA); + r = btrfs_subvol_snapshot_at(AT_FDCWD, i->path, AT_FDCWD, 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); diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index 67acba23a79..ccb1661a914 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -54,11 +54,11 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to write file: %m"); - r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", 0); + r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest2", 0); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); - r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY); + r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxtest", AT_FDCWD, "/xxxtest3", BTRFS_SNAPSHOT_READ_ONLY); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); @@ -74,7 +74,8 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); - r = btrfs_subvol_snapshot("/etc", "/etc2", BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY); + r = btrfs_subvol_snapshot_at(AT_FDCWD, "/etc", AT_FDCWD, "/etc2", + BTRFS_SNAPSHOT_READ_ONLY|BTRFS_SNAPSHOT_FALLBACK_COPY); if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); @@ -115,7 +116,7 @@ int main(int argc, char *argv[]) { if (mkdir("/xxxrectest/mnt", 0755) < 0) log_error_errno(errno, "Failed to make directory: %m"); - r = btrfs_subvol_snapshot("/xxxrectest", "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxrectest", AT_FDCWD, "/xxxrectest2", BTRFS_SNAPSHOT_RECURSIVE); if (r < 0) log_error_errno(r, "Failed to snapshot subvolume: %m"); @@ -151,7 +152,8 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to set up quota limit: %m"); - r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA); + r = btrfs_subvol_snapshot_at(AT_FDCWD, "/xxxquotatest", AT_FDCWD, "/xxxquotatest2", + BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA); if (r < 0) log_error_errno(r, "Failed to set up snapshot: %m"); -- 2.47.3