Fun with sparse files

Let's create a 1 gig sparse file:

~ # cd /tmp
tmp # ./sparse bla.img 1000000000
tmp # 
/tmp is a 4 GB tmpfs on a Gentoo box running Linux 3.5.0 x86_64. sparse (the tool to create the sparse file named bla.img) was compiled using cc -o sparse sparse.c. You might download sparse.c.
tmp # ls -l bla.img ; ls -s bla.img 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:18 bla.img
4 bla.img
tmp # 
That's what I expected. File size is 1 GB, actual size is 4 KiB.
tmp # losetup /dev/loop0 bla.img 
tmp # ls -l bla.img ; ls -s bla.img 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:18 bla.img
332 bla.img
tmp # 
Attaching the sparse file as a loop device consumes 328 KiB.
tmp # mkfs.ext4 /dev/loop0 
mke2fs 1.42.5 (29-Jul-2012)
Discarding device blocks: done                            
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
61056 inodes, 244140 blocks
12207 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=251658240
8 block groups
32768 blocks per group, 32768 fragments per group
7632 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

tmp # ls -l bla.img ; ls -s bla.img 
tmp # -rw-r--r-- 1 root root 1000000000 Sep  1 15:20 bla.img
16976 bla.img
tmp # 
Ext4 metadata consumes almost 17 MiB.
tmp # ls -l bla.img ; ls -s bla.img 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:21 bla.img
16976 bla.img
tmp # 
Mounting is for free.
tmp # dd if=/dev/zero of=/mnt/foo.bar bs=1M count=80 oflag=sync
80+0 records in
80+0 records out
83886080 bytes (84 MB) copied, 0.0894017 s, 938 MB/s
tmp # ls -l bla.img ; ls -s bla.img ; ls -l /mnt/foo.bar ; ls -s /mnt/foo.bar 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:25 bla.img
98896 bla.img
-rw-r--r-- 1 root root 83886080 Sep  1 15:25 /mnt/foo.bar
81920 /mnt/foo.bar
tmp # 
Writing a 80 MiB file to the ext4 filesystem extends the sparse file by exactly 80 MiB.
tmp # rm /mnt/foo.bar 
tmp # ls -l bla.img ; ls -s bla.img
/mnt/foo.bar 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:25 bla.img
98896 bla.img
tmp # 
Removing a file doesn't release any allocated blocks.
tmp # ls -l bla.img ; ls -s bla.img ; ls -l /mnt/foo.bar ; ls -s /mnt/foo.bar 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:53 bla.img
98896 bla.img
-rw-r--r-- 1 root root 83886080 Sep  1 15:53 /mnt/foo.bar
81920 /mnt/foo.bar
tmp # 
Recreating the file after several minutes doesn't consume any additional space.
tmp # rm /mnt/foo.bar 
core tmp # dd if=/dev/zero of=/mnt/foo.bar bs=1M count=80 oflag=sync
80+0 records in
80+0 records out
83886080 bytes (84 MB) copied, 0.0860126 s, 975 MB/s
tmp # ls -l bla.img ; ls -s bla.img ; ls -l /mnt/foo.bar ; ls -s /mnt/foo.bar 
-rw-r--r-- 1 root root 1000000000 Sep  1 15:54 bla.img
139856 bla.img
-rw-r--r-- 1 root root 83886080 Sep  1 15:54 /mnt/foo.bar
81920 /mnt/foo.bar
tmp # 
But recreating it within a minute requires 50% additional space.
tmp # umount /mnt
tmp # ls -l bla.img ; ls -s bla.img                                           
-rw-r--r-- 1 root root 1000000000 Sep  1 16:01 bla.img
139856 bla.img
tmp # 
Again, unmounting is for free.
tmp # mkfs.ext4 /dev/loop0 
mke2fs 1.42.5 (29-Jul-2012)
Discarding device blocks: done                            
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
61056 inodes, 244140 blocks
12207 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=251658240
8 block groups
32768 blocks per group, 32768 fragments per group
7632 inodes per group
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

tmp # ls -l bla.img ; ls -s bla.img
-rw-r--r-- 1 root root 1000000000 Sep  1 16:02 bla.img
16976 bla.img
tmp # 
Recreating the filesystem resets the space consumption. I didn't expect that.