Hi all, I discovered that making a file sparse with "fallocate -d filename" fails on the last block of a file, because - usually being partial - the system call only zeroes that part instead of deallocating the block. See man fallocate(2) - section "Deallocating file space". The expected call is punching the whole block beyond eof, which doesn't change the file length because of flag FALLOC_FL_KEEP_SIZE. The following commands illustrate this (all on Debian buster with a real existing file). Behaviour with fallocate from system: file gets fragmented user:~/dev/util-linux$ cp /usr/lib/locale/C.UTF-8/LC_CTYPE . user:~/dev/util-linux$ /usr/sbin/filefrag -e ./LC_CTYPE Filesystem type is: 9123683e File size of ./LC_CTYPE is 200752 (50 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 49: 22403653.. 22403702: 50: last,eof ./LC_CTYPE: 1 extent found user:~/dev/util-linux$ fallocate -v -d ./LC_CTYPE ./LC_CTYPE: 48 B (48 bytes) converted to sparse holes. user:~/dev/util-linux$ /usr/sbin/filefrag -e ./LC_CTYPE Filesystem type is: 9123683e File size of ./LC_CTYPE is 200752 (50 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 48: 22403653.. 22403701: 49: 1: 49.. 49: 22385666.. 22385666: 1: 22403702: last,eof ./LC_CTYPE: 2 extents found user:~/dev/util-linux$ du -s ./LC_CTYPE 200 ./LC_CTYPE Behaviour with fixed fallocate: file becomes sparse user:~/dev/util-linux$ cp /usr/lib/locale/C.UTF-8/LC_CTYPE . user:~/dev/util-linux$ ./fallocate -v -d ./LC_CTYPE ./LC_CTYPE: 48 B (48 bytes) converted to sparse holes. user:~/dev/util-linux$ /usr/sbin/filefrag -e ./LC_CTYPE Filesystem type is: 9123683e File size of ./LC_CTYPE is 200752 (50 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 48: 22346286.. 22346334: 49: last ./LC_CTYPE: 1 extent found user:~/dev/util-linux$ du -s ./LC_CTYPE 196 ./LC_CTYPE Please consider the attached patch. I also tested with other files containing real holes (instead of a notch) that function is preserved. Kind regards, Gero
>From 7b3e0a3921ca7c84fa3913b2bb916be938dfe04a Mon Sep 17 00:00:00 2001 From: Gero Treuner <gero@xxxxxx> Date: Thu, 10 Sep 2020 21:43:03 +0200 Subject: [PATCH] fallocate: fix --dig-holes at end of files --- sys-utils/fallocate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c index 014b94624..ba97092fc 100644 --- a/sys-utils/fallocate.c +++ b/sys-utils/fallocate.c @@ -264,8 +264,11 @@ static void dig_holes(int fd, off_t file_off, off_t len) off += rsz; } if (hole_sz) { + off_t alloc_sz = hole_sz; + if (off >= end) + alloc_sz += st.st_blksize; /* meet block boundary */ xfallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, - hole_start, hole_sz); + hole_start, alloc_sz); ct += hole_sz; } file_off = off; -- 2.20.1