]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: Make partition files NOCOW if the disk image is NOCOW
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 23 Jul 2024 19:43:13 +0000 (21:43 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 24 Jul 2024 16:58:41 +0000 (18:58 +0200)
On btrfs, reflinks into a disk image that has copy-on-write disabled
only work if the source has copy-on-write disabled as well so let's
make sure that's the case if the disk image has copy-on-write disabled.

src/partition/repart.c

index 5ba099940a0d2a7834fd1443997555c4d8cb4d12..118a369206d322e6be14b62f82dd2beb2c627e2b 100644 (file)
@@ -23,6 +23,7 @@
 #include "btrfs-util.h"
 #include "build.h"
 #include "chase.h"
+#include "chattr-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "constants.h"
@@ -3792,12 +3793,14 @@ static PartitionTarget* partition_target_free(PartitionTarget *t) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(PartitionTarget*, partition_target_free);
 
-static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
+static int prepare_temporary_file(Context *context, PartitionTarget *t, uint64_t size) {
         _cleanup_(unlink_and_freep) char *temp = NULL;
         _cleanup_close_ int fd = -EBADF;
         const char *vt;
+        unsigned attrs = 0;
         int r;
 
+        assert(context);
         assert(t);
 
         r = var_tmp_dir(&vt);
@@ -3812,6 +3815,16 @@ static int prepare_temporary_file(PartitionTarget *t, uint64_t size) {
         if (fd < 0)
                 return log_error_errno(fd, "Failed to create temporary file: %m");
 
+        r = read_attr_fd(fdisk_get_devfd(context->fdisk_context), &attrs);
+        if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                return log_error_errno(r, "Failed to read file attributes of %s: %m", arg_node);
+
+        if (FLAGS_SET(attrs, FS_NOCOW_FL)) {
+                r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+                if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
+                        return log_error_errno(r, "Failed to disable copy-on-write on %s: %m", temp);
+        }
+
         if (ftruncate(fd, size) < 0)
                 return log_error_errno(errno, "Failed to truncate temporary file to %s: %m",
                                        FORMAT_BYTES(size));
@@ -3882,7 +3895,7 @@ static int partition_target_prepare(
          * reflinking support, we can take advantage of this and just reflink the result into the image.
          */
 
-        r = prepare_temporary_file(t, size);
+        r = prepare_temporary_file(context, t, size);
         if (r < 0)
                 return r;
 
@@ -5831,6 +5844,7 @@ static int split_name_resolve(Context *context) {
 }
 
 static int context_split(Context *context) {
+        unsigned attrs = 0;
         int fd = -EBADF, r;
 
         if (!arg_split)
@@ -5857,13 +5871,23 @@ static int context_split(Context *context) {
                 if (partition_type_defer(&p->type))
                         continue;
 
-                fdt = open(p->split_path, O_WRONLY|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW|O_CREAT|O_EXCL, 0666);
+                if (fd < 0) {
+                        assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
+
+                        r = read_attr_fd(fd, &attrs);
+                        if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                                return log_error_errno(r, "Failed to read file attributes of %s: %m", arg_node);
+                }
+
+                fdt = xopenat_full(
+                                AT_FDCWD,
+                                p->split_path,
+                                O_WRONLY|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW|O_CREAT|O_EXCL,
+                                attrs & FS_NOCOW_FL ? XO_NOCOW : 0,
+                                0666);
                 if (fdt < 0)
                         return log_error_errno(fdt, "Failed to open split partition file %s: %m", p->split_path);
 
-                if (fd < 0)
-                        assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
-
                 if (lseek(fd, p->offset, SEEK_SET) < 0)
                         return log_error_errno(errno, "Failed to seek to partition offset: %m");
 
@@ -6661,10 +6685,15 @@ static int context_crypttab(Context *context) {
 
 static int context_minimize(Context *context) {
         const char *vt = NULL;
+        unsigned attrs = 0;
         int r;
 
         assert(context);
 
+        r = read_attr_fd(context->backing_fd, &attrs);
+        if (r < 0 && !ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                return log_error_errno(r, "Failed to read file attributes of %s: %m", arg_node);
+
         LIST_FOREACH(partitions, p, context->partitions) {
                 _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
                 _cleanup_(unlink_and_freep) char *temp = NULL;
@@ -6711,13 +6740,18 @@ static int context_minimize(Context *context) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate temporary file path: %m");
 
+                fd = xopenat_full(
+                                AT_FDCWD,
+                                temp,
+                                O_CREAT|O_EXCL|O_CLOEXEC|O_RDWR|O_NOCTTY,
+                                attrs & FS_NOCOW_FL ? XO_NOCOW : 0,
+                                0600);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
+
                 if (fstype_is_ro(p->format))
                         fs_uuid = p->fs_uuid;
                 else {
-                        fd = open(temp, O_CREAT|O_EXCL|O_CLOEXEC|O_RDWR|O_NOCTTY, 0600);
-                        if (fd < 0)
-                                return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
-
                         /* This may seem huge but it will be created sparse so it doesn't take up any space
                          * on disk until written to. */
                         if (ftruncate(fd, 1024ULL * 1024ULL * 1024ULL * 1024ULL) < 0)
@@ -6768,7 +6802,7 @@ static int context_minimize(Context *context) {
                 /* Read-only filesystems are minimal from the first try because they create and size the
                  * loopback file for us. */
                 if (fstype_is_ro(p->format)) {
-                        assert(fd < 0);
+                        fd = safe_close(fd);
 
                         fd = open(temp, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
                         if (fd < 0)
@@ -6904,18 +6938,19 @@ static int context_minimize(Context *context) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate temporary file path: %m");
 
-                r = touch(temp);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to create temporary file: %m");
+                fd = xopenat_full(
+                                AT_FDCWD,
+                                temp,
+                                O_RDONLY|O_CLOEXEC|O_CREAT|O_NONBLOCK,
+                                attrs & FS_NOCOW_FL ? XO_NOCOW : 0,
+                                0600);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
 
                 r = partition_format_verity_hash(context, p, temp, dp->copy_blocks_path);
                 if (r < 0)
                         return r;
 
-                fd = open(temp, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
-                if (fd < 0)
-                        return log_error_errno(errno, "Failed to open temporary file %s: %m", temp);
-
                 if (fstat(fd, &st) < 0)
                         return log_error_errno(errno, "Failed to stat temporary file: %m");