diff --git a/man/repart.d.xml b/man/repart.d.xml index 7d3dc4e04b..d0992830b7 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -679,6 +679,22 @@ + + Discard= + + Takes a boolean argument. The default is no if + is used for the invocation of systemd-repart + or if Integrity=inline is set. It is yes otherwise. + + If set to yes, when creating the LUKS2 superblock for the partition, the + allow-discards activation flag will be set so that future activations will allow + discards by default. + + This option has no effect if the partition already exists or if Encrypt=off is used. + + + + Verity= diff --git a/src/repart/repart.c b/src/repart/repart.c index 7dbcfd6d58..5b4d801958 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -472,6 +472,7 @@ typedef struct Partition { char *compression; char *compression_level; uint64_t fs_sector_size; + int discard; int add_validatefs; CopyFiles *copy_files; @@ -728,6 +729,7 @@ static Partition *partition_new(Context *c) { .last_percent = UINT_MAX, .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, .fs_sector_size = UINT64_MAX, + .discard = -1, }; return p; @@ -851,6 +853,7 @@ static void partition_foreignize(Partition *p) { p->verity = VERITY_OFF; p->add_validatefs = false; p->fs_sector_size = UINT64_MAX; + p->discard = -1; partition_mountpoint_free_many(p->mountpoints, p->n_mountpoints); p->mountpoints = NULL; @@ -2882,6 +2885,7 @@ static int partition_read_definition( { "Partition", "SupplementFor", config_parse_string, 0, &p->supplement_for_name }, { "Partition", "AddValidateFS", config_parse_tristate, 0, &p->add_validatefs }, { "Partition", "FileSystemSectorSize", config_parse_fs_sector_size, 0, &p->fs_sector_size }, + { "Partition", "Discard", config_parse_tristate, 0, &p->discard }, {} }; _cleanup_free_ char *filename = NULL; @@ -3032,6 +3036,14 @@ static int partition_read_definition( "SupplementFor= cannot be combined with CopyBlocks=/Encrypt=/Verity="); } + if (p->encrypt == ENCRYPT_OFF && p->discard > 0) + log_syntax(NULL, LOG_WARNING, path, 1, 0, + "Discard=yes has no effect with Encrypt=off."); + + if (p->encrypt != ENCRYPT_OFF && p->integrity == INTEGRITY_INLINE && p->discard > 0) + return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), + "Integrity=inline is incompatible with Discard=yes."); + /* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */ if ((partition_designator_is_verity_hash(p->type.designator) || partition_designator_is_verity_sig(p->type.designator) || @@ -5225,6 +5237,22 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta if (r < 0) return log_error_errno(r, "Failed to LUKS2 format future partition: %m"); + bool allow_discards = p->integrity != INTEGRITY_INLINE && (arg_discard ? p->discard != 0 : p->discard > 0); + if (allow_discards) { + uint32_t flags; + + r = sym_crypt_persistent_flags_get(cd, CRYPT_FLAGS_ACTIVATION, &flags); + if (r < 0) + return log_error_errno(r, "Failed to get persistent activation flags for %s: %m", node); + + if (!FLAGS_SET(flags, CRYPT_ACTIVATE_ALLOW_DISCARDS)) { + flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + r = sym_crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, flags); + if (r < 0) + return log_error_errno(r, "Failed to set persistent activation flags for %s: %m", node); + } + } + if (p->encrypted_volume && p->encrypted_volume->fixate_volume_key) { _cleanup_free_ char *key_id = NULL, *hash_option = NULL; @@ -5543,7 +5571,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta dm_name, NULL, /* volume_key_size= */ volume_key_size, - (arg_discard && p->integrity != INTEGRITY_INLINE ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0) | CRYPT_ACTIVATE_PRIVATE); + (allow_discards ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0) | CRYPT_ACTIVATE_PRIVATE); if (r < 0) return log_error_errno(r, "Failed to activate LUKS superblock: %m"); diff --git a/src/shared/cryptsetup-util.c b/src/shared/cryptsetup-util.c index 5058bca3fd..2ffd1b63bb 100644 --- a/src/shared/cryptsetup-util.c +++ b/src/shared/cryptsetup-util.c @@ -42,6 +42,8 @@ DLSYM_PROTOTYPE(crypt_keyslot_destroy) = NULL; DLSYM_PROTOTYPE(crypt_keyslot_max) = NULL; DLSYM_PROTOTYPE(crypt_load) = NULL; DLSYM_PROTOTYPE(crypt_metadata_locking) = NULL; +DLSYM_PROTOTYPE(crypt_persistent_flags_get) = NULL; +DLSYM_PROTOTYPE(crypt_persistent_flags_set) = NULL; DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase) = NULL; DLSYM_PROTOTYPE(crypt_reencrypt_run); DLSYM_PROTOTYPE(crypt_resize) = NULL; @@ -302,6 +304,8 @@ int dlopen_cryptsetup(void) { DLSYM_ARG(crypt_keyslot_max), DLSYM_ARG(crypt_load), DLSYM_ARG(crypt_metadata_locking), + DLSYM_ARG(crypt_persistent_flags_get), + DLSYM_ARG(crypt_persistent_flags_set), DLSYM_ARG(crypt_reencrypt_init_by_passphrase), DLSYM_ARG(crypt_reencrypt_run), DLSYM_ARG(crypt_resize), diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h index e9be8249fa..2e3ffe4c9e 100644 --- a/src/shared/cryptsetup-util.h +++ b/src/shared/cryptsetup-util.h @@ -30,6 +30,8 @@ extern DLSYM_PROTOTYPE(crypt_keyslot_destroy); extern DLSYM_PROTOTYPE(crypt_keyslot_max); extern DLSYM_PROTOTYPE(crypt_load); extern DLSYM_PROTOTYPE(crypt_metadata_locking); +extern DLSYM_PROTOTYPE(crypt_persistent_flags_get); +extern DLSYM_PROTOTYPE(crypt_persistent_flags_set); extern DLSYM_PROTOTYPE(crypt_reencrypt_init_by_passphrase); extern DLSYM_PROTOTYPE(crypt_reencrypt_run); extern DLSYM_PROTOTYPE(crypt_resize); diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh index f25cf42c4b..546df29f44 100755 --- a/test/units/TEST-58-REPART.sh +++ b/test/units/TEST-58-REPART.sh @@ -380,6 +380,8 @@ $imgs/zzz7 : start= 6291416, size= 131072, type=3B8F8425-20E0-4F3B-907F loop="$(losetup -P --show --find "$imgs/zzz")" udevadm wait --timeout=60 --settle "${loop:?}p7" + cryptsetup luksDump "${loop}p7" | grep 'Flags:[[:space:]]*allow-discards' >/dev/null + volume="test-repart-$RANDOM" touch "$imgs/empty-password" @@ -396,6 +398,50 @@ $imgs/zzz7 : start= 6291416, size= 131072, type=3B8F8425-20E0-4F3B-907F PASSWORD="" systemd-dissect "$imgs/zzz" -M "$imgs/mount" udevadm info /dev/disk/by-label/schrupfel | grep ID_FS_TYPE=crypto_LUKS >/dev/null systemd-dissect -U "$imgs/mount" + + echo "*** 7. Testing Discard=no ***" + + tee "$defs/extra4.conf" </dev/null + losetup -d "$loop" } testcase_dropin() {