diff --git a/man/repart.d.xml b/man/repart.d.xml index a53057ffa1..eb628ffc16 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -1007,6 +1007,25 @@ + + FileSystemSectorSize= + + Controls the sector size for any file system, LUKS volume or Verity volume formatted + on this partition. Expects a power of 2 as value, and must be equal or larger than 512. Typically + it's recommended to set the file system sector size to 4096, even on 512 sector disks (and in + particular for images that are only ever intended to be stored as file on disks), in order to + optimize performance. However, for compatibility with foreign operating systems or firmware it might + be advisable to use the native sector size of the backing disk. + + If unspecified and operating on a block device, defaults to the native sector size of the + device. If unspecified and operating on a disk image file defaults to 4096. + + Regardless of what is configured here, or which default is picked, the file system sector size + is always increased to be equal or larger than the disk sector size. + + + + diff --git a/src/repart/repart.c b/src/repart/repart.c index de138c15d3..0dc9b7eb0e 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -409,6 +409,7 @@ typedef struct Partition { uint64_t verity_hash_block_size; char *compression; char *compression_level; + uint64_t fs_sector_size; int add_validatefs; CopyFiles *copy_files; @@ -461,7 +462,7 @@ typedef struct Context { uint64_t start, end, total; struct fdisk_context *fdisk_context; - uint64_t sector_size, grain_size, fs_sector_size; + uint64_t sector_size, grain_size, default_fs_sector_size; sd_id128_t seed; @@ -609,6 +610,7 @@ static Partition *partition_new(void) { .add_validatefs = -1, .last_percent = UINT_MAX, .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, + .fs_sector_size = UINT64_MAX, }; return p; @@ -724,6 +726,7 @@ static void partition_foreignize(Partition *p) { p->growfs = -1; p->verity = VERITY_OFF; p->add_validatefs = false; + p->fs_sector_size = UINT64_MAX; partition_mountpoint_free_many(p->mountpoints, p->n_mountpoints); p->mountpoints = NULL; @@ -909,6 +912,23 @@ static bool context_drop_or_foreignize_one_priority(Context *context) { return true; } +static uint64_t partition_fs_sector_size(const Context *c, const Partition *p) { + assert(c); + assert(p); + + uint64_t ss; + + if (p->fs_sector_size != UINT64_MAX) + /* Prefer explicitly configured value */ + ss = p->fs_sector_size; + else + /* Otherwise follow the default sector size */ + ss = c->default_fs_sector_size; + + /* never allow the fs sector size to be picked smaller than the physical sector size */ + return MAX(ss, c->sector_size); +} + static uint64_t partition_min_size(const Context *context, const Partition *p) { uint64_t sz, override_min; @@ -1731,6 +1751,45 @@ static int config_parse_block_size( return 0; } +static int config_parse_fs_sector_size( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint64_t *fssecsz = ASSERT_PTR(data), parsed; + int r; + + assert(rvalue); + + if (isempty(rvalue)) { + *fssecsz = UINT64_MAX; + return 0; + } + + r = parse_size(rvalue, 1024, &parsed); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse size value: %s", rvalue); + + if (!ISPOWEROF2(parsed)) + return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), + "Value not a power of 2: %s", rvalue); + + /* NB: we make no upper restriction here, since the maximum logical sector sizes file systems support + * vary greatly, and can be much larger than 4K. (That's also the reason we dont't use + * parse_sector_size() here.) */ + + *fssecsz = parsed; + return 0; +} + static int config_parse_fstype( const char *unit, const char *filename, @@ -2483,6 +2542,7 @@ static int partition_read_definition(Partition *p, const char *path, const char { "Partition", "CompressionLevel", config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, &p->compression_level }, { "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 }, {} }; _cleanup_free_ char *filename = NULL; @@ -3256,7 +3316,7 @@ static int context_load_partition_table(Context *context) { if (S_ISREG(st.st_mode) && st.st_size == 0) { /* Use the fallback values if we have no better idea */ context->sector_size = fdisk_get_sector_size(c); - context->fs_sector_size = fs_secsz; + context->default_fs_sector_size = fs_secsz; context->grain_size = 4096; return /* from_scratch = */ true; } @@ -3290,7 +3350,7 @@ static int context_load_partition_table(Context *context) { * larger */ grainsz = secsz < 4096 ? 4096 : secsz; - log_debug("Sector size of device is %lu bytes. Using filesystem sector size of %" PRIu64 " and grain size of %" PRIu64 ".", secsz, fs_secsz, grainsz); + log_debug("Sector size of device is %lu bytes. Using default filesystem sector size of %" PRIu64 " and grain size of %" PRIu64 ".", secsz, fs_secsz, grainsz); switch (arg_empty) { @@ -3539,7 +3599,7 @@ add_initial_free_area: context->end = last_lba; context->total = nsectors; context->sector_size = secsz; - context->fs_sector_size = fs_secsz; + context->default_fs_sector_size = fs_secsz; context->grain_size = grainsz; context->fdisk_context = TAKE_PTR(c); @@ -4597,7 +4657,7 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta const char *node = partition_target_path(target); struct crypt_params_luks2 luks_params = { .label = strempty(ASSERT_PTR(p)->new_label), - .sector_size = ASSERT_PTR(context)->fs_sector_size, + .sector_size = partition_fs_sector_size(context, p), .data_device = offline ? node : NULL, }; struct crypt_params_reencrypt reencrypt_params = { @@ -6347,10 +6407,17 @@ static int context_mkfs(Context *context) { if (r < 0) return r; - r = make_filesystem(partition_target_path(t), p->format, strempty(p->new_label), root, - p->fs_uuid, partition_mkfs_flags(p), - context->fs_sector_size, p->compression, p->compression_level, - extra_mkfs_options); + r = make_filesystem( + partition_target_path(t), + p->format, + strempty(p->new_label), + root, + p->fs_uuid, + partition_mkfs_flags(p), + partition_fs_sector_size(context, p), + p->compression, + p->compression_level, + extra_mkfs_options); if (r < 0) return r; @@ -7925,10 +7992,10 @@ static int context_update_verity_size(Context *context) { assert_se(dp = p->siblings[VERITY_DATA]); if (p->verity_data_block_size == UINT64_MAX) - p->verity_data_block_size = context->fs_sector_size; + p->verity_data_block_size = partition_fs_sector_size(context, p); if (p->verity_hash_block_size == UINT64_MAX) - p->verity_hash_block_size = context->fs_sector_size; + p->verity_hash_block_size = partition_fs_sector_size(context, p); uint64_t sz; if (dp->size_max != UINT64_MAX) { @@ -8061,16 +8128,17 @@ static int context_minimize(Context *context) { if (r < 0) return r; - r = make_filesystem(d ? d->node : temp, - p->format, - strempty(p->new_label), - root, - fs_uuid, - partition_mkfs_flags(p), - context->fs_sector_size, - p->compression, - p->compression_level, - extra_mkfs_options); + r = make_filesystem( + d ? d->node : temp, + p->format, + strempty(p->new_label), + root, + fs_uuid, + partition_mkfs_flags(p), + partition_fs_sector_size(context, p), + p->compression, + p->compression_level, + extra_mkfs_options); if (r < 0) return r; @@ -8152,16 +8220,17 @@ static int context_minimize(Context *context) { return log_error_errno(r, "Failed to make loopback device of %s: %m", temp); } - r = make_filesystem(d ? d->node : temp, - p->format, - strempty(p->new_label), - root, - p->fs_uuid, - partition_mkfs_flags(p), - context->fs_sector_size, - p->compression, - p->compression_level, - extra_mkfs_options); + r = make_filesystem( + d ? d->node : temp, + p->format, + strempty(p->new_label), + root, + p->fs_uuid, + partition_mkfs_flags(p), + partition_fs_sector_size(context, p), + p->compression, + p->compression_level, + extra_mkfs_options); if (r < 0) return r;