分类 技术 下的文章

学习如何使用链接,通过从 Linux 文件系统多个位置来访问文件,可以让日常工作变得轻松。

 title=

在我为 opensource.com 写过的关于 Linux 文件系统方方面面的文章中,包括 Linux 的 EXT4 文件系统的历史、特性以及最佳实践在 Linux 中管理设备Linux 文件系统概览用户指南:逻辑卷管理,我曾简要的提到过 Linux 文件系统一个有趣的特性,它允许用户从多个位置来访问 Linux 文件目录树中的文件来简化一些任务。

Linux 文件系统中有两种 链接 link 硬链接 hard link 软链接 soft link 。虽然二者差别显著,但都用来解决相似的问题。它们都提供了对单个文件的多个目录项(引用)的访问,但实现却大为不同。链接的强大功能赋予了 Linux 文件系统灵活性,因为一切皆是文件

举个例子,我曾发现一些程序要求特定的版本库方可运行。 当用升级后的库替代旧库后,程序会崩溃,提示旧版本库缺失。通常,库名的唯一变化就是版本号。出于直觉,我仅仅给程序添加了一个新的库链接,并以旧库名称命名。我试着再次启动程序,运行良好。程序就是一个游戏,人人都明白,每个玩家都会尽力使游戏进行下去。

事实上,几乎所有的应用程序链接库都使用通用的命名规则,链接名称中包含了主版本号,链接所指向的文件的文件名中同样包含了小版本号。再比如,程序的一些必需文件为了迎合 Linux 文件系统规范,从一个目录移动到另一个目录中,系统为了向后兼容那些不能获取这些文件新位置的程序在旧的目录中存放了这些文件的链接。如果你对 /lib64 目录做一个长清单列表,你会发现很多这样的例子。

lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.hwm -> ../../usr/share/cracklib/pw_dict.hwm 
lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.pwd -> ../../usr/share/cracklib/pw_dict.pwd 
lrwxrwxrwx.  1 root root       36 Dec  8  2016 cracklib_dict.pwi -> ../../usr/share/cracklib/pw_dict.pwi
lrwxrwxrwx.  1 root root       27 Jun  9  2016 libaccountsservice.so.0 -> libaccountsservice.so.0.0.0 
-rwxr-xr-x.  1 root root   288456 Jun  9  2016 libaccountsservice.so.0.0.0 
lrwxrwxrwx   1 root root       15 May 17 11:47 libacl.so.1 -> libacl.so.1.1.0 
-rwxr-xr-x   1 root root    36472 May 17 11:47 libacl.so.1.1.0 
lrwxrwxrwx.  1 root root       15 Feb  4  2016 libaio.so.1 -> libaio.so.1.0.1 
-rwxr-xr-x.  1 root root     6224 Feb  4  2016 libaio.so.1.0.0 
-rwxr-xr-x.  1 root root     6224 Feb  4  2016 libaio.so.1.0.1 
lrwxrwxrwx.  1 root root       30 Jan 16 16:39 libakonadi-calendar.so.4 -> libakonadi-calendar.so.4.14.26 
-rwxr-xr-x.  1 root root   816160 Jan 16 16:39 libakonadi-calendar.so.4.14.26 
lrwxrwxrwx.  1 root root       29 Jan 16 16:39 libakonadi-contact.so.4 -> libakonadi-contact.so.4.14.26 

/lib64 目录下的一些链接

在上面展示的 /lib64 目录清单列表中,文件模式第一个字母 l (小写字母 l)表示这是一个软链接(又称符号链接)。

硬链接

Linux 的 EXT4 文件系统的历史、特性以及最佳实践一文中,我曾探讨过这样一个事实,每个文件都有一个包含该文件信息的 inode,包含了该文件的位置信息。上述文章中的图2展示了一个指向 inode 的单一目录项。每个文件都至少有一个目录项指向描述该文件信息的 inode ,目录项是一个硬链接,因此每个文件至少都有一个硬链接。

如下图 1 所示,多个目录项指向了同一 inode 。这些目录项都是硬链接。我曾在三个目录项中使用波浪线 (~) 的缩写,这是用户目录的惯例表示,因此在该例中波浪线等同于 /home/user 。值得注意的是,第四个目录项是一个完全不同的目录,/home/shared,可能是该计算机上用户的共享文件目录。

fig1directory_entries.png

图 1

硬链接被限制在一个单一的文件系统中。此处的“文件系统” 是指挂载在特定挂载点上的分区或逻辑卷,此例中是 /home。这是因为在每个文件系统中的 inode 号都是唯一的。而在不同的文件系统中,如 /var/opt,会有和 /home 中相同的 inode 号。

因为所有的硬链接都指向了包含文件元信息的单一 inode ,这些属性都是文件的一部分,像所属关系、权限、到该 inode 的硬链接数目,对每个硬链接来说这些特性没有什么不同的。这是一个文件所具有的一组属性。唯一能区分这些文件的是包含在 inode 信息中的文件名。链接到同一目录中的单一文件/ inode 的硬链接必须拥有不同的文件名,这是基于同一目录下不能存在重复的文件名的事实的。

文件的硬链接数目可通过 ls -l 来查看,如果你想查看实际节点号,可使用 ls -li 命令。

符号(软)链接

硬链接和软链接(也称为 符号链接 symlink )的区别在于,硬链接直接指向属于该文件的 inode ,而软链接直接指向一个目录项,即指向一个硬链接。因为软链接指向的是一个文件的硬链接而非该文件的 inode ,所以它们并不依赖于 inode 号,这使得它们能跨越不同的文件系统、分区和逻辑卷起作用。

软链接的缺点是,一旦它所指向的硬链接被删除或重命名后,该软链接就失效了。软链接虽然还在,但所指向的硬链接已不存在。所幸的是,ls 命令能以红底白字的方式在其列表中高亮显示失效的软链接。

实验项目: 链接实验

我认为最容易理解链接用法及其差异的方法是动手搭建一个项目。这个项目应以非超级用户的身份在一个空目录下进行。我创建了 ~/temp 目录做这个实验,你也可以这么做。这么做可为项目创建一个安全的环境且提供一个新的空目录让程序运作,如此以来这儿仅存放和程序有关的文件。

