Xfs: find files on the first 1 TB

inodexfs

I have been hit by xfs' No space left on device. According to the FAQ:

http://xfs.org/index.php/XFS_FAQ#Q:_Why_do_I_receive_No_space_left_on_device_after_xfs_growfs.3F

The only way to fix this is to move data around to free up space
below 1TB. Find your oldest data (i.e. that was around before even
the first grow) and move it off the filesystem (move, not copy).
Then if you copy it back on, the data blocks will end up above 1TB
and that should leave you with plenty of space for inodes below 1TB.

But how do I identify the data to move? I cannot go by age, because the first 10 TB was filled the same day using rsync.

I have tried:

xfs_db -r -c "blockget -i 1 -n -v" /dev/md3

But I only seem to get the basename of the file and not the full path to the file. And since a lot of my files are called the same (but in different dirs) then that is not very useful. Also it seems to give me more information that just inode 1.

I have a feeling that I can use xfs_db and get that to tell me what files are using blocks in the first 1 TB, but I have been unable to see how.

(By using the mount option inode64 the file system will not give No space left on device, but if you later forget to use mount option inode64 then you will get No space left on device again. I would like to avoid the mount option inode64 as the filesystem may be mounted by other people on other systems, and they will forget that and thus get a surprising No space left on device).

Best Answer

Quick & Dirty example (remove inline comments, adjust numbers):

# select filesystem
find / -xdev -type f -print0 | \
  xargs -0r -I{} \
    # execute xfs_bmap on every file (and prefix output with path for later processing)
    sh -c "xfs_bmap -v {} | awk '{gsub(/\.\./,\" \"); print \"{}: \" \$0}'" | \
    # remove some cruft
    awk -F: '$4 != ""{print $1 " " $4}' | \
    # print line if last block < 1TB/512B/block and size (in 512B blocks) > 100.
    awk '$3 < 1024*1024*1024*1024/512 && $7 > 100{print}'