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 
0

1 Answer 1

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 \" 1: Reads Completed : %9d\n\", \$1 printf \" 2: Reads Merged : %9d\n\", \$2 printf \" 3: Read Sectors : %9d %6d MiB %9d KiB %d bytes\n\", \$3, rsm, rsk, rs printf \" 4: Read ms : %9d\n\", \$4 printf \" 5: Writes Completed : %9d\n\", \$5 printf \" 6: Writes Merged : %9d\n\", \$6 printf \" 7: Write Sectors : %9d %6d MiB %9d KiB %d bytes\n\", \$7, wsm, wsk, rs printf \" 8: Write ms : %9d\n\", \$8 printf \" 9: I/Os in progress : %9d\n\", \$9 printf \"10: I/O ms : %9d\n\", \$10 printf \"11: I/O ms weighted : %9d\n\", \$11 printf \"\n\nFILE <%d> %s:\n\", inode, dev_path system(\"sudo debugfs -R '\''cat <\"inode\">'\'' \"dev_path\" | xxd -a -c 32\") } "' "$fn_stat" 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.