Files
使用 debugfs cat 讀取過時的文件數據
我正在嘗試使用文件的 inode 讀取文件的內容。
這工作正常:
echo "First line" > data.txt sync sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3
debugfs 告訴我文件內容是“第一行”。這部分命令獲取 data.txt 的 inode 號:
$(stat -c %i data.txt)
。添加第二行時出現問題:
echo "Second line" >> data.txt sync sudo debugfs -R "cat <$(stat -c %i data.txt)>" /dev/sda3
我仍然只能從調試文件中獲得“第一行”。
sync
在添加更多行、再次執行或幾天后重試後,這不會改變。為什麼 debugfs 不顯示文件內容的其餘部分?我是否以錯誤的方式使用 debugfs?
我可以使用其他文件可靠地重現此行為。
我注意到當用 覆蓋現有文件內容時
echo "New content" > data.txt
,debugfs 確實顯示了新內容。但是,如上所述,添加第二行將只顯示第一行。我在 Arch Linux 5.12.3 上使用 debugfs 1.46.2。文件系統
/dev/sda3
是ext4。呼叫debugfs -R "stat ..."
會產生以下結果,這對我來說似乎並不可疑: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
這是由於記憶體。你至少有兩個選擇。
- 使用
-D
標誌:-D 使 debugfs 使用 Direct I/O 打開設備,繞過緩衝區 fer記憶體。請注意,某些 Linux 設備,尤其是設備映射器 本文不支持 Direct I/O。
- 丟棄緩衝區記憶體:
迴聲 1 | sudo tee /proc/sys/vm/drop_caches
參見例如:
- 如何清空 Linux 系統上的緩衝區和記憶體?
- https://www.kernel.org/doc/Documentation/sysctl/vm.txt
- /proc/sys/vm/ HTML 的文件(我更喜歡純文字變體,但是嘿;)
如果您不傳遞
-D
標誌,您仍然可以通過將結果傳遞到例如xxd
:sudo debugfs -R "cat <$(stat --printf %i data.txt)>" /dev/sda3 | xxd -a -c 32
您將看到*
cat
*’ed 文件充滿了零字節,有時還有數據(如果已寫入足夠多的數據)。例如,之後
echo A >data.txt
00000000: 410a A.
然後之後
for i in {1..7}; do echo A >>data.txt; done
:00000000: 410a 0000 0000 0000 0000 0000 0000 0000 A...............
您還可以使用以下方式進行監控:
用法:
sudo ./script file_to_monitor
watch
它使用一個腳本啟動,該腳本除了列印文件的結果外,還列印awk
設備的統計資訊。/sys/block``cat <inode>
#!/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"