12

If we create a swapfile with fallocate we are told that the file contains holes and therefore the operation is halted.

What are these holes?

  • Is it unallocated disk space, which makes the whole file allocation a hole itself? Like this:
  • block1 -> empty
  • block2 -> empty
  • block3 -> empty

or

  • is it the blocks preallocated contains holes in between, and therefore they are not contiguous? Like this:
  • block1
  • block2
  • hole in block3 [occupied by other file in the disk]
  • block4

Test

fallocate -l 100MB /swap
chmod 600 /swap
mkswap /swap
swapon /swap

Output

swapon: swapfile has holes
swapon: /swap: swapon failed: Invalid argument
Stephen Kitt
  • 434,908
Nelssen
  • 295
  • 1
    Use filefrag -e myfile to see the extents in the file. Modern filesystems are based on extents, not blockmaps, so there will be one big extent (start + length) not a separate record for each filesystem block. (Or better on XFS use xfs_bmap -vpl myfile for more detailed info which distinguishes unwritten but pre-allocated extents from sparse hole) – Peter Cordes May 12 '19 at 17:40
  • Thank you @PeterCordes, that information about extents vs blocks is valuable to me – Nelssen May 13 '19 at 09:58
  • 1
    This may help. It explains what a hole is. What is a sparse file and why do we need it? – Rick Jun 17 '20 at 05:01

1 Answers1

17

Holes in a file don’t have any block associated with them at all. A file created with fallocate can end up with no blocks associated with it, only a size. Reads from unallocated blocks always return all zeroes; writes to an unallocated block cause the file system to allocate a block (filling the hole, at least partially) before writing.

Files with holes can’t be used for swap because the kernel expects to be able to access the file’s blocks without help from the file system (once the list of blocks is determined). Any file which isn’t fully allocated (containing holes, or copy-on-write) can’t be used for swap because some writes will involve the file system.

You can see how many blocks are really used by a file with stat:

$ truncate -s 16K holes
$ stat holes
  File: holes
  Size: 16384           Blocks: 0          IO Block: 4096   regular file
Device: fd13h/64787d    Inode: 36708573    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   steve)   Gid: ( 1000/   steve)
Access: 2019-05-12 20:04:22.498258356 +0200
Modify: 2019-05-12 20:04:22.498258356 +0200
Change: 2019-05-12 20:04:22.498258356 +0200
 Birth: -

filefrag will tell you what’s allocated:

$ /usr/sbin/filefrag holes
holes: 0 extents found

Forcing partial allocation of the file will reduce the hole:

$ fallocate -z -l 8K holes
$ stat holes
  File: holes
  Size: 16384           Blocks: 16         IO Block: 4096   regular file
Device: fd13h/64787d    Inode: 36708573    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   steve)   Gid: ( 1000/   steve)
Access: 2019-05-12 20:04:22.498258356 +0200
Modify: 2019-05-12 20:10:12.520380272 +0200
Change: 2019-05-12 20:10:12.520380272 +0200
 Birth: -
$ /usr/sbin/filefrag -e holes
Filesystem type is: ef53
File size of holes is 16384 (4 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       1:  116741448.. 116741449:      2:             last,unwritten
holes: 1 extent found
Stephen Kitt
  • 434,908