sysupdate: Compute temporary paths before vacuuming

We don't want to vacuum anything if we're just going to fail just
afterwards because a GPT partition label exceeds the maximum size
so let's compute the temporary paths for all transfers before we do
any vacuuming or acquiring.
This commit is contained in:
Daan De Meyer
2026-02-12 16:17:36 +01:00
committed by Yu Watanabe
parent 09b9466e8c
commit 7b9600a6b2
3 changed files with 39 additions and 26 deletions

View File

@@ -1171,7 +1171,7 @@ static int run_callout(
/* Build the filenames and paths which is normally done by transfer_acquire_instance(), but for partial
* and pending instances which are about to be installed (in which case, transfer_acquire_instance() is
* skipped). */
static int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) {
int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) {
_cleanup_free_ char *formatted_pattern = NULL, *formatted_partial_pattern = NULL, *formatted_pending_pattern = NULL;
int r;
@@ -1260,16 +1260,16 @@ static int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMe
return 0;
}
int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata) {
int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata) {
_cleanup_free_ char *digest = NULL;
char offset[DECIMAL_STR_MAX(uint64_t)+1], max_size[DECIMAL_STR_MAX(uint64_t)+1];
const char *where = NULL;
InstanceMetadata f;
Instance *existing;
int r;
assert(t);
assert(i);
assert(f);
assert(i->resource == &t->source);
assert(cb);
@@ -1282,11 +1282,6 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi
return 0;
}
/* Compute up the temporary paths */
r = transfer_compute_temporary_paths(t, i, &f);
if (r < 0)
return r;
if (RESOURCE_IS_FILESYSTEM(t->target.type)) {
r = mkdir_parents(t->temporary_partial_path, 0755);
if (r < 0)
@@ -1502,10 +1497,10 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi
assert(t->temporary_pending_path);
/* Apply file attributes if set */
if (f.mtime != USEC_INFINITY) {
if (f->mtime != USEC_INFINITY) {
struct timespec ts;
timespec_store(&ts, f.mtime);
timespec_store(&ts, f->mtime);
if (utimensat(AT_FDCWD, t->temporary_partial_path, (struct timespec[2]) { ts, ts }, AT_SYMLINK_NOFOLLOW) < 0)
return log_error_errno(errno, "Failed to adjust mtime of '%s': %m", t->temporary_partial_path);
@@ -1513,12 +1508,12 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi
need_sync = true;
}
if (f.mode != MODE_INVALID) {
if (f->mode != MODE_INVALID) {
/* Try with AT_SYMLINK_NOFOLLOW first, because it's the safe thing to do. Older
* kernels don't support that however, in that case we fall back to chmod(). Not as
* safe, but shouldn't be a problem, given that we don't create symlinks here. */
if (fchmodat(AT_FDCWD, t->temporary_partial_path, f.mode, AT_SYMLINK_NOFOLLOW) < 0 &&
(!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f.mode) < 0))
if (fchmodat(AT_FDCWD, t->temporary_partial_path, f->mode, AT_SYMLINK_NOFOLLOW) < 0 &&
(!ERRNO_IS_NOT_SUPPORTED(errno) || chmod(t->temporary_partial_path, f->mode) < 0))
return log_error_errno(errno, "Failed to adjust mode of '%s': %m", t->temporary_partial_path);
need_sync = true;
@@ -1536,7 +1531,7 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi
return log_error_errno(r, "Failed to synchronize file system backing '%s': %m", t->temporary_partial_path);
}
t->install_read_only = f.read_only;
t->install_read_only = f->read_only;
/* Rename the file from `.sysupdate.partial.<VERSION>` to `.sysupdate.pending.<VERSION>` to indicate its ready to install. */
log_debug("Renaming resource instance '%s' to '%s'.", t->temporary_partial_path, t->temporary_pending_path);
@@ -1557,28 +1552,28 @@ int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, voi
return r;
t->partition_change = PARTITION_LABEL;
if (f.partition_uuid_set) {
t->partition_info.uuid = f.partition_uuid;
if (f->partition_uuid_set) {
t->partition_info.uuid = f->partition_uuid;
t->partition_change |= PARTITION_UUID;
}
if (f.partition_flags_set) {
t->partition_info.flags = f.partition_flags;
if (f->partition_flags_set) {
t->partition_info.flags = f->partition_flags;
t->partition_change |= PARTITION_FLAGS;
}
if (f.no_auto >= 0) {
t->partition_info.no_auto = f.no_auto;
if (f->no_auto >= 0) {
t->partition_info.no_auto = f->no_auto;
t->partition_change |= PARTITION_NO_AUTO;
}
if (f.read_only >= 0) {
t->partition_info.read_only = f.read_only;
if (f->read_only >= 0) {
t->partition_info.read_only = f->read_only;
t->partition_change |= PARTITION_READ_ONLY;
}
if (f.growfs >= 0) {
t->partition_info.growfs = f.growfs;
if (f->growfs >= 0) {
t->partition_info.growfs = f->growfs;
t->partition_change |= PARTITION_GROWFS;
}

View File

@@ -66,7 +66,8 @@ int transfer_resolve_paths(Transfer *t, const char *root, const char *node);
int transfer_vacuum(Transfer *t, uint64_t space, const char *extra_protected_version);
int transfer_acquire_instance(Transfer *t, Instance *i, TransferProgress cb, void *userdata);
int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f);
int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata);
int transfer_process_partial_and_pending_instance(Transfer *t, Instance *i);
int transfer_install_instance(Transfer *t, Instance *i, const char *root);

View File

@@ -1055,6 +1055,23 @@ static int context_acquire(
log_info("Selected update '%s' for install.", us->version);
_cleanup_free_ InstanceMetadata *metadata = new0(InstanceMetadata, c->n_transfers);
if (!metadata)
return log_oom();
/* Compute up the temporary paths before vacuuming so we don't vacuum anything if we fail to compute
* any paths because of failed validations (e.g. exceeding the gpt partition label size). */
for (size_t i = 0; i < c->n_transfers; i++) {
Instance *inst = us->instances[i];
Transfer *t = c->transfers[i];
assert(inst);
r = transfer_compute_temporary_paths(t, inst, metadata + i);
if (r < 0)
return r;
}
(void) sd_notifyf(/* unset_environment= */ false,
"READY=1\n"
"X_SYSUPDATE_VERSION=%s\n"
@@ -1090,7 +1107,7 @@ static int context_acquire(
continue;
}
r = transfer_acquire_instance(t, inst, context_on_acquire_progress, c);
r = transfer_acquire_instance(t, inst, metadata + i, context_on_acquire_progress, c);
if (r < 0)
return r;
}