ArticlesRocky Linux

Preventing Sparse Allocation in ext4 Loopback Filesystems

Introduction

When creating ext4 filesystems on loopback devices (image files), you may encounter unexpected behavior where a fully allocated image file becomes sparse after mounting. This article explains why this happens and how to prevent it.

Problem

When creating an ext4 filesystem on a fully allocated file and then mounting it, some blocks may be unexpectedly optimized or trimmed, potentially resulting in a sparse file. This behavior can be problematic in situations where you need the backing file to remain fully allocated to ensure the mounted filesystem stays robust against ENOSPC (no space left on device) errors on the host filesystem.

Symptoms

The issue can be observed through the following sequence:

  1. Create an allocated file of roughly 5 GB:

    fallocate -l 5368709120 cache.img
    
  2. Confirm the allocation:

    stat "--printf=%b\n" cache.img
    # Output: 10485784
    
  3. Create an ext4 filesystem:

    mkfs.ext4 -E nodiscard cache.img
    
  4. Check allocation again:

    stat "--printf=%b\n" cache.img
    # Output: 10485784
    
  5. Mount the filesystem:

    mount -o defaults,nodiscard cache.img /mnt/test
    
  6. After a short period, check allocation:

    stat "--printf=%b\n" cache.img
    # Output: 10321936
    

Notice that the number of allocated blocks may decrease after mounting, indicating that the file has become sparse despite using the nodiscard option.

Resolution

To prevent ext4 from sparsifying the loopback file during the first mount, use the following options when creating the filesystem:

mkfs.ext4 -E nodiscard,lazy_itable_init=0,lazy_journal_init=0 cache.img

These options disable the lazy initialization features that defer part of the filesystem creation to the kernel at first mount time, which can cause the sparsification.

Root Cause

The issue can occur because ext4's default behavior includes lazy initialization of the inode table and journal. When using the default settings:

  1. mkfs.ext4 creates the filesystem but defers some initialization work
  2. During the first mount, the kernel completes the initialization
  3. As part of this process, certain I/O patterns or optimizations may lead to blocks being treated as sparse, depending on the host filesystem and configuration

The lazy_itable_init=0 and lazy_journal_init=0 options force more complete initialization during filesystem creation, helping to prevent deferred work that could result in sparsification.

Notes

  • This behavior is specific to ext4 filesystems. Other filesystems like XFS do not typically exhibit this behavior.
  • The nodiscard mount option alone may be insufficient to prevent this behavior in all cases.
  • While disabling lazy initialization can prevent sparsification, it may increase the time required to create the filesystem.

References

Rocky Linux Filesystem Guide
ext4 mkfs documentation
ext4 mount options