初始工作

首先,在你要进行实验的目录下为该项目中的任务创建一个临时目录,确保当前工作目录(PWD)是你的主目录,然后键入下列命令。

mkdir temp

使用这个命令将当前工作目录切换到 ~/temp

cd temp

实验开始,我们需要创建一个能够链接到的文件,下列命令可完成该工作并向其填充内容。

du -h > main.file.txt

使用 ls -l 长列表命名确认文件正确地创建了。运行结果应类似于我的。注意文件大小只有 7 字节,但你的可能会有 1~2 字节的变动。

[dboth@david temp]$ ls -l 
total 4 
-rw-rw-r-- 1 dboth dboth 7 Jun 13 07:34 main.file.txt

在列表中,文件模式串后的数字 1 代表存在于该文件上的硬链接数。现在应该是 1 ,因为我们还没有为这个测试文件建立任何硬链接。

对硬链接进行实验

硬链接创建一个指向同一 inode 的新目录项,当为文件添加一个硬链接时,你会看到链接数目的增加。确保当前工作目录仍为 ~/temp。创建一个指向 main.file.txt 的硬链接,然后查看该目录下文件列表。

[dboth@david temp]$ ln main.file.txt link1.file.txt 
[dboth@david temp]$ ls -l 
total 8 
-rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 link1.file.txt 
-rw-rw-r-- 2 dboth dboth 7 Jun 13 07:34 main.file.txt

目录中两个文件都有两个链接且大小相同,时间戳也一样。这就是有一个 inode 和两个硬链接(即该文件的目录项)的一个文件。再建立一个该文件的硬链接,并列出目录清单内容。你可以建立硬链接: link1.file.txtmain.file.txt

[dboth@david temp]$ ln link1.file.txt link2.file.txt ; ls -l
total 16 
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link1.file.txt 
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 link2.file.txt 
-rw-rw-r-- 3 dboth dboth 7 Jun 13 07:34 main.file.txt

注意,该目录下的每个硬链接必须使用不同的名称,因为同一目录下的两个文件不能拥有相同的文件名。试着创建一个和现存链接名称相同的硬链接。

[dboth@david temp]$ ln main.file.txt link2.file.txt 
ln: failed to create hard link 'link2.file.txt': File exists

显然不行,因为 link2.file.txt 已经存在。目前为止我们只在同一目录下创建硬链接,接着在临时目录的父目录(你的主目录)中创建一个链接。

[dboth@david temp]$ ln main.file.txt ../main.file.txt ; ls -l ../main*
-rw-rw-r--    4 dboth dboth     7 Jun 13 07:34 main.file.txt

上面的 ls 命令显示 main.file.txt 文件确实存在于主目录中,且与该文件在 temp 目录中的名称一致。当然它们不是不同的文件,它们是同一文件的两个链接,指向了同一文件的目录项。为了帮助说明下一点,在 temp 目录中添加一个非链接文件。

[dboth@david temp]$ touch unlinked.file ; ls -l
total 12
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt
-rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt
-rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file

使用 ls 命令的 i 选项查看 inode 的硬链接号和新创建文件的硬链接号。

[dboth@david temp]$ ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 7 Jun 13 07:34 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth 0 Jun 14 08:18 unlinked.file

注意上面文件模式左边的数字 657024 ,这是三个硬链接文件所指的同一文件的 inode 号,你也可以使用 i 选项查看主目录中所创建的链接的节点号,和该值相同。而那个只有一个链接的 inode 号和其他的不同,在你的系统上看到的 inode 号或许不同于本文中的。

接着改变其中一个硬链接文件的大小。

[dboth@david temp]$ df -h > link2.file.txt ; ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

现在所有的硬链接文件大小都比原来大了,因为多个目录项都链接着同一文件。

下个实验在我的电脑上会出现这样的结果,是因为我的 /tmp 目录在一个独立的逻辑卷上。如果你有单独的逻辑卷或文件系统在不同的分区上(如果未使用逻辑卷),确定你是否能访问那个分区或逻辑卷,如果不能,你可以在电脑上挂载一个 U 盘,如果上述方式适合你,你可以进行这个实验。

试着在 /tmp 目录中建立一个 ~/temp 目录下文件的链接(或你的文件系统所在的位置)。

[dboth@david temp]$ ln link2.file.txt /tmp/link3.file.txt
ln: failed to create hard link '/tmp/link3.file.txt' => 'link2.file.txt': 
Invalid cross-device link

为什么会出现这个错误呢? 原因是每一个单独的可挂载文件系统都有一套自己的 inode 号。简单的通过 inode 号来跨越整个 Linux 文件系统结构引用一个文件会使系统困惑,因为相同的节点号会存在于每个已挂载的文件系统中。

有时你可能会想找到一个 inode 的所有硬链接。你可以使用 ls -li 命令。然后使用 find 命令找到所有硬链接的节点号。

[dboth@david temp]$ find . -inum 657024 
./main.file.txt
./link1.file.txt
./link2.file.txt

注意 find 命令不能找到所属该节点的四个硬链接,因为我们在 ~/temp 目录中查找。 find 命令仅在当前工作目录及其子目录中查找文件。要找到所有的硬链接,我们可以使用下列命令,指定你的主目录作为起始查找条件。

[dboth@david temp]$ find ~ -samefile main.file.txt 
/home/dboth/temp/main.file.txt
/home/dboth/temp/link1.file.txt
/home/dboth/temp/link2.file.txt
/home/dboth/main.file.txt

如果你是非超级用户,没有权限,可能会看到错误信息。这个命令也使用了 -samefile 选项而不是指定文件的节点号。这个效果和使用 inode 号一样且更容易,如果你知道其中一个硬链接名称的话。

对软链接进行实验

如你刚才看到的,不能跨越文件系统边界创建硬链接,即在逻辑卷或文件系统中从一个文件系统到另一个文件系统。软链接给出了这个问题的解决方案。虽然它们可以达到相同的目的,但它们是非常不同的,知道这些差异是很重要的。

