如何使用其 inode 找出文件的 LBA 范围?

slm*_*slm 9 filesystems

在回答标题为:我使用什么命令查看文件系统中文件的开始和结束块的U&L 问题时,我试图弄清楚是否可以使用它的 inode 来确定文件的 LBA。

我的回答确定我可以将其hdparm用作查找 LBA 的一种方法:

$ sudo hdparm --fibmap afile 

afile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0  282439184  282439191          8
Run Code Online (Sandbox Code Playgroud)

但我很好奇是否有某种方法使用文件的 inode 来获取 LBA;不使用hdparm.

我认为可能有其他方法隐藏在工具filefrag, stat, 中debugfstune2fs但我无法将其弄明白。

谁能想到替代方案?


这是我迄今为止的一些研究,可能对那些勇敢地尝试回答这个问题的人有用。

文件碎片

我怀疑您可以使用该工具filefrag来做到这一点,特别是使用其-e开关的结果,也许通过执行一些我不太熟悉的计算来实现。

样本输出

$ filefrag -e afile
Filesystem type is: ef53
File size of afile is 20 (1 block of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       0:   35304898..  35304898:      1:             eof
afile: 1 extent found
Run Code Online (Sandbox Code Playgroud)

节点

我怀疑可能有潜力的另一种潜在方法是直接使用文件的 inode 信息,或者通过一些在互联网上记录不佳的复杂数学。

例子

首先我们找出文件的inode。我们可以使用stat命令或ls -i.

状态

$ stat afile 
  File: ‘afile’
  Size: 20          Blocks: 8          IO Block: 4096   regular file
Device: fd02h/64770d    Inode: 6560281     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/    saml)   Gid: ( 1000/    saml)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2013-12-27 18:40:12.788333778 -0500
Modify: 2013-12-27 18:40:23.103333073 -0500
Change: 2013-12-27 18:44:03.697317989 -0500
 Birth: -
Run Code Online (Sandbox Code Playgroud)

ls -i

$ ls -i 
6560281 afile
Run Code Online (Sandbox Code Playgroud)

有了 inode 信息,我们现在可以使用工具打开这个文件所在的文件系统,debugfs.

注意:要确定文件所在的文件系统,您可以使用命令df <filename>.

现在,如果我们运行debugfs并运行该命令,stat <inode #>我们可以获得包含此文件数据的范围列表。

$ sudo debugfs -R "stat <6560281>" /dev/mapper/fedora_greeneggs-home
debugfs 1.42.7 (21-Jan-2013)
Inode: 6560281   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 1999478298    Version: 0x00000000:00000001
User:  1000   Group:  1000   Size: 20
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x52be10c3:a640e994 -- Fri Dec 27 18:44:03 2013
 atime: 0x52be0fdc:bbf41348 -- Fri Dec 27 18:40:12 2013
 mtime: 0x52be0fe7:18a2f344 -- Fri Dec 27 18:40:23 2013
crtime: 0x52be0dd8:64394b00 -- Fri Dec 27 18:31:36 2013
Size of extra inode fields: 28
Extended attributes stored in inode body: 
  selinux = "unconfined_u:object_r:user_home_t:s0\000" (37)
EXTENTS:
(0):35304898
Run Code Online (Sandbox Code Playgroud)

现在我们有了上面的范围信息,这就是我迷路的地方,不知道如何继续。

参考

Sté*_*las 5

filefragdebugfs报告以文件系统块数表示的偏移量。

要获得以 512 字节为单位的偏移量,您需要乘以以 512 字节为单位的块大小。在 ext4 FS 上,块大小通常为 4k,因此需要乘以 8。

使用filefrag,您还可以使用-b 512选项以 512 字节为单位获取偏移量。

您可以使用 中的stats命令debugfs或 GNU stat获取块大小:

stat -fc%s /mount/point
Run Code Online (Sandbox Code Playgroud)

(或该文件系统中的任何文件)。

请注意,这hdparm是一个硬盘实用程序,它将尝试提供磁盘内的偏移量,而不是安装文件系统的块设备(假设块设备确实以某种方式驻留在磁盘上)。它仅适用于分区(通过将 的内容添加/sys/class/block/the-block-device/start到实际偏移量)和 md RAID 1 设备,但不适用于其他可能的磁盘支持的块设备类型,如设备映射器设备、其他 RAID 级别、dmraid 设备、循环、nbd。 .. 另请注意,旧版本hdparm依赖于 FIBMAP ioctl,它在可以使用的块设备方面受到限制,而较新版本使用 FIEMAP 之类的filefrag.

因此,例如,如果您ext2/dev/sda1.

# hdparm --fibmap /file/in/there
/file/in/there:
 filesystem blocksize 1024, begins at LBA 2048; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0     109766     109767          2
Run Code Online (Sandbox Code Playgroud)

您可以获得这两个扇区(但请注意,该文件可能仅使用其中的一部分):

dd skip=109766 count=2 if=/dev/sda # not /dev/sda1
Run Code Online (Sandbox Code Playgroud)

使用filefrag或 debugfs 时。

# filefrag -v /file/in/there
Filesystem type is: ef53
Filesystem cylinder groups is approximately 12
File size of /file/in/there is 87 (1 block, blocksize 1024)
 ext logical physical expected length flags
   0       0    53859               1 merged,eof
Run Code Online (Sandbox Code Playgroud)

你从实际的块设备中得到它:

dd bs=1024 skip=53859 count=1 if=/dev/sda1
Run Code Online (Sandbox Code Playgroud)


slm*_*slm 2

事实证明,一旦您了解了数字的来源,从范围转换为 LBA 实际上相当简单。@StephaneChazelas 的回答对于获得这种理解至关重要。

原始 debugfs 输出

使用问题中提到的以下示例。

$ sudo debugfs -R "stat <6560281>" /dev/mapper/fedora_greeneggs-home
debugfs 1.42.7 (21-Jan-2013)
Inode: 6560281   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 1999478298    Version: 0x00000000:00000001
User:  1000   Group:  1000   Size: 20
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x52be10c3:a640e994 -- Fri Dec 27 18:44:03 2013
 atime: 0x52be0fdc:bbf41348 -- Fri Dec 27 18:40:12 2013
 mtime: 0x52be0fe7:18a2f344 -- Fri Dec 27 18:40:23 2013
crtime: 0x52be0dd8:64394b00 -- Fri Dec 27 18:31:36 2013
Size of extra inode fields: 28
Extended attributes stored in inode body: 
  selinux = "unconfined_u:object_r:user_home_t:s0\000" (37)
EXTENTS:
(0):35304898
Run Code Online (Sandbox Code Playgroud)

利用范围信息,我们可以进行以下计算。但我们还需要一条额外的信息。底层文件系统的块大小。您可以使用此命令来获取它。

块大小

$ sudo tune2fs -l /dev/mapper/fedora_greeneggs-home | grep "Block size"
Block size:               4096
Run Code Online (Sandbox Code Playgroud)

从范围转换为 LBA

因此,这里要认识到的关键转换是 LBA 以 512 字节为单位,而上面debugfs报告范围数的命令是以 4096 字节块为单位报告的。

因此,4096/512 = 8。因此我们需要将范围乘以 8 将它们转换为 LBA 值。

因此,下面的数学计算将给出我们的初始 LBA:

$ calc -d
; 35304898 * 8
    282439184
; 
Run Code Online (Sandbox Code Playgroud)

那么我们的最终 LBA 是什么?为此,我们需要认识到我们的索引节点适合单个块,因此其结束范围与其开始范围相同。为了计算最终的 LBA,我们可以使用这个方程。

ending LBA = ( (extent + 1) * 8 ) - 1
Run Code Online (Sandbox Code Playgroud)

因此执行这个计算:

$ calc -d
; ( (35304898 + 1) * 8 ) - 1
    282439191
Run Code Online (Sandbox Code Playgroud)

确认结果

查看原始hdparm输出:

 byte_offset  begin_LBA    end_LBA    sectors
           0  282439184  282439191          8
Run Code Online (Sandbox Code Playgroud)

我们看到事情是匹配的。

另一个例子

只是为了确保我们这里有一个更大的文件作为第二个示例。

$ ls -i util-linux-2.19.tar.bz2 
6559005 util-linux-2.19.tar.bz2
Run Code Online (Sandbox Code Playgroud)

这是索引节点的范围。

$ sudo debugfs -R "stat <6559005>" /dev/mapper/fedora_greeneggs-home
...
EXTENTS:
(0-1068):26473396-26474464
Run Code Online (Sandbox Code Playgroud)

现在我们进行从范围到 LBA 的转换。

$ calc -d
; 26473396*8
    211787168
; (26474464+1)*8 - 1
    211795719
Run Code Online (Sandbox Code Playgroud)

我们确认了。

$ sudo hdparm --fibmap util-linux-2.19.tar.bz2 
...
 byte_offset  begin_LBA    end_LBA    sectors
           0  211787168  211795719       8552
Run Code Online (Sandbox Code Playgroud)

我们再次匹配。