Re: Understanding reported block count for sparse files

From: Konstantin Belousov <kostikbel_at_gmail.com>
Date: Thu, 24 Jul 2025 02:49:16 UTC
On Wed, Jul 23, 2025 at 12:52:11PM -0600, Alan Somers wrote:
> On Wed, Jul 23, 2025 at 12:33 PM Roman Bogorodskiy <novel@freebsd.org>
> wrote:
> 
> > Hi,
> >
> > I'm porting a test from Linux, and this test checks the allocated block
> > count for the sparse file. Its expectation is that the block count
> > should be close to zero.
> >
> > To isolate things, it roughly does the following:
> >
> > Linux:
> >
> > $ truncate -s +52428800 test.raw
> > $ stat test.raw
> >   File: test.raw
> >   Size: 52428800        Blocks: 0          IO Block: 4096   regular file
> > Device: 252,0   Inode: 25218599    Links: 1
> > Access: (0644/-rw-r--r--)  Uid: ( 1000/   novel)   Gid: ( 1000/   novel)
> > Context: unconfined_u:object_r:user_home_t:s0
> > Access: 2025-07-23 14:20:31.640547511 -0400
> > Modify: 2025-07-23 14:20:31.642105574 -0400
> > Change: 2025-07-23 14:20:31.642105574 -0400
> >  Birth: 2025-07-23 14:20:31.640547511 -0400
> >
> > It reports 0 blocks.
> > Filesystem here is xfs.
> >
> > FreeBSD:
> >
> > $ truncate -s +52428800 test.raw
> > $ stat -f "%z %k %b" test.raw
> > 52428800 32768 128
> >
> > This reports 128 blocks. Filesystem here is UFS.
> >
> > What's reason behind this difference?
> >
> > Thanks,
> > Roman
> 
> 
> That "Blocks" figure comes from the "st_blocks" field, returned by
> VOP_STAT.  It is entirely up to the file system what to put in that field.
> For example, if the file system is compressed, should st_blocks describe
> the blocks used before or after compression?  ZFS reports blocks after
> compression, but IIRC btrfs reports blocks before compression.  Both are
> legal.
> 
> In this very specific case I can tell you why you are seeing this
> difference.  UFS organizes files in a tree of indirect blocks.  The tree
> can be up to 4 levels high, IIRC.  So what's probably happening is that UFS
> is actually allocating all of the L2 and/or L1 blocks for the file, even
> though it's totally sparse, but not allocating any L0 blocks.  If you
> really want to know exactly what's going on, we can probably explore the
> file in detail with filesystems/fuse-ufs.
> 
> XFS, OTOH, is different.  It's an extent-based file system.  There's no
> such thing as indirect blocks.  So when you create a huge but sparse file
> in XFS, all it needs to allocate is the inode.  The number of metadata
> blocks is determined not so much by the file's size as by its
> fragmentation.  It's technically possible, if the file is fully
> defragmented, to represent a 1 TB file with no metadata blocks except for
> the inode.  But unlikely in practice.  You could try using
> filesystems/xfuse or filesystems/lkl to see what that XFS file system looks
> like when mounted on FreeBSD, too.

UFS always allocates (partial) block for the last byte of the file.