[root@xx]# cat -n create_extents.sh 
     1  #!/bin/bash
     3  if [ $# -ne 2 ]
     4  then
     5          echo "$0 [filename] [size in kb]"
     6          exit 1
     7  fi
     9  filename=$1
    10  size=$2
    11  i=0
    13  while [ $i -lt $size ]
    14  do
    15          i=`expr $i + 7`
    16          echo -n "$i" | dd of=$1 bs=1024 seek=$i
    17  done

so I did

sudo ./create_extents.sh  /device3/test70 70

Then, I use debugfs "stat" command to check it,

Inode: 13 Type: regular Mode: 0644 Flags: 0x80000

Generation: 2638566511    Version: 0x00000000:00000001
User:     0   Group:     0   Size: 71682
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 88
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x53292990:042e685c -- Wed Mar 19 01:22:24 2014
 atime: 0x5329298f:edd4dc60 -- Wed Mar 19 01:22:23 2014
 mtime: 0x53292990:042e685c -- Wed Mar 19 01:22:24 2014
crtime: 0x5329298f:edd4dc60 -- Wed Mar 19 01:22:23 2014
Size of extra inode fields: 28
(ETB0):33803, (1):33825, (3):33827, (5):33829, (7-8):33831-33832, (10):33834, (12):33836, (14-15):33838-33839, (17):33841

Why it takes so many blocks? and the place is so scattered..? My block size is 4k. I know that ext4 tries hard to keep locality for one file.


  • I am not sure why. Funny thing is if you do cat /device3/test70 > /device3/test70.cat stat reports 144 blockcount instead of 88... which is by the way the same blockcount as if you would have created a similar sized file with: dd if=/dev/zero of=/device3/test70.dd bs=1024 count=70 (although the file generated with this last command will be 2 bytes less than the one generated by your script)
    – Huygens
    Mar 19, 2014 at 12:43

1 Answer 1


The “Blockcount” value is the i_blocks field of the struct ext2_inode. This is the value that is returned to the stat syscall in the st_blocks field. For historical reasons, the unit of that field is 512-byte blocks — this was the filesystem block size on early Unix filesystems, but now it's just an arbitrary unit. You can see the value being incremented and decremented depending solely on the file size further down in fs/stat.c.

You can see this same value by running stat /device3/test70 (“Blocks: 88”).

The file in fact contains 18 blocks, which is as expected with a 4kB block size (the file is 71682 bytes long, not sparse, and 17 × 4096 \< 71682 ≤ 18 × 4096).

It probably comes out as surprising that the number of 512-byte blocks is 88 and not 141 (because 140 × 512 \< 71682 ≤ 141 × 512) or 144 (which is 18 × 4096/512). The reason has to do with the calculation in fs/stat.c that I linked to above. Your script creates this file by seeking repeatedly past the end, and for the i_blocks field calculation, the file is sparse — there are whole 512-byte blocks that are never written to and thus not counted in i_blocks. (However, there isn't any storage block that's fully sought past, so the file is not actually sparse.)

If you copy the file, you'll see that the copy has 144 such blocks as expected (note that you need to run cp --sparse=never, because GNU cp tries to be clever and seeks when it sees expanses of zeroes).

As to the number of extents, creating a file the way you do by successive seeks past the end is not a situation that filesystems tend to be optimized for. I think that the heuristics in the filesystem driver first decide that you're creating a small file, so start by reserving space one block at a time; later, when the file grows, the heuristics start reserving multiple blocks at a time. If you create a larger file, you should see increasing large extents. But I don't know ext4 in enough detail to be sure.

  • this helps. Very deep explanation. thank you @Gilles
    – BufBills
    Mar 20, 2014 at 2:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .