1

I'm trying to read the contents of a file using the file's inode.

This works fine:

echo "First line" > data.txt
sync
sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3

debugfs tells me the file contents are "First line". This part of the command gets data.txt's inode number: $(stat -c %i data.txt).

Things go awry when adding a second line:

echo "Second line" >> data.txt
sync
sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3

I still only get "First line" from debugfs. This doesn't change after adding more lines, running sync again, or retrying a couple of days later.

Why doesn't debugfs show the remainder of the file contents? Am I using debugfs the wrong way?

I can reproduce this behavior reliably with other files.


I noticed that when overwriting existing file contents with echo "New content" > data.txt, debugfs does show the new content. But adding a second line to it, will, as described above, show only the first line.


I'm on Arch Linux 5.12.3 using debugfs 1.46.2. The file system on /dev/sda3 is ext4. Calling debugfs -R "stat ..." produces the following, which seems unsuspicious to me:

Inode: 16515371   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 3923658711    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 34
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x60b639e5:71315fa0 -- Tue Jun  1 15:45:09 2021
atime: 0x60b63988:b7c456cc -- Tue Jun  1 15:43:36 2021
mtime: 0x60b639e5:71315fa0 -- Tue Jun  1 15:45:09 2021
crtime: 0x60b63988:b7c456cc -- Tue Jun  1 15:43:36 2021
Size of extra inode fields: 32
Inode checksum: 0xbfa4390e
EXTENTS:
(0):66095479

1 Answers1

3

It is due to caching. You have at least two options.

  1. Use the -D flag:

    -D  Causes debugfs to open the device using Direct I/O, bypassing the buf‐
    fer  cache.  Note that some Linux devices, notably device mapper as of
    this writing, do not support Direct I/O.
    
  2. Drop buffer cache:

    echo 1 | sudo tee /proc/sys/vm/drop_caches
    

See for example:


If you do not pass the -D flag you can still see some action by piping the result to for example xxd:

sudo debugfs -R "cat <$(stat --printf %i data.txt)>" /dev/sda3 | xxd -a -c 32

You will see that the cat'ed file is filled with zero bytes, and sometimes data (if enough has been written).

For example, after echo A >data.txt

00000000: 410a                A.

Then after for i in {1..7}; do echo A >>data.txt; done:

00000000: 410a 0000 0000 0000 0000 0000 0000 0000  A...............

You can also monitor by using something like this:

Usage: sudo ./script file_to_monitor

It launches watch with an awk script that prints statistics for the device from /sys/block in addition to print the result of cat <inode> for the file.

#!/bin/sh

if [ "$1" = "-h" ]; then printf '%s FILE\n' "$0" exit 1 fi

file="$1" inode=$(stat --printf %i "$file") dev_path="$(df -P -- "$file" | awk 'END{print $1}')" dev_name="$(lsblk -no NAME "$dev_path")" dev_core="$(lsblk -no PKNAME "$dev_path")"

if [ "$dev_core" = "loop" ]; then fn_stat=/sys/block/$dev_name/stat else fn_stat=/sys/block/$dev_core/$dev_name/stat fi

printf 'File : %s\n' "$file" printf 'Inode: %s\n' "$inode" printf 'Stat : %s\n' "$fn_stat" printf 'Dev : %s\n' "$dev_path"

printf "Continue? [yN] " >&2 read -r ans if ! [ "$ans" = "y" ] && ! [ "$ans" = "Y" ]; then exit fi

watch -n 0.2 'awk
-v inode="'$inode'"
-v dev_path="'$dev_path'"
"{ rs = $3 * 512 rsk = rs / 1024 rsm = rsk / 1024 ws = $7 * 512 wsk = ws / 1024 wsm = wsk / 1024

printf \&quot; 1: Reads  Completed   : %9d\n\&quot;, \$1
printf \&quot; 2: Reads  Merged      : %9d\n\&quot;, \$2
printf \&quot; 3: Read   Sectors     : %9d %6d MiB %9d KiB %d bytes\n\&quot;,
\$3, rsm, rsk, rs
printf \&quot; 4: Read   ms          : %9d\n\&quot;, \$4
printf \&quot; 5: Writes Completed   : %9d\n\&quot;, \$5
printf \&quot; 6: Writes Merged      : %9d\n\&quot;, \$6
printf \&quot; 7: Write  Sectors     : %9d %6d MiB %9d KiB %d bytes\n\&quot;,
\$7, wsm, wsk, rs
printf \&quot; 8: Write  ms          : %9d\n\&quot;, \$8
printf \&quot; 9: I/Os   in progress : %9d\n\&quot;, \$9
printf \&quot;10: I/O    ms          : %9d\n\&quot;, \$10
printf \&quot;11: I/O    ms weighted : %9d\n\&quot;, \$11

printf \&quot;\n\nFILE &lt;%d&gt; %s:\n\&quot;, inode, dev_path

system(\&quot;sudo debugfs -R '\''cat &lt;\&quot;inode\&quot;&gt;'\'' \&quot;dev_path\&quot; | xxd -a -c 32\&quot;)

} "' "$fn_stat"

ibuprofen
  • 2,890