我正在编写一个需要打开和读取文件的 Linux 内核模块。实现这一目标的最佳方法是什么?
6 回答
请问您为什么要打开文件?
我喜欢关注 Linux 开发(出于好奇,我不是内核开发人员,我做的是 Java),而且我之前也看到过关于这个问题的讨论。我能够找到关于此的LKML 消息,基本上提到这通常是一个坏主意。我几乎肯定 LWN 在去年报道过它,但我很难找到这篇文章。
如果这是一个私有模块(例如某些自定义硬件并且该模块不会分发),那么您可以这样做,但我的印象是,如果您要将代码提交到主线,那么它可能不会被接受。
Evan Teran 提到了 sysfs,这对我来说似乎是个好主意。如果你真的需要做更难的自定义东西,你总是可以制作新的 ioctrls。
编辑:
好的,我找到了我要找的文章,它来自Linux Journal。它解释了为什么做这种事情通常是一个坏主意,然后继续告诉你到底该怎么做。
假设您可以获得指向系统调用的相关函数指针的指针open
,您可以执行以下操作read
:close
mm_segment_t fs = get_fs();
set_fs(KERNEL_DS);
fd = (*syscall_open)(file, flags, mode);
if(fd != -1) {
(*syscall_read)(fd, buf, size);
(*syscall_close)(fd);
}
set_fs(fs);
您将需要创建syscall_*
我已经显示的“”函数指针。我相信有更好的方法,但我相信这会奏效。
一般来说,如果您需要从内核模块读取/写入文件,那么您在架构上做错了事。
存在允许内核模块与用户空间助手进程对话的机制(例如 netlink - 或只是注册字符设备)。该用户空间助手进程可以为所欲为。
您还可以实现系统调用(或类似的调用)来获取在用户空间中打开的文件描述符并从内核读取/写入它。
这可能比尝试在内核空间中打开文件更简洁。
还有一些其他的东西已经从内核空间打开了文件,你可以看看它们(循环驱动程序浮现在脑海中?)。
/proc 文件系统也适合私人使用,而且很容易。
http://www.linuxtopia.org/online_books/Linux_Kernel_Module_Programming_Guide/x773.html
所有内核开发人员都说来自内核空间的文件 I/O 很糟糕(特别是如果您通过它们的路径引用这些文件),但主流内核在您加载固件时会这样做。如果您只需要从文件中读取,请使用
kernel_read_file_from_path(const char *path, void **buf, loff_t *size, loff_t max_size, enum kernel_read_file_id id)
函数,这是固件加载程序代码使用的,在include/linux/fs.h
. 此函数在出错时返回负值。
我不太确定最后id
变量的意义,如果你看一下它并没有真正使用的代码,所以只要放一些类似的东西READING_FIRMWARE
(没有引号)。
buf
不是以 null 结尾的,而是在size
. 如果您需要它以空值终止,请创建一个size + 1
字节长的字符串并将其复制或重写该kernel_read_file()
函数(由 使用kernel_read_file_from_path()
,在 中定义)并在分配内存的位置fs/exec.c
添加一个。i_size
(如果你想这样做,你可以kernel_read_file()
在你的模块中用不同的函数名重新定义函数,以避免修改整个内核。)
如果您需要写入文件,则有一个kernel_write()
函数(类似于kernel_read()
,由 使用kernel_read_file()
,因此也由使用kernel_read_file_from_path()
),但没有kernel_write_file()
orkernel_write_file_from_path()
函数。您可以查看fs/exec.c
Linux 内核源代码树中文件中的代码kernel_read_file()
,其中kernel_read_file_from_path()
定义了您自己的代码kernel_write_file()
和kernel_write_file_from_path()
可以包含在模块中的函数。
和往常一样,您可以使用此函数通过强制转换将文件的内容存储在 char 指针而不是 void 指针中。
您还可以在此Linux 内核模块编程指南中找到有关 sys_call_open 的一些信息。