让我们在 ~/temp 目录中创建一个符号链接来开始我们的探索。

[dboth@david temp]$ ln -s link2.file.txt link3.file.txt ; ls -li
total 12
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 link2.file.txt
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt -> 
link2.file.txt
657024 -rw-rw-r-- 4 dboth dboth 1157 Jun 14 14:14 main.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

拥有节点号 657024 的那些硬链接没有变化,且硬链接的数目也没有变化。新创建的符号链接有不同的 inode 号 658270。 名为 link3.file.txt 的软链接指向了 link2.file.txt 文件。使用 cat 命令查看 link3.file.txt 文件的内容。符号链接的 inode 信息以字母 l (小写字母 l)开头,意味着这个文件实际是个符号链接。

上例中软链接文件 link3.file.txt 的大小只有 14 字节。这是文本内容 link3.file.txt 的大小,即该目录项的实际内容。目录项 link3.file.txt 并不指向一个 inode ;它指向了另一个目录项,这在跨越文件系统建立链接时很有帮助。现在试着创建一个软链接,之前在 /tmp 目录中尝试过的。

[dboth@david temp]$ ln -s /home/dboth/temp/link2.file.txt 
/tmp/link3.file.txt ; ls -l /tmp/link*
lrwxrwxrwx 1 dboth dboth 31 Jun 14 21:53 /tmp/link3.file.txt -> 
/home/dboth/temp/link2.file.txt

删除链接

当你删除硬链接或硬链接所指的文件时,需要考虑一些问题。

首先,让我们删除硬链接文件 main.file.txt。注意指向 inode 的每个目录项就是一个硬链接。

[dboth@david temp]$ rm main.file.txt ; ls -li
total 8
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link2.file.txt
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt -> 
link2.file.txt
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

main.file.txt 是该文件被创建时所创建的第一个硬链接。现在删除它,仍然保留着原始文件和硬盘上的数据以及所有剩余的硬链接。要删除原始文件,你必须删除它的所有硬链接。

现在删除 link2.file.txt 硬链接文件。

[dboth@david temp]$ rm link2.file.txt ; ls -li 
total 8 
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 link1.file.txt 
658270 lrwxrwxrwx 1 dboth dboth   14 Jun 14 15:21 link3.file.txt -> 
link2.file.txt 
657024 -rw-rw-r-- 3 dboth dboth 1157 Jun 14 14:14 main.file.txt 
657863 -rw-rw-r-- 1 dboth dboth    0 Jun 14 08:18 unlinked.file

注意软链接的变化。删除软链接所指的硬链接会使该软链接失效。在我的系统中,断开的链接用颜色高亮显示,目标的硬链接会闪烁显示。如果需要修复这个损坏的软链接,你需要在同一目录下建立一个和旧链接相同名字的硬链接,只要不是所有硬链接都已删除就行。您还可以重新创建链接本身,链接保持相同的名称,但指向剩余的硬链接中的一个。当然如果软链接不再需要,可以使用 rm 命令删除它们。

unlink 命令在删除文件和链接时也有用。它非常简单且没有选项,就像 rm 命令一样。然而,它更准确地反映了删除的基本过程,因为它删除了目录项与被删除文件的链接。

写在最后

我用过这两种类型的链接很长一段时间后,我开始了解它们的能力和特质。我为我所教的 Linux 课程编写了一个实验室项目,以充分理解链接是如何工作的,并且我希望增进你的理解。

