简体   繁体   English

无法从自定义内核模块在 /proc 中创建目录

[英]Unable to create directories in /proc from a custom kernel module

In the /proc directory a custom module should create two directories lkm and mem to get a hierarchy like /proc/lkm/mem .在 /proc 目录中,自定义模块应创建两个目录lkmmem以获得类似/proc/lkm/mem的层次结构。

A simple refactoring now broke what was working without obvious reason.一个简单的重构现在在没有明显原因的情况下破坏了工作。

After the refactoring the module is not creating the hierarchy /proc/lkm/mem anymore.重构后,模块不再创建层次结构/proc/lkm/mem It only creates lkm and then stops.它只创建lkm然后停止。 There're no messages in the Kernel Ring Buffer.内核环缓冲区中没有消息。 I was wondering what did I break with that refactoring?我想知道我在重构中破坏了什么? I hope you can help me finding the issue.我希望你能帮我找到问题。

Manual tests have been run with a fresh started VM and with usual insmod/rmmod and following versions:手动测试已使用新启动的 VM 和通常的 insmod/rmmod 和以下版本运行:

  • Kernel: 5.3.0 (x86_64)内核:5.3.0 (x86_64)
  • GCC: 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2) GCC:9.2.1 20191008(Ubuntu 9.2.1-9ubuntu2)
  • Distribution: Ubuntu 19.10, eoan发行版:Ubuntu 19.10,eoan

In the following you can see the original and the refactored code.在下面,您可以看到原始代码和重构代码。 At the bottom I put the a minimum source file and the Makefile.在底部,我放了一个最小的源文件和 Makefile。 There is also a repository , an issue and the breaking commit .还有一个存储库、一个问题破坏性提交 Of course I could revert that commit, but other refactorings are coming and I want to know the reason, before I break something similar.当然,我可以恢复那个提交,但其他重构即将到来,我想知道原因,然后再破坏类似的东西。

Thanks in advance :)提前致谢 :)

Original code prior to refactoring重构前的原始代码

static int __init lkm_mem_init(void)
{

    lkm_proc_parent = proc_mkdir(LKM_PROC_PARENT, NULL);

    if (lkm_proc_parent == NULL) {
        printk(KERN_ERR "lkm_mem: Failed to create parent /proc/%s for lkm.\n",
        LKM_PROC_PARENT);

        return 1;
    }

    mem_proc_parent = proc_mkdir(LKM_MEM_PROC_PARENT, lkm_proc_parent);

    if (mem_proc_parent == NULL) {
        printk(KERN_ERR
        "lkm_mem: Failed to create parent /proc/%s/%s for mem.\n",
        LKM_PROC_PARENT, LKM_MEM_PROC_PARENT);

        return 1;
    }

    // ...
}

Refactored code重构代码

static int __init lkm_mem_init(void)
{

    lkm_proc_mkdir(lkm_proc_parent, LKM_PROC_PARENT, NULL);
    lkm_proc_mkdir(mem_proc_parent, LKM_MEM_PROC_PARENT, lkm_proc_parent);

    // ...
}

void lkm_proc_mkdir(struct proc_dir_entry *entry, const char *name,
            struct proc_dir_entry *parent)
{
    entry = proc_mkdir(name, parent);

    if (entry == NULL) {
        printk(KERN_ERR
               "lkm_mem: Failed to create parent %s in proc.\n",
               name);

        // todo: How to abort loading module in gentle way?
    }
}

// ...

Minimum source code最小源代码

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Piekarski");
MODULE_DESCRIPTION("Exposing separated memory and swap statistics to /proc");
MODULE_VERSION("0.1");

#define LKM_PROC_PERMISSION 0444
#define LKM_PROC_PARENT "lkm"
#define LKM_MEM_PROC_PARENT "mem"
#define LKM_MEM_PROC_TOTAL_ENTRY "total"
#define LKM_MEM_PROC_FREE_ENTRY "free"

struct sysinfo si;
struct proc_dir_entry *lkm_proc_parent;
struct proc_dir_entry *mem_proc_parent;
struct proc_dir_entry *mem_proc_total_entry;
struct proc_dir_entry *mem_proc_free_entry;

static int lkm_value_show(struct seq_file *seq, void *v)
{
    seq_put_decimal_ull(seq, "", *(unsigned long *)seq->private);
    seq_putc(seq, '\n');

    return 0;
}

void lkm_proc_create_single_data(struct proc_dir_entry *entry,
                 unsigned long *value, const char *name)
{
    entry = proc_create_single_data(name, LKM_PROC_PERMISSION,
                    mem_proc_parent, lkm_value_show, value);

    if (entry == NULL) {
        printk(KERN_ERR "lkm_mem: Failed to create /proc/%s/%s/%s.\n",
               LKM_PROC_PARENT, LKM_MEM_PROC_PARENT, name);
    }
}

void lkm_proc_mkdir(struct proc_dir_entry *entry, const char *name,
            struct proc_dir_entry *parent)
{
    entry = proc_mkdir(name, parent);

    if (entry == NULL) {
        printk(KERN_ERR
               "lkm_mem: Failed to create parent %s in proc.\n",
               name);
    }
}

void lkm_remove_proc_entry(struct proc_dir_entry *entry, const char *name,
               struct proc_dir_entry *parent)
{
    if (entry != NULL) {
        remove_proc_entry(name, parent);
    }
}

static int __init lkm_mem_init(void)
{
    lkm_proc_mkdir(lkm_proc_parent, LKM_PROC_PARENT, NULL);
    lkm_proc_mkdir(mem_proc_parent, LKM_MEM_PROC_PARENT, lkm_proc_parent);

    si_meminfo(&si);

    lkm_proc_create_single_data(mem_proc_total_entry, &si.totalram,
                    LKM_MEM_PROC_TOTAL_ENTRY);

    lkm_proc_create_single_data(mem_proc_free_entry, &si.freeram,
                    LKM_MEM_PROC_FREE_ENTRY);

    return 0;
}

static void __exit lkm_mem_exit(void)
{
    lkm_remove_proc_entry(mem_proc_total_entry, LKM_MEM_PROC_TOTAL_ENTRY,
                  mem_proc_parent);

    lkm_remove_proc_entry(mem_proc_free_entry, LKM_MEM_PROC_FREE_ENTRY,
                  mem_proc_parent);

    lkm_remove_proc_entry(mem_proc_parent, LKM_MEM_PROC_PARENT,
                  lkm_proc_parent);

    lkm_remove_proc_entry(lkm_proc_parent, LKM_PROC_PARENT, NULL);
}

module_init(lkm_mem_init);
module_exit(lkm_mem_exit);

Makefile生成文件

ccflags-y := -Wall

obj-m += lkm_device.o lkm_mem.o lkm_parameters.o lkm_proc.o lkm_sandbox.o lkm_skeleton.o

all:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Edits - Added URLs to repository, issue and commit编辑- 添加了存储库、发布和提交的 URL

struct proc_dir_entry *lkm_proc_parent;
struct proc_dir_entry *mem_proc_parent;

static int __init lkm_mem_init(void)
{

lkm_proc_parent is NULL here... lkm_proc_parent在这里为NULL ...

    lkm_proc_mkdir(lkm_proc_parent, LKM_PROC_PARENT, NULL);

and it's still NULL here , since of course, function arguments in C are passed by value.并且NULL here仍然是NULL here ,因为当然,C 中的函数参数是按值传递的。

    lkm_proc_mkdir(mem_proc_parent, LKM_MEM_PROC_PARENT, lkm_proc_parent);

So this is calling proc_mkdir("mem", NULL) .所以这是调用proc_mkdir("mem", NULL) You'll probably notice that a /proc/mem directory has been created.您可能会注意到已经创建了一个/proc/mem目录。

    // ...
}

Meanwhile:同时:

void lkm_proc_mkdir(struct proc_dir_entry *entry, const char *name,
            struct proc_dir_entry *parent)
{
    entry = proc_mkdir(name, parent);

    if (entry == NULL) {
        printk(KERN_ERR
               "lkm_mem: Failed to create parent %s in proc.\n",
               name);
    }
}

The value returned by proc_mkdir is lost when this function returns, since you only assigned it to one of the function arguments, which of course is local to the function.当这个函数返回时, proc_mkdir返回的值会丢失,因为你只将它分配给函数参数之一,这当然是函数的本地参数。 Again, arguments are passed by value!同样,参数是按值传递的!

It seems like you probably want lkm_proc_mkdir to return a struct proc_dir * , rather than taking one as an argument.看起来您可能希望lkm_proc_mkdir返回一个struct proc_dir * ,而不是将其作为参数。 Or possibly you wanted the first argument to be a struct proc_dir ** , but that seems to me like worse style.或者您可能希望第一个参数是struct proc_dir ** ,但在我看来这更像是一种更糟糕的风格。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM