Skip to content

Filesystem Settings

A flexBlock device is an ordinary Linux block device, so any filesystem works on it. A few settings matter more than usual, because the volume sits behind a write-back cache and its cold data lives in object storage.

Format ext4 with lazy inode table initialization turned off:

Terminal window
sudo mkfs.ext4 -E lazy_itable_init=0 /dev/ublkb0

Otherwise the kernel zeroes inode tables in the background after the first mount, while the volume is already serving.

CommandFlagDefaultMeaning
init--logical-block-size <512|4096>4096Advertised block size. Fixed for the volume’s life.

With 4096, the kernel aligns and splits guest I/O on page boundaries. Choose 512 only for software that insists on it; sub-page I/O is served buffered.

Returning freed space matters more on a write-back-cached volume than on a plain SSD.

ApproachBehavior
discard mount optionEvery extent a delete frees is applied as it happens. A dirty chunk whose pages are all freed is dropped before it is ever uploaded, and its object is deleted. A fully freed chunk that has left the cache is not fetched back from object storage when its space is reused, because it no longer has an object.
fstrim.timerBatches the deletes and is lighter on a busy bucket. But between trims, deleted data that was dirty is still uploaded, and space reused after the chunk left the cache pays a chunk fetch, usually at its next flush, unless the new writes cover the whole chunk.

While a freed chunk is still in the cache, reusing it is cheap either way. A chunk freed only in part keeps its object, though freeing part of an evicted chunk brings it back dirty and costs a fetch and an upload at its next flush.

The XFS example mounts with discard; the ext4 example relies on fstrim.timer:

Terminal window
sudo systemctl enable --now fstrim.timer

Set the fsck pass (the last fstab field) to 0. A full check on a cold cache reads all of the filesystem’s metadata from the bucket. ext4 still replays its journal at mount.

FlagDefaultMeaning
--read-ahead <SIZE>32MKernel read-ahead for the exported device, a whole number of KiB and of logical blocks, up to 64M. 0 disables.

The default is 32 MiB whatever the chunk size, so buffered sequential readers pull whole chunks instead of making a round trip per page. For cold sequential reads, flexBlock also prefetches chunks itself; see Sequential prefetch.

The kernel’s writeback throttling (wbt_lat_usec, 2 ms on SSD-class devices) stays at its default, because it keeps reads fast while buffered writers are busy.

With the cache saturated and completions taking hundreds of milliseconds, though, it can hold buffered writeback, fsync and the journal to a trickle for minutes while direct I/O proceeds. For such mixed workloads, write 0 after each start:

Terminal window
echo 0 | sudo tee /sys/block/ublkb0/queue/wbt_lat_usec

This keeps writeback steady at the cost of read latency under buffered writes.

  • btrfs, OpenZFS and LUKS work on the device as on any other. LVM and mdadm work too. Close LUKS, LVM and md mappings before stopping the daemon, since it refuses to stop while device-mapper or another kernel user holds the device.
  • ZFS pools. ublk devices have no /dev/disk/by-id entries, so import a ZFS pool with zpool import -d /dev.