summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2024-07-23 21:43:13 +0200
committerDaan De Meyer <daan.j.demeyer@gmail.com>2024-07-24 18:58:41 +0200
commitb9c0b6c011fd0b30d3484d21d70cef6f5ae2fc0a (patch)
treeb6bcc67aa2349371e6e3bf3ac435015baeebcda3 /src
parentfs-util: Add XO_NOCOW flag (diff)
downloadsystemd-b9c0b6c011fd0b30d3484d21d70cef6f5ae2fc0a.tar.xz
systemd-b9c0b6c011fd0b30d3484d21d70cef6f5ae2fc0a.zip
repart: Make partition files NOCOW if the disk image is NOCOW
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.
Diffstat (limited to 'src')
-rw-r--r--src/partition/repart.c71
1 files changed, 53 insertions, 18 deletions
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 5ba099940a..118a369206 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -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");