I have a directory with 18 files in it, but stat and other tools report its size as 0. How is this possible?

$ \stat $PWD
  File: `/home/users/gholl/checkouts_local/FCDR_HIRS/FCDR_HIRS/analysis'
  Size: 0               Blocks: 0          IO Block: 524288 directory
Device: 14h/20d Inode: 62487444829821592  Links: 1
Access: (0755/drwxr-xr-x)  Uid: (35063/   gholl)   Gid: (26030/   users)
Access: 2018-04-09 11:38:43.574427000 +0100
Modify: 2018-04-09 11:38:43.574427000 +0100
Change: 2018-04-09 11:38:43.575000000 +0100
~/checkouts_local/FCDR_HIRS/FCDR_HIRS/analysis$ \ls -1 | wc -l

$ mount | grep homeusers on /home/users type nfs (rw,tcp,hard,intr,timeo=50,addr=

The machine is a Red Hat Enterprise Linux Server release 6.9 (Santiago). According to df -T, the filesystem type is nfs:

$ df -hT .
Filesystem    Type    Size  Used Avail Use% Mounted on
               nfs    200T  3.5T  197T   2% /home/users

I thought that the size of a directory was related to the number of files in it, as it stored their metadata. Then how can it be zero for a non-empty directory?

NB: I don't have access to the server and I don't have superuser powers, so I cannot investigate what happens server-side.

  • What happens if you run stat on the NFS server? What operating system does the NFS server run? What filesystem does it use? – Wouter Verhelst Apr 9 '18 at 16:20
  • @WouterVerhelst I don't have access to the server. I've edited the question to include this information. – gerrit Apr 9 '18 at 16:40
  • Please show mount | grep homeusers. – Yurij Goncharuk Apr 9 '18 at 16:46
  • @YurijGoncharuk Added. – gerrit Apr 9 '18 at 17:40

It depends on the underlying filesystem on the NFS server. Ultimately, this comes down to a somewhat odd and not well known bit of POSIX semantics, namely that the st_blocks field returned by stat() does not include blocks allocated as metadata, only blocks allocated as data.

This distinction originated back when the standard filesystems on UNIX systems used statically allocated inode tables, which meant that there was a fixed amount of space used by every filesystem object for metadata (and therefore it made no sense to worry about counting that in file size since it didn't contribute to total space usage of the file (because the inode table was statically allocated, that space was already reserved) On these filesystems, directory entries were not stored as metadata, but as regularly allocated blocks in the main part of the filesystem (IOW, directory entries are treated just like file contents, not as metadata). This is why most directories on older UNIX systems are some multiple of 4kB in size, as that's the block size for most UNIX filesystems, and it's also why stat() and tools that use it report file-sizes without accounting for metadata.

On a lot of newer filesystems however, things are rather different. Space for metadata is dynamically allocated instead of being a static table of fixed-size entries, and directory entries are treated as metadata. As a result, depending on the exact system and filesystem, directories may show as having zero apparent size, or may show zero disk usage (as reported by stat or du) but a small sub-kB apparent size as reported by ls. BTRFS is a good example of a filesystem that falls into the second category, the apparent size of a directory is a function of how many entries are in it and how long their names are, while the reported on-disk size you get back from stat() is always zero.

Your Answer