(题图: Paul Lewin,Opensource.com 修改。 CC BY-SA 2.0


作者简介:

戴维.布斯 - 戴维.布斯是 Linux 和开源倡导者,居住在北卡罗莱纳的罗列 。他在 IT 行业工作了四十年,为 IBM 工作了 20 多年的 OS/2。在 IBM 时,他在 1981 年编写了最初的 IBM PC 的第一个培训课程。他为 RedHat 教授过 RHCE 班,并曾在 MCI Worldcom、思科和北卡罗莱纳州工作。他已经用 Linux 和开源软件工作将近 20 年了。


via: https://opensource.com/article/17/6/linking-linux-filesystem

作者:David Both 译者:yongshouzhang 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

回复:amarao 在块层介绍第一部分:块 I/O 层 中提的问题

先前的文章:块层介绍第一部分:块 I/O 层

嗨,

你在这里描述的问题与块层不直接相关。这可能是一个驱动错误、可能是一个 SCSI 层错误,但绝对不是一个块层的问题。

不幸的是,报告针对 Linux 的错误是一件难事。有些开发者拒绝去看 bugzilla,有些开发者喜欢它,有些(像我这样)只能勉强地使用它。

另一种方法是发送电子邮件。为此,你需要选择正确的邮件列表,还有也许是正确的开发人员,当他们心情愉快,或者不是太忙或者不是假期时找到它们。有些人会努力回复所有,有些是完全不可预知的 - 这对我来说通常会发送一个补丁,包含一些错误报告。如果你只是有一个你自己几乎都不了解的 bug,那么你的预期响应率可能会更低。很遗憾,但这是是真的。

许多 bug 都会得到回应和处理,但很多 bug 都没有。

我不认为说没有人关心是公平的,但是没有人认为它如你想的那样重要是有可能的。如果你想要一个解决方案,那么你需要驱动它。一个驱动它的方法是花钱请顾问或者与经销商签订支持合同。我怀疑你的情况没有上面的可能。另一种方法是了解代码如何工作,并自己找到解决方案。很多人都这么做,但是这对你来说可能不是一种选择。另一种方法是在不同的相关论坛上不断提出问题,直到得到回复。坚持可以见效。你需要做好准备去执行任何你所要求的测试,可能包括建立一个新的内核来测试。

如果你能在最近的内核(4.12 或者更新)上复现这个 bug,我建议你邮件报告给 [email protected][email protected] 和我([email protected])(注意你不必订阅这些列表来发送邮件,只需要发送就行)。描述你的硬件以及如何触发问题的。

包含所有进程状态是 “D” 的栈追踪。你可以用 “cat /proc/$PID/stack” 来得到它,这里的 “$PID” 是进程的 pid。

确保避免抱怨或者说这个已经坏了好几年了以及这是多么严重不足。没有人关心这个。我们关心的是 bug 以及如何修复它。因此只要报告相关的事实就行。

尝试在邮件中而不是链接到其他地方的链接中包含所有事实。有时链接是需要的,但是对于你的脚本,它只有 8 行,所以把它包含在邮件中就行(并避免像 “fuckup” 之类的描述。只需称它为 “坏的” broken 或者类似的)。同样确保你的邮件发送的不是 HTML 格式。我们喜欢纯文本。HTML 被所有的 @vger.kernel.org 邮件列表拒绝。你或许需要配置你的邮箱程序不发送 HTML。


via: https://lwn.net/Articles/737655/

作者:neilbrown 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

此前我们介绍了如何在命令行中使用 Google 搜索。许多读者反馈说他们平时使用 Duck Duck Go,这是一个功能强大而且保密性很强的搜索引擎。

正巧,最近出现了一款能够从命令行搜索 DuckDuckGo 的工具。它叫做 ddgr(我把它读作 “dodger”),非常好用。

Googler 一样,ddgr 是一个完全开源而且非官方的工具。没错,它并不属于 DuckDuckGo。所以,如果你发现它返回的结果有些奇怪,请先询问这个工具的开发者,而不是搜索引擎的开发者。

DuckDuckGo 命令行应用

DuckDuckGo Bangs(DuckDuckGo 快捷搜索) 可以帮助你轻易地在 DuckDuckGo 上找到想要的信息(甚至 本网站 omgubuntu 都有快捷搜索)。ddgr 非常忠实地呈现了这个功能。

和网页版不同的是,你可以更改每页返回多少结果。这比起每次查询都要看三十多条结果要方便一些。默认界面经过了精心设计,在不影响可读性的情况下尽量减少了占用空间。

ddgr 有许多功能和亮点,包括:

  • 更改搜索结果数
  • 支持 Bash 自动补全
  • 使用 DuckDuckGo Bangs
  • 在浏览器中打开链接
  • ”手气不错“选项
  • 基于时间、地区、文件类型等的筛选功能
  • 极少的依赖项

你可以从 Github 的项目页面上下载支持各种系统的 ddgr

另外,在 Ubuntu 16.04 LTS 或更新版本中,你可以使用 PPA 安装 ddgr。这个仓库由 ddgr 的开发者维护。如果你想要保持在最新版本的话,推荐使用这种方式安装。

需要提醒的是,在本文创作时,这个 PPA 中的 ddgr 并不是 最新版本,而是一个稍旧的版本(缺少 -num 选项)。

使用以下命令添加 PPA:

sudo add-apt-repository ppa:twodopeshaggy/jarun
sudo apt-get update

如何使用 ddgr 在命令行中搜索 DuckDuckGo

安装完毕后,你只需打开你的终端模拟器,并运行:

ddgr

然后输入查询内容:

search-term

你可以限制搜索结果数:

ddgr --num 5 search-term

或者自动在浏览器中打开第一条搜索结果:

ddgr -j search-term

你可以使用参数和选项来提高搜索精确度。使用以下命令来查看所有的参数:

ddgr -h

via: http://www.omgubuntu.co.uk/2017/11/duck-duck-go-terminal-app

作者:JOEY SNEDDON 译者:yixunx 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

如果你尝试在 Ubuntu 下连接你的安卓手机,你也许可以试试 Linux 下的安卓文件传输助手。

本质上来说,这个应用是谷歌 macOS 版本的一个克隆。它是用 Qt 编写的,用户界面非常简洁,使得你能轻松在 Ubuntu 和安卓手机之间传输文件和文件夹。

现在,有可能一部分人想知道有什么是这个应用可以做,而 Nautilus(Ubuntu 默认的文件资源管理器)不能做的,答案是没有。

当我将我的 Nexus 5X(记得选择 媒体传输协议 MTP 选项)连接在 Ubuntu 上时,在 GVfs(LCTT 译注: GNOME 桌面下的虚拟文件系统)的帮助下,我可以打开、浏览和管理我的手机,就像它是一个普通的 U 盘一样。

Nautilus MTP integration with a Nexus 5X

但是一些用户在使用默认的文件管理器时,在 MTP 的某些功能上会出现问题:比如文件夹没有正确加载,创建新文件夹后此文件夹不存在,或者无法在媒体播放器中使用自己的手机。

这就是要为 Linux 系统用户设计一个安卓文件传输助手应用的原因,将这个应用当做将 MTP 设备安装在 Linux 下的另一种选择。如果你使用 Linux 下的默认应用时一切正常,你也许并不需要尝试使用它 (除非你真的很想尝试新鲜事物)。

Android File Transfer Linux App

该 app 特点:

  • 简洁直观的用户界面
  • 支持文件拖放功能(从 Linux 系统到手机)
  • 支持批量下载 (从手机到 Linux系统)
  • 显示传输进程对话框
  • FUSE 模块支持
  • 没有文件大小限制
  • 可选命令行工具

Ubuntu 下安装安卓手机文件助手的步骤

以上就是对这个应用的介绍,下面是如何安装它的具体步骤。

这有一个 [PPA](个人软件包集)源为 Ubuntu 14.04 LTS、16.04 LTS 和 Ubuntu 17.10 提供可用应用。

为了将这一 PPA 加入你的软件资源列表中,执行这条命令:

sudo add-apt-repository ppa:samoilov-lex/aftl-stable

接着,为了在 Ubuntu 下安装 Linux版本的安卓文件传输助手,执行:

sudo apt-get update && sudo apt install android-file-transfer

这样就行了。

你会在你的应用列表中发现这一应用的启动图标。

在你启动这一应用之前,要确保没有其他应用(比如 Nautilus)已经挂载了你的手机。如果其它应用正在使用你的手机,就会显示“无法找到 MTP 设备”。要解决这一问题,将你的手机从 Nautilus(或者任何正在使用你的手机的应用)上移除,然后再重新启动安卓文件传输助手。


via: http://www.omgubuntu.co.uk/2017/11/android-file-transfer-app-linux

作者:JOEY SNEDDON 译者:wenwensnow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux 系统提供了许多有用的命令来检查网络配置和连接。下面来看几个,包括 ifqueryifupifdownifconfig

Linux 上有许多可用于查看网络设置和连接的命令。在今天的文章中,我们将会通过一些非常方便的命令来看看它们是如何工作的。

ifquery 命令

一个非常有用的命令是 ifquery。这个命令应该会显示一个网络接口列表。但是,你可能只会看到类似这样的内容 - 仅显示回环接口:

$ ifquery --list
lo

如果是这种情况,那说明你的 /etc/network/interfaces 不包括除了回环接口之外的网络接口信息。在下面的例子中,假设你使用 DHCP 来分配地址,且如果你希望它更有用的话,你可以添加例子最后的两行。

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp

ifup 和 ifdown 命令

可以使用相关的 ifupifdown 命令来打开网络连接并根据需要将其关闭,只要该文件具有所需的描述性数据即可。请记住,“if” 在这里意思是 接口 interface ,这与 ifconfig 命令中的一样,而不是 如果我只有一个大脑 if I only had a brain 中的 “if”。

ifconfig 命令

另外,ifconfig 命令完全不读取 /etc/network/interfaces,但是仍然提供了网络接口相当多的有用信息 —— 配置数据以及可以告诉你每个接口有多忙的数据包计数。ifconfig 命令也可用于关闭和重新启动网络接口(例如:ifconfig eth0 down)。

$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:1e:4f:c8:43:fc
          inet addr:192.168.0.6  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: fe80::b44b:bdb6:2527:6ae9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:60474 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33463 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:43922053 (43.9 MB)  TX bytes:4000460 (4.0 MB)
          Interrupt:21 Memory:fe9e0000-fea00000

输出中的 RX 和 TX 数据包计数很低。此外,没有报告错误或数据包冲突。或许可以用 uptime 命令确认此系统最近才重新启动。

上面显示的广播 (Bcast) 和网络掩码 (Mask) 地址表明系统运行在 C 类等效网络(默认)上,所以本地地址范围从 192.168.0.1192.168.0.254

netstat 命令

netstat 命令提供有关路由和网络连接的信息。netstat -rn 命令显示系统的路由表。192.168.0.1 是本地网关 (Flags=UG)。

$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.0.1     0.0.0.0         UG        0 0          0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 eth0
192.168.0.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0

上面输出中的 169.254.0.0 条目仅在你正在使用或计划使用本地链路通信时才有必要。如果不是这样的话,你可以在 /etc/network/if-up.d/avahi-autoipd 中注释掉相关的行:

$ tail -12 /etc/network/if-up.d/avahi-autoipd
#if [ -x /bin/ip ]; then
#       # route already present?
#       ip route show | grep -q '^169.254.0.0/16[[:space:]]' && exit 0
#
#       /bin/ip route add 169.254.0.0/16 dev $IFACE metric 1000 scope link
#elif [ -x /sbin/route ]; then
#       # route already present?
#       /sbin/route -n | egrep -q "^169.254.0.0[[:space:]]" && exit 0
#
#       /sbin/route add -net 169.254.0.0 netmask 255.255.0.0 dev $IFACE metric 1000
#fi

netstat -a 命令

netstat -a 命令将显示“所有”网络连接。为了将其限制为显示正在监听和已建立的连接(通常更有用),请改用 netstat -at 命令。

$ netstat -at
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 *:ssh                   *:*                     LISTEN
tcp        0      0 localhost:ipp           *:*                     LISTEN
tcp        0      0 localhost:smtp          *:*                     LISTEN
tcp        0    256 192.168.0.6:ssh         192.168.0.32:53550      ESTABLISHED
tcp6       0      0 [::]:http               [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
tcp6       0      0 ip6-localhost:ipp       [::]:*                  LISTEN
tcp6       0      0 ip6-localhost:smtp      [::]:*                  LISTEN

host 命令

host 命令就像 nslookup 一样,用来查询远程系统的 IP 地址,但是还提供系统的邮箱处理地址。

$ host world.std.com
world.std.com has address 192.74.137.5
world.std.com mail is handled by 10 smtp.theworld.com.

nslookup 命令

nslookup 还提供系统中(本例中是本地系统)提供 DNS 查询服务的信息。

$ nslookup world.std.com
Server:         127.0.1.1
Address:        127.0.1.1#53

Non-authoritative answer:
Name:   world.std.com
Address: 192.74.137.5

dig 命令

dig 命令提供了很多有关连接到远程系统的信息 - 包括与我们通信的名称服务器以及查询需要多长时间进行响应,并经常用于故障排除。

$ dig world.std.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> world.std.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28679
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;world.std.com.                 IN      A

;; ANSWER SECTION:
world.std.com.          78146   IN      A       192.74.137.5

;; Query time: 37 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Mon Oct 09 13:26:46 EDT 2017
;; MSG SIZE  rcvd: 58

nmap 命令

nmap 经常用于探查远程系统,但是同样也用于报告本地系统提供的服务。在下面的输出中,我们可以看到登录可以使用 ssh、smtp 用于电子邮箱、web 站点也是启用的,并且 ipp 打印服务正在运行。

$ nmap localhost

Starting Nmap 7.01 ( https://nmap.org ) at 2017-10-09 15:01 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00016s latency).
Not shown: 996 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
25/tcp  open  smtp
80/tcp  open  http
631/tcp open  ipp

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds

Linux 系统提供了很多有用的命令用于查看网络配置和连接。如果你都探索完了,请记住 apropos network 或许会让你了解更多。


via: https://www.networkworld.com/article/3230519/linux/examining-network-connections-on-linux-systems.html

作者:Sandra Henry-Stocker 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

介绍

kprobes 是一种内核功能,它允许通过在执行(或模拟)断点指令之前和之后,设置调用开发者提供例程的任意断点来检测内核。可参见 kprobes 文档 注1 获取更多信息。基本的 kprobes 功能可使用 CONFIG_KPROBEES 来选择。在 arm64 的 v4.8 内核发行版中, kprobes 支持被添加到主线。

在这篇文章中,我们将介绍 kprobes 在 arm64 上的使用,通过在命令行中使用 debugfs 事件追踪接口来收集动态追踪事件。这个功能在一些架构(包括 arm32)上可用已经有段时间,现在在 arm64 上也能使用了。这个功能可以无需编写任何代码就能使用 kprobes。

探针类型

kprobes 子系统提供了三种不同类型的动态探针,如下所述。

kprobes

基本探针是 kprobes 插入的一个软件断点,用以替代你正在探测的指令,当探测点被命中时,它为最终的单步执行(或模拟)保存下原始指令。

kretprobes

kretprobes 是 kprobes 的一部分,它允许拦截返回函数,而不必在返回点设置一个探针(或者可能有多个探针)。对于支持的架构(包括 ARMv8),只要选择 kprobes,就可以选择此功能。

jprobes

jprobes 允许通过提供一个具有相同 调用签名 call signature 的中间函数来拦截对一个函数的调用,这里中间函数将被首先调用。jprobes 只是一个编程接口,它不能通过 debugfs 事件追踪子系统来使用。因此,我们将不会在这里进一步讨论 jprobes。如果你想使用 jprobes,请参考 kprobes 文档。

调用 kprobes

kprobes 提供一系列能从内核代码中调用的 API 来设置探测点和当探测点被命中时调用的注册函数。在不往内核中添加代码的情况下,kprobes 也是可用的,这是通过写入特定事件追踪的 debugfs 文件来实现的,需要在文件中设置探针地址和信息,以便在探针被命中时记录到追踪日志中。后者是本文将要讨论的重点。最后 kprobes 可以通过 perl 命令来使用。

kprobes API

内核开发人员可以在内核中编写函数(通常在专用的调试模块中完成)来设置探测点,并且在探测指令执行前和执行后立即执行任何所需操作。这在 kprobes.txt 中有很好的解释。

事件追踪

事件追踪子系统有自己的自己的文档 注2 ,对于了解一般追踪事件的背景可能值得一读。事件追踪子系统是 追踪点 tracepoints 和 kprobes 事件追踪的基础。事件追踪文档重点关注追踪点,所以请在查阅文档时记住这一点。kprobes 与追踪点不同的是没有预定义的追踪点列表,而是采用动态创建的用于触发追踪事件信息收集的任意探测点。事件追踪子系统通过一系列 debugfs 文件来控制和监视。事件追踪(CONFIG_EVENT_TRACING)将在被如 kprobe 事件追踪子系统等需要时自动选择。

kprobes 事件

使用 kprobes 事件追踪子系统,用户可以在内核任意断点处指定要报告的信息,只需要指定任意现有可探测指令的地址以及格式化信息即可确定。在执行过程中遇到断点时,kprobes 将所请求的信息传递给事件追踪子系统的公共部分,这些部分将数据格式化并追加到追踪日志中,就像追踪点的工作方式一样。kprobes 使用一个类似的但是大部分是独立的 debugfs 文件来控制和显示追踪事件信息。该功能可使用 CONFIG_KPROBE_EVENT 来选择。Kprobetrace 文档^ 注3 提供了如何使用 kprobes 事件追踪的基本信息,并且应当被参考用以了解以下介绍示例的详细信息。

kprobes 和 perf

perf 工具为 kprobes 提供了另一个命令行接口。特别地,perf probe 允许探测点除了由函数名加偏移量和地址指定外,还可由源文件和行号指定。perf 接口实际上是使用 kprobes 的 debugfs 接口的封装器。

Arm64 kprobes

上述所有 kprobes 的方面现在都在 arm64 上得到实现,然而实际上与其它架构上的有一些不同:

  • 注册名称参数当然是依架构而特定的,并且可以在 ARM ARM 中找到。
  • 目前不是所有的指令类型都可被探测。当前不可探测的指令包括 mrs/msr(除了 DAIF 读取)、异常生成指令、eret 和 hint(除了 nop 变体)。在这些情况下,只探测一个附近的指令来代替是最简单的。这些指令在探测的黑名单里是因为在 kprobes 单步执行或者指令模拟时它们对处理器状态造成的改变是不安全的,这是由于 kprobes 构造的单步执行上下文和指令所需要的不一致,或者是由于指令不能容忍在 kprobes 中额外的处理时间和异常处理(ldx/stx)。
  • 试图识别在 ldx/stx 序列中的指令并且防止探测,但是理论上这种检查可能会失败,导致允许探测到的原子序列永远不会成功。当探测原子代码序列附近时应该小心。
  • 注意由于 linux ARM64 调用约定的具体信息,为探测函数可靠地复制栈帧是不可能的,基于此不要试图用 jprobes 这样做,这一点与支持 jprobes 的大多数其它架构不同。这样的原因是被调用者没有足够的信息来确定需要的栈数量。
  • 注意当探针被命中时,一个探针记录的栈指针信息将反映出使用中的特定栈指针,它是内核栈指针或者中断栈指针。
  • 有一组内核函数是不能被探测的,通常因为它们作为 kprobes 处理的一部分被调用。这组函数的一部分是依架构特定的,并且也包含如异常入口代码等。

使用 kprobes 事件追踪

kprobes 的一个常用例子是检测函数入口和/或出口。因为只需要使用函数名来作为探针地址,它安装探针特别简单。kprobes 事件追踪将查看符号名称并且确定地址。ARMv8 调用标准定义了函数参数和返回值的位置,并且这些可以作为 kprobes 事件处理的一部分被打印出来。

例子: 函数入口探测

检测 USB 以太网驱动程序复位功能:

$ pwd
/sys/kernel/debug/tracing
$ cat > kprobe_events <<EOF
p ax88772_reset %x0
EOF
$ echo 1 > events/kprobes/enable

此时每次该驱动的 ax8872_reset() 函数被调用,追踪事件都将会被记录。这个事件将显示指向通过作为此函数的唯一参数的 X0(按照 ARMv8 调用标准)传入的 usbnet 结构的指针。插入需要以太网驱动程序的 USB 加密狗后,我们看见以下追踪信息:

$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1   #P:8
#
#                           _—–=> irqs-off
#                          / _—-=> need-resched
#                         | / _—=> hardirq/softirq
#                         || / _–=> preempt-depth
#                         ||| / delay
#        TASK-PID   CPU#  |||| TIMESTAMP  FUNCTION
#           | |    |   ||||    |      |
kworker/0:0-4             [000] d… 10972.102939:   p_ax88772_reset_0:
(ax88772_reset+0x0/0x230)   arg1=0xffff800064824c80

这里我们可以看见传入到我们的探测函数的指针参数的值。由于我们没有使用 kprobes 事件追踪的可选标签功能,我们需要的信息自动被标注为 arg1。注意这指向我们需要 kprobes 记录这个探针的一组值的第一个,而不是函数参数的实际位置。在这个例子中它也只是碰巧是我们探测函数的第一个参数。

例子: 函数入口和返回探测

kretprobe 功能专门用于探测函数返回。在函数入口 kprobes 子系统将会被调用并且建立钩子以便在函数返回时调用,钩子将记录需求事件信息。对最常见情况,返回信息通常在 X0 寄存器中,这是非常有用的。在 %x0 中返回值也可以被称为 $retval。以下例子也演示了如何提供一个可读的标签来展示有趣的信息。

使用 kprobes 和 kretprobe 检测内核 do_fork() 函数来记录参数和结果的例子:

$ cd /sys/kernel/debug/tracing
$ cat > kprobe_events <<EOF
p _do_fork %x0 %x1 %x2 %x3 %x4 %x5
r _do_fork pid=%x0
EOF
$ echo 1 > events/kprobes/enable

此时每次对 _do_fork() 的调用都会产生两个记录到 trace 文件的 kprobe 事件,一个报告调用参数值,另一个报告返回值。返回值在 trace 文件中将被标记为 pid。这里是三次 fork 系统调用执行后的 trace 文件的内容:

_$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 6/6   #P:8
#
#                              _—–=> irqs-off
#                             / _—-=> need-resched
#                            | / _—=> hardirq/softirq
#                            || / _–=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
              bash-1671  [001] d…   204.946007: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   204.946391: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x724
              bash-1671  [001] d…   208.845749: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   208.846127: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x725
              bash-1671  [001] d…   214.401604: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   214.401975: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x726_

例子: 解引用指针参数

对于指针值,kprobes 事件处理子系统也允许解引用和打印所需的内存内容,适用于各种基本数据类型。为了展示所需字段,手动计算结构的偏移量是必要的。

检测 _do_wait() 函数:

$ cat > kprobe_events <<EOF
p:wait_p do_wait wo_type=+0(%x0):u32 wo_flags=+4(%x0):u32
r:wait_r do_wait $retval
EOF
$ echo 1 > events/kprobes/enable

注意在第一个探针中使用的参数标签是可选的,并且可用于更清晰地识别记录在追踪日志中的信息。带符号的偏移量和括号表明了寄存器参数是指向记录在追踪日志中的内存内容的指针。:u32 表明了内存位置包含一个无符号的 4 字节宽的数据(在这个例子中指局部定义的结构中的一个 emum 和一个 int)。

探针标签(冒号后)是可选的,并且将用来识别日志中的探针。对每个探针来说标签必须是独一无二的。如果没有指定,将从附近的符号名称自动生成一个有用的标签,如前面的例子所示。

也要注意 $retval 参数可以只是指定为 %x0

这里是两次 fork 系统调用执行后的 trace 文件的内容:

$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 4/4   #P:8
#
#                              _—–=> irqs-off
#                             / _—-=> need-resched
#                            | / _—=> hardirq/softirq
#                            || / _–=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
             bash-1702  [001] d…   175.342074: wait_p: (do_wait+0x0/0x260) wo_type=0x3 wo_flags=0xe
             bash-1702  [002] d..1   175.347236: wait_r: (SyS_wait4+0x74/0xe4 <- do_wait) arg1=0x757
             bash-1702  [002] d…   175.347337: wait_p: (do_wait+0x0/0x260) wo_type=0x3 wo_flags=0xf
             bash-1702  [002] d..1   175.347349: wait_r: (SyS_wait4+0x74/0xe4 <- do_wait) arg1=0xfffffffffffffff6

例子: 探测任意指令地址

在前面的例子中,我们已经为函数的入口和出口插入探针,然而探测一个任意指令(除少数例外)是可能的。如果我们正在 C 函数中放置一个探针,第一步是查看代码的汇编版本以确定我们要放置探针的位置。一种方法是在 vmlinux 文件上使用 gdb,并在要放置探针的函数中展示指令。下面是一个在 arch/arm64/kernel/modules.cmodule_alloc 函数执行此操作的示例。在这种情况下,因为 gdb 似乎更喜欢使用弱符号定义,并且它是与这个函数关联的存根代码,所以我们从 System.map 中来获取符号值:

$ grep module_alloc System.map
ffff2000080951c4 T module_alloc
ffff200008297770 T kasan_module_alloc

在这个例子中我们使用了交叉开发工具,并且在我们的主机系统上调用 gdb 来检查指令包含我们感兴趣函数。

$ ${CROSS_COMPILE}gdb vmlinux
(gdb) x/30i 0xffff2000080951c4
        0xffff2000080951c4 <module_alloc>:    sub    sp, sp, #0x30
        0xffff2000080951c8 <module_alloc+4>:    adrp    x3, 0xffff200008d70000
        0xffff2000080951cc <module_alloc+8>:    add    x3, x3, #0x0
        0xffff2000080951d0 <module_alloc+12>:    mov    x5, #0x713             // #1811
        0xffff2000080951d4 <module_alloc+16>:    mov    w4, #0xc0              // #192
        0xffff2000080951d8 <module_alloc+20>:
              mov    x2, #0xfffffffff8000000    // #-134217728
        0xffff2000080951dc <module_alloc+24>:    stp    x29, x30, [sp,#16]         0xffff2000080951e0 <module_alloc+28>:    add    x29, sp, #0x10
        0xffff2000080951e4 <module_alloc+32>:    movk    x5, #0xc8, lsl #48
        0xffff2000080951e8 <module_alloc+36>:    movk    w4, #0x240, lsl #16
        0xffff2000080951ec <module_alloc+40>:    str    x30, [sp]         0xffff2000080951f0 <module_alloc+44>:    mov    w7, #0xffffffff        // #-1
        0xffff2000080951f4 <module_alloc+48>:    mov    x6, #0x0               // #0
        0xffff2000080951f8 <module_alloc+52>:    add    x2, x3, x2
        0xffff2000080951fc <module_alloc+56>:    mov    x1, #0x8000            // #32768
        0xffff200008095200 <module_alloc+60>:    stp    x19, x20, [sp,#32]         0xffff200008095204 <module_alloc+64>:    mov    x20, x0
        0xffff200008095208 <module_alloc+68>:    bl    0xffff2000082737a8 <__vmalloc_node_range>
        0xffff20000809520c <module_alloc+72>:    mov    x19, x0
        0xffff200008095210 <module_alloc+76>:    cbz    x0, 0xffff200008095234 <module_alloc+112>
        0xffff200008095214 <module_alloc+80>:    mov    x1, x20
        0xffff200008095218 <module_alloc+84>:    bl    0xffff200008297770 <kasan_module_alloc>
        0xffff20000809521c <module_alloc+88>:    tbnz    w0, #31, 0xffff20000809524c <module_alloc+136>
        0xffff200008095220 <module_alloc+92>:    mov    sp, x29
        0xffff200008095224 <module_alloc+96>:    mov    x0, x19
        0xffff200008095228 <module_alloc+100>:    ldp    x19, x20, [sp,#16]         0xffff20000809522c <module_alloc+104>:    ldp    x29, x30, [sp],#32
        0xffff200008095230 <module_alloc+108>:    ret
        0xffff200008095234 <module_alloc+112>:    mov    sp, x29
        0xffff200008095238 <module_alloc+116>:    mov    x19, #0x0               // #0

在这种情况下,我们将在此函数中显示以下源代码行的结果:

p = __vmalloc_node_range(size, MODULE_ALIGN, VMALLOC_START,
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
NUMA_NO_NODE, __builtin_return_address(0));

……以及在此代码行的函数调用的返回值:

if (p && (kasan_module_alloc(p, size) < 0)) {

我们可以在从调用外部函数的汇编代码中识别这些。为了展示这些值,我们将在目标系统上的 0xffff20000809520c0xffff20000809521c 处放置探针。

$ cat > kprobe_events <<EOF
p 0xffff20000809520c %x0
p 0xffff20000809521c %x0
EOF
$ echo 1 > events/kprobes/enable

现在将一个以太网适配器加密狗插入到 USB 端口后,我们看到以下写入追踪日志的内容:

$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 12/12   #P:8
#
#                           _—–=> irqs-off
#                          / _—-=> need-resched
#                         | / _—=> hardirq/softirq
#                         || / _–=> preempt-depth
#                         ||| / delay
#        TASK-PID   CPU#  |||| TIMESTAMP  FUNCTION
#           | |    |   ||||    |      |
      systemd-udevd-2082  [000] d… 77.200991: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001188000
      systemd-udevd-2082  [000] d… 77.201059: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.201115: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001198000
      systemd-udevd-2082  [000] d… 77.201157: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.227456: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011a0000
      systemd-udevd-2082  [000] d… 77.227522: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.227579: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011b0000
      systemd-udevd-2082  [000] d… 77.227635: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      modprobe-2097  [002] d… 78.030643: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011b8000
      modprobe-2097  [002] d… 78.030761: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      modprobe-2097  [002] d… 78.031132: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001270000
      modprobe-2097  [002] d… 78.031187: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0

kprobes 事件系统的另一个功能是记录统计信息,这可在 inkprobe_profile 中找到。在以上追踪后,该文件的内容为:

$ cat kprobe_profile
 p_0xffff20000809520c                                    6            0
p_0xffff20000809521c                                    6            0

这表明我们设置的两处断点每个共发生了 8 次命中,这当然与追踪日志数据是一致的。在 kprobetrace 文档中有更多 kprobe\_profile 的功能描述。

也可以进一步过滤 kprobes 事件。用来控制这点的 debugfs 文件在 kprobetrace 文档中被列出,然而它们内容的详细信息大多在 trace events 文档中被描述。

总结

现在,Linux ARMv8 对支持 kprobes 功能也和其它架构相当。有人正在做添加 uprobes 和 systemtap 支持的工作。这些功能/工具和其他已经完成的功能(如: perf、 coresight)允许 Linux ARMv8 用户像在其它更老的架构上一样调试和测试性能。


参考文献

  • 注1: Jim Keniston, Prasanna S. Panchamukhi, Masami Hiramatsu. “Kernel Probes (kprobes).” GitHub. GitHub, Inc., 15 Aug. 2016. Web. 13 Dec. 2016.
  • 注2: Ts’o, Theodore, Li Zefan, and Tom Zanussi. “Event Tracing.” GitHub. GitHub, Inc., 3 Mar. 2016. Web. 13 Dec. 2016.
  • 注3: Hiramatsu, Masami. “Kprobe-based Event Tracing.” GitHub. GitHub, Inc., 18 Aug. 2016. Web. 13 Dec. 2016.

作者简介 : David Long 在 Linaro Kernel - Core Development 团队中担任工程师。 在加入 Linaro 之前,他在商业和国防行业工作了数年,既做嵌入式实时工作又为Unix提供软件开发工具。之后,在 Digital(又名 Compaq)公司工作了十几年,负责 Unix 标准,C 编译器和运行时库的工作。之后 David 又去了一系列初创公司做嵌入式 Linux 和安卓系统,嵌入式定制操作系统和 Xen 虚拟化。他拥有 MIPS,Alpha 和 ARM 平台的经验(等等)。他使用过从 1979 年贝尔实验室 V6 开始的大部分Unix操作系统,并且长期以来一直是 Linux 用户和倡导者。他偶尔也因使用烙铁和数字示波器调试设备驱动而知名。


via: http://www.linaro.org/blog/kprobes-event-tracing-armv8/

作者:David Long 译者:kimii 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出