我试图通过查看内核源代码来理解一个函数,例如mkdir。这是一种尝试了解内核内部结构并在各种功能之间导航的尝试。我知道mkdir是在sys/stat.h中定义的。我找到了原型:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));


现在我需要查看在哪个C文件中实现了此功能。在源目录中,我尝试了

ack "int mkdir"


其中显示的是

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);


,但是它们都不符合定义在sys/stat.h中。

问题


哪个文件具有mkdir的实现?
使用上述函数定义,如何找出哪个文件有实施吗?内核在定义和实现方法时遵循什么模式?

注意:我正在使用内核2.6.36-rc1。

评论

顺便说一句,看看这个:voinici.ceata.org/~tct/resurse/utlk.pdf

#1 楼

系统调用不会像常规函数调用那样处理。从用户空间到内核空间的转换需要特殊的代码,基本上是在调用站点上将一些内联汇编代码注入到您的程序中。 “捕捉”系统调用的内核端代码也是您可能不需要深入了解的低级内容,至少在一开始时就不需要。

在内核源目录下的include/linux/syscalls.h中,您会发现这个:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);


然后在/usr/include/asm*/unistd.h中找到这个:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)


这段代码说mkdir(2)是系统调用#83。也就是说,系统调用是通过数字调用的,而不是通过地址调用,而不是像在您自己的程序或链接到该程序的库中的正常函数调用那样,通过地址调用。我上面提到的内联汇编粘合代码使用它来进行从用户到内核空间的转换,并带上您的参数。

还有一点证据表明这里有些奇怪:对于系统调用,并非总是严格的参数列表:例如,open(2)可以使用2个或3个参数。这意味着open(2)重载,是C ++(不是C)的功能,但是syscall接口是C兼容的。 (这与C的varargs功能不同,后者允许单个函数采用可变数量的参数。)

要回答第一个问题,在mkdir()所在的位置没有单个文件。 Linux支持许多不同的文件系统,并且每个文件系统都有自己的“ mkdir”操作实现。使内核将所有内容隐藏在单个系统调用之后的抽象层称为VFS。因此,您可能想开始使用fs/namei.cvfs_mkdir()中进行挖掘。低级文件系统修改代码的实际实现在其他地方。例如,ext4实现称为ext4_mkdir(),在fs/ext4/namei.c中定义。

关于第二个问题,是的,所有这些都有模式,但没有一条规则。实际上,您需要对内核的工作方式有一个相当广泛的了解,以便弄清楚应该在哪里寻找任何特定的系统调用。并非所有系统调用都涉及VFS,因此它们的内核端调用链并非都始于fs/namei.c。例如,mmap(2)mm/mmap.c开始,因为它是内核的内存管理(“ mm”)子系统的一部分。

我建议您获得Bovet和切萨蒂。

评论


很好的答案。关于您提到的书,“了解Linux内核”有一点。我没有,但是从发布日期(2000年)和TOC(在oreilly站点)开始,我觉得这大约是2.2内核以及2.4内核的一些见解(但我错了)。我的问题是:有一本等效的书涵盖了2.6内核的内部原理? (甚至更好的覆盖2.2、2.4和2.6)?

– DavAlPi
13年5月14日在14:27

@DavAlPi:据我所知,Bovet&Cesati仍然是关于该主题的最佳单本书。当我需要用更多最新资料补充它时,我会在正在使用的内核的源树的“文档”子目录中进行挖掘。

–沃伦·杨(Warren Young)
13年5月14日在17:28

实际上,open(2)是一个varargs函数。只有两种方法可以调用它,因此手册页以此方式进行文档记录,实际的原型中包含...作为任何varargs函数。当然,这是在libc级别实现的。当不使用第三个参数时,它可以将0或垃圾值传递给内核ABI。

–Random832
17年1月19日在16:48

“这是您不需要了解的东西”。如果在Stackexchange网络上找不到这种句子,那么世界将是一个更好的地方。

–石油
17年9月29日在7:37

#2 楼

这可能无法直接回答您的问题,但是我发现strace在尝试了解实际上是针对最简单的shell命令进行的底层系统调用时确实很棒。例如,

strace -o trace.txt mkdir mynewdir


系统调用mkdir mynewdir的命令将转储到trace.txt中,以供您查看。

评论


+1整洁的把戏!我以前没用过

–大卫·奥尼尔(David Oneill)
10 Nov 16 '20:42

更好的是,使输出文件trace.strace并在VIM中打开。 VIM将突出显示它,使阅读变得容易得多。

–马辛
16年8月23日在14:25

#3 楼

阅读Linux内核源代码的一个好地方是Linux交叉引用(LXR)¹。除了自由文本搜索结果外,搜索还返回类型化的匹配项(函数原型,变量声明等),因此它比单纯的grep更方便(而且速度更快)。

LXR不会扩展预处理器定义。系统调用的名称在各处都受到预处理器的控制。但是,大多数(全部?)系统调用是使用SYSCALL_DEFINEx宏系列之一定义的。由于mkdir接受两个参数,因此对SYSCALL_DEFINE2(mkdir的搜索将导致对mkdir系统调用的声明:

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}


好,sys_mkdirat表示它是mkdirat系统调用,因此仅单击将您带到include/linux/syscalls.h中的声明,但是定义就在上面。

mkdirat的主要工作是调用vfs_mkdir(VFS是通用文件系统层)。单击该按钮将显示两个搜索结果:include/linux/fs.h中的声明以及上面几行的定义。 vfs_mkdir的主要工作是调用特定于文件系统的实现:dir->i_op->mkdir。要找到实现的方法,您需要转向单个文件系统的实现,并且没有一成不变的规则-它甚至可能是内核树之外的模块。

¹LXR是一个索引程序。有几个网站提供到LXR的界面,其已知版本集略有不同,Web界面也略有不同。它们往往会来来去去,因此,如果您不习惯使用一个,请在网络上搜索“ linux cross-reference”以查找另一个。

#4 楼

系统调用通常包装在SYSCALL_DEFINEx()宏中,这就是为什么简单的grep找不到它们的原因:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)


扩展宏后的最终函数名称最终结束正在sys_mkdirSYSCALL_DEFINEx()宏添加了样板化的东西,例如每个系统调用定义都需要具有的跟踪代码。

#5 楼

注意:.h文件未定义函数。它在该.h文件中声明,并在其他位置定义(实现)。这使编译器可以包含有关函数签名(原型)的信息,以允许对参数进行类型检查,并将返回类型与代码中的任何调用上下文进行匹配。

通常,.h(头文件)在C用于声明函数和定义宏。mkdir特别是系统调用。该系统调用周围可能有一个GNU libc包装器(实际上几乎可以肯定是)。可以通过搜索内核源代码以及特别是系统调用来找到mkdir的真正内核实现。 VFS(虚拟文件系统)层提供了系统调用层可以调用的公共API。每个文件系统都必须注册供VFS层调用的功能。这允许不同的文件系统实现它们自己的语义,以了解目录的结构(例如,如果使用某种哈希方法存储它们,以使搜索特定条目更为有效)。我之所以这样说是因为,如果您正在搜索Linux内核源代码树,则很可能会跳过这些文件系统特定的目录创建功能。

#6 楼

您找到的所有实现都不匹配sys / stat.h中的原型。也许使用此头文件搜索include语句会更成功吗?

评论


该实现(如sys / stat.h中所述)是userland和libc的业务。内核内部的东西(如何真正完成)是内核内部的业务。对于所有内核黑客,内部函数可以称为xyzzy并采用5个参数。 libc的工作是接受userland调用,将其转换为所需的所有内核要求,将其交付并收集任何结果。

– vonbrand
13年1月16日在3:42

#7 楼

这是一对非常出色的博客文章,描述了用于查找底层内核源代码的各种技术。


https://stackoverflow.com/questions/2442966/cc-function-definitions -without-assembly / 2444508#2444508
sysadvent:第15天-在'ls'兔子洞下


评论


请不要仅仅发布指向博客或论坛的链接,总结其内容,以便读者可以看到它们的内容,如果网站消失了,还可以保留一些东西。另外,您的第一个链接是关于libc的,对于这个问题,这是不合主题的。

–吉尔斯'所以-不再是邪恶的'
2011年1月13日22:24