Search code examples
freebsdmmap

FreeBSD ftruncate()+mmap() big hole warning


FreeBSD 13.1 manual page mmap() has the following warning:

WARNING! Extending a file with ftruncate(2), thus creating a big hole, and then filling the hole by modifying a shared mmap() can lead to severe file fragmentation. In order to avoid such fragmentation you should always pre-allocate the file's backing store by write()ing zero's into the newly extended area prior to modifying the area via your mmap(). The fragmentation problem is especially sensitive to MAP_NOSYNC pages, because pages may be flushed to disk in a totally random order.

Questions:

  1. What is this big hole; why ftruncate() has the effect of creating it; and why write() is a proposed solution to the problem?
  2. How does one efficiently zero-fill the hole after ftruncate() and before mmap()? Repeatedly calling write() sounds like more system calls that maybe necessary.
  3. Does the same problem exist on other operating systems? I find no such warning on macOS or Linux.

Solution

  • You can avoid this problem by using posix_fallocate to preallocate desired areas.

    The hole is created because files can be sparse, taking up only the space required for the actually used areas, so when using just ftruncate, the backing for the new area is virtual, it isn't reserved on disk until you allocate it or write to it.

    It applies to Linux as well, it's just not mentioned. You can expect most filesystem implementations to do similarly; often they do try to be smart, and will defragment your writes if time-wise close one to another, but can't do magic.