]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
btrfs-util: Add btrfs_subvol_snapshot_at() 27885/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 1 Jun 2023 12:59:59 +0000 (14:59 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 6 Jun 2023 12:44:02 +0000 (14:44 +0200)
src/import/export-tar.c
src/import/import-fs.c
src/import/pull-tar.c
src/nspawn/nspawn.c
src/shared/btrfs-util.c
src/shared/btrfs-util.h
src/shared/discover-image.c
src/test/test-btrfs.c

index 4aa8204983a448b1817da8e789dbd3da09e136e4..2f54cd811486b4fffcb8642b51b917b0f69c7d89 100644 (file)
@@ -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);
index 221febea19c3647eaf7f20a4e8a0ee10d5953ff1..fd79c8f01a06fef0f1d8a4d9a61f6dfc5bb3ca1c 100644 (file)
@@ -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|
index f22eb0e3a33da5ebe2d8aa4cf0b50359dda09d64..e474dffa72ec6bbb453c5fe7bc76c6d33d41a772 100644 (file)
@@ -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|
index f54e955caea81cb255c0b6fd2bcde851cd6954c6..ab61184d9f914332c6e7f2df36b476b068996e3d 100644 (file)
@@ -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,
index a3e175768b1dd1b3a6142f110ef14856f7c449e5..429e5afe117e1002c2907517c6b6a3f2eab2adb0 100644 (file)
@@ -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 = {
index 56a0169027c6cf2a9cde467e74ace9be18531b56..de38f1e45c39a8578f5e6e99c2399712ad10c083 100644 (file)
@@ -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);
index 198c975c443c85320c11e5ee7334da9f0fde1c06..d93a1cc74c2cfec74175cb31bc58edeee8738122 100644 (file)
@@ -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);
index 67acba23a79d548791b8013eeec4d08cdb7bd231..ccb1661a9142eeeab43da6bbe664ae8917eed0a0 100644 (file)
@@ -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");