我在 Linux 内核中找不到 proc_create_data 函数的定义 - 或者我找到了它但未能理解它

I couldn't find the definition of proc_create_data function in Linux kernel - or maybe I found it but failed to understand it

情况

我正在关注 this 以更好地了解 Linux 内核。

有一个编写自定义 /proc 接口的示例。这是上面示例代码 link 中的一个片段 - custom-proc.c:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/types.h>

#omitted

int create_new_proc_entry(void) {
    int i;
    char *DATA = "Hello People";
    len = strlen(DATA);
    msg = kmalloc((size_t) DATA_SIZE, GFP_KERNEL); // +1 for [=12=]

    if (msg != NULL) {
        printk(KERN_INFO "Allocated memory for msg");
    } else {
        return -1;
    }

    strncpy(msg, DATA, len+1);
    for (i=0; i < len +1 ; i++) {
        printk(KERN_INFO "%c", msg[i]);
        if (msg[i] == '[=12=]') {
            printk(KERN_INFO "YES");
        }
    }
    proc = proc_create_data(MY_PROC_ENTRY, 0666, NULL, &proc_fops, msg);
    if (proc) {
        return 0;
    }
    return -1;
}

因为示例中没有定义 proc_create_data,我假设它必须在内核的某个地方定义。我下载了内核 5x 并在内核代码中搜索所有出现的 proc_create_data,发现它唯一被 defined 的地方是 /include/linux/proc_fs.h:

#Omitted

#define proc_create_data(name, mode, parent, proc_ops, data) ({ NULL; })

#Omitted

extern struct proc_dir_entry *proc_create_data(const char *, umode_t,
                           struct proc_dir_entry *,
                           const struct proc_ops *, void *)

就是这样。

我从 here 了解到,在 C 中,宏将在文本上展开,并且可以像函数一样使用它。

如果我在这里应用,那么在所有扩展之后,我将有

/include/linux/proc_fs.h:

#omitted
extern struct proc_dir_entry ({ NULL; })

custom-proc.c

#omitted
proc = ({ NULL; })

我觉得不对。

我不是编程新手,但不熟悉 C。我读过 Brian W. Kernighan 和 Dennis M. Ritchie 的 The C programming Language,但那里对宏的解释与 link 相同以上。

问题(主菜:))

如何理解内核中定义的proc_create_data函数?

我不是在寻找非常详细的技术答案,只是在寻找一种解释该代码的方法,这样我就可以按照示例进行操作,并能够在自己需要时阅读更多内核代码。

配菜 我在某处听说内核尽管是用 C 编写的,但与“普通”C 有一些差异。不过,我不确定这是不是真的或差异的程度。

如果这是“C 语言的内核版本”使用的技巧,如果有人知道 link 来解释这些技巧,那将会很有帮助。

我已经查看了以下资源,但找不到此类信息:

proc_fs.h中看起来像这样:

#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry *proc_create_data(const char *, umode_t,
                           struct proc_dir_entry *,
                           const struct proc_ops *,
                           void *);
#else /* CONFIG_PROC_FS */
#define proc_create_data(name, mode, parent, proc_ops, data) ({NULL;})
#endif

如果用户 configured kernel without proc filesystem support, then the function call is expanded to a statement that just returns NULL. Note that ({...}) is a gcc extensions statement expression - 不要在代码中使用 non-portable 扩展,而更喜欢使用 static inline 函数。语句表达式的 return 值是最后使用的表达式的值 - 在本例中为 NULL

如果 CONFIG_PROC_FS 是从用户配置中定义的,那么 proc/generic.c 就像任何其他函数一样定义函数 here,包括 proc_fs.h 在内的源文件请参阅函数声明并且看不到宏。

I couldn't find the definition of proc_create_data function in Linux kernel

不用担心 - typing proc_create_data in elixir results in all 3 definitions mentioned in this answer. There are even multiple indexed kernel source code browsers on the net, with lxr as an example (but I see internal error right now on lxr). If not, you can index the source code on your computer with ctags or GNU GLOBAL 然后浏览代码。

How do I understand the proc_create_data function as defined in the kernel?

与任何其他函数一样。不,宏没有通过声明展开 - 编译器会看到 宏或函数声明,具体取决于是否启用 PROC_FS

Side Dish I heard somewhere that the kernel, despite being written in C, has some differences to "normal" C.

Linux 内核专门针对 GNU GCC 编译器,因此倾向于使用 GNU C extensions,有时标记为 GNU C.