无法从自定义内核模块在 /proc 中创建目录
Unable to create directories in /proc from a custom kernel module
在 /proc 目录中,自定义模块应创建两个目录 lkm 和 mem 以获得类似 的层次结构/proc/lkm/mem。
一个简单的重构现在没有明显的原因就破坏了工作。
重构后模块不再创建层次结构 /proc/lkm/mem。它只会创建 lkm 然后停止。内核环形缓冲区中没有消息。我想知道我在重构中破坏了什么?我希望你能帮我找到问题所在。
手动测试已 运行 使用全新启动的 VM 和通常的 insmod/rmmod 及以下版本:
- 内核:5.3.0 (x86_64)
- 海湾合作委员会:9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)
- 分布:Ubuntu19.10,eoan
在下面你可以看到原始代码和重构代码。在底部我放了一个最小的源文件和 Makefile。还有一个repository, an issue and the breaking commit。当然,我可以恢复该提交,但其他重构即将到来,我想知道原因,然后再破坏类似的东西。
提前致谢:)
重构前的原始代码
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;
}
// ...
}
重构代码
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?
}
}
// ...
最小源代码
#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);
生成文件
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
编辑
- 添加了存储库、问题和提交的 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
这里是 NULL
...
lkm_proc_mkdir(lkm_proc_parent, LKM_PROC_PARENT, NULL);
它仍然是 NULL here
,因为 C 中的函数参数当然是按值传递的。
lkm_proc_mkdir(mem_proc_parent, LKM_MEM_PROC_PARENT, lkm_proc_parent);
所以这是调用 proc_mkdir("mem", NULL)
。您可能会注意到已经创建了一个 /proc/mem
目录。
// ...
}
同时:
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);
}
}
当这个函数 returns 时,由 proc_mkdir
编辑的值 return 丢失了,因为你只将它分配给了一个函数参数,这当然是局部的功能。同样,参数是按值传递的!
看起来你可能想要 lkm_proc_mkdir
到 return 一个 struct proc_dir *
,而不是将一个作为参数。或者您可能希望第一个参数是 struct proc_dir **
,但在我看来这更糟糕。
在 /proc 目录中,自定义模块应创建两个目录 lkm 和 mem 以获得类似 的层次结构/proc/lkm/mem。
一个简单的重构现在没有明显的原因就破坏了工作。
重构后模块不再创建层次结构 /proc/lkm/mem。它只会创建 lkm 然后停止。内核环形缓冲区中没有消息。我想知道我在重构中破坏了什么?我希望你能帮我找到问题所在。
手动测试已 运行 使用全新启动的 VM 和通常的 insmod/rmmod 及以下版本:
- 内核:5.3.0 (x86_64)
- 海湾合作委员会:9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2)
- 分布:Ubuntu19.10,eoan
在下面你可以看到原始代码和重构代码。在底部我放了一个最小的源文件和 Makefile。还有一个repository, an issue and the breaking commit。当然,我可以恢复该提交,但其他重构即将到来,我想知道原因,然后再破坏类似的东西。
提前致谢:)
重构前的原始代码
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;
}
// ...
}
重构代码
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?
}
}
// ...
最小源代码
#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);
生成文件
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
编辑 - 添加了存储库、问题和提交的 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
这里是 NULL
...
lkm_proc_mkdir(lkm_proc_parent, LKM_PROC_PARENT, NULL);
它仍然是 NULL here
,因为 C 中的函数参数当然是按值传递的。
lkm_proc_mkdir(mem_proc_parent, LKM_MEM_PROC_PARENT, lkm_proc_parent);
所以这是调用 proc_mkdir("mem", NULL)
。您可能会注意到已经创建了一个 /proc/mem
目录。
// ...
}
同时:
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);
}
}
当这个函数 returns 时,由 proc_mkdir
编辑的值 return 丢失了,因为你只将它分配给了一个函数参数,这当然是局部的功能。同样,参数是按值传递的!
看起来你可能想要 lkm_proc_mkdir
到 return 一个 struct proc_dir *
,而不是将一个作为参数。或者您可能希望第一个参数是 struct proc_dir **
,但在我看来这更糟糕。