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() {