如何在 Linux 中跟踪块设备?

cle*_*om0 4 linux tail

我正在尝试获取 /dev/sda2 的最后 1024 个字节。当我这样做时sudo tail -c 1024 /dev/sda2 | hd,提示会一直挂起,直到我按下 Ctrl-C。但是,当 I 时tail -c 1024 ddfilecopyofsda2 | hd,我立即得到文件最后 1024 个字节的不错输出。我在这里读到(https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system)“块设备通常是可查找的, “那我错过了什么?

Del*_*tik 10

这是获取块设备的最后 1024 个字节的一种方法:

last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE
Run Code Online (Sandbox Code Playgroud)

替换DEVICE为设备路径。在你的情况下,你会使用/dev/sda2.


现在来回答一个更有趣的问题……

为什么要tail -c 1024 /dev/sda2搜索整个磁盘?

原因是如何tail实施。当tail知道它正在读取的文件的大小时,它确切地知道要查找多少。否则,它必须一直读取文件或流以找出要倒计时多远。

使用管道,这是有道理的,例如cat /dev/sda2 | tail -c 1024. tail正在以流的形式接收内容,无法知道数据何时结束。

您可能希望tail -c 1024 /dev/sda2能够计算出 的大小/dev/sda2,但实际上,在tail查找时/dev/sda2,它是作为块设备而不是常规文件打开的。

实现细节是tail调用fstat()获取有关文件的信息。

tail 在常规文件上

stracetail打开文件示例的相关部分:

21:30:27 open("/var/log/syslog", O_RDONLY) = 3
21:30:27 fstat(3, {st_dev=makedev(0, 22), st_ino=4715, st_mode=S_IFREG|0640, st_nlink=1, st_uid=104, st_gid=4, st_blksize=131072, st_blocks=54, st_size=175500, st_atime=2017/11/10-21:28:39.243133398, st_mtime=2017/11/10-21:30:20.438031639, st_ctime=2017/11/10-21:30:20.438031639}) = 0
21:30:27 lseek(3, 0, SEEK_CUR)          = 0
21:30:27 lseek(3, 174476, SEEK_SET)     = 174476
Run Code Online (Sandbox Code Playgroud)

fstat()提供st_size=175500. 现在tail只需要倒数 1024 个字节:

175500 - 1024 = 174476

......这正是tail它的作用:

lseek(3, 174476, SEEK_SET)     = 174476
Run Code Online (Sandbox Code Playgroud)

tail 在块设备上

fstat() 这次不返回大小!:

21:29:43 open("/dev/sda", O_RDONLY)     = 3
21:29:43 fstat(3, {st_dev=makedev(0, 6), st_ino=17488, st_mode=S_IFBLK|0660, st_nlink=1, st_uid=0, st_gid=6, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2017/11/10-09:21:15.643998960, st_mtime=2017/11/10-09:21:15.555998962, st_ctime=2017/11/10-09:21:15.555998962}) = 0
Run Code Online (Sandbox Code Playgroud)

没有st_sizetail无法知道要查找多远,所以它默认读取整个块设备直到结束。

这就是为什么您通常应该使用块设备工具dd来操作块设备而不是用于常规文件的工具,例如tail.


您可能会问,“如何blockdev --getsize64快速获取块设备的大小?”

这是sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda

21:53:15 open("/dev/sda", O_RDONLY)     = 3
21:53:15 ioctl(3, BLKGETSIZE64, [512110190592]) = 0
Run Code Online (Sandbox Code Playgroud)

blockdev用于获取块设备ioctls,并BLKGETSIZE64获取块设备的大小。


至于为什么 tail不这样做BLKGETSIZE64,我不知道。的源代码显示:

#define IS_TAILABLE_FILE_TYPE(Mode) \
  (S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode))
Run Code Online (Sandbox Code Playgroud)

我只从那行中知道,没有S_ISBLK(),作者并不是要tail支持块设备。

  • 我希望我能对这个答案点赞 5 次!谢谢你这么详细的解释! (2认同)