Linux内核模块中的文件I / O

File I/O in a Linux kernel module

我正在编写一个需要打开和读取文件的Linux内核模块。 做到这一点的最佳方法是什么?


请问您为什么要打开文件?

我喜欢关注Linux的开发(出于好奇,我不是内核开发人员,我使用Java),并且我之前已经看过有关此问题的讨论。我能够找到关于此的LKML消息,基本上提到这通常是一个坏主意。我几乎肯定LWN在去年进行了报道,但是我很难找到该文章。

如果这是一个私有模块(例如对于某些自定义硬件,并且该模块将不会分发),则可以执行此操作,但我的印象是,如果要将代码提交到主线,则可能不会被接受。

Evan Teran提到了sysfs,这对我来说似乎是个好主意。如果您确实需要做更艰苦的自定义工作,则可以随时制作新的ioctrl。

编辑:

好的,我找到了我想要的文章,该文章来自Linux Journal。它解释了为什么做这种事情通常不是一个好主意,然后继续告诉您确切如何去做。


假设您可以获取指向open / read / close系统调用的relavent函数的指针,则可以执行以下操作:

1
2
3
4
5
6
7
8
9
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-或仅注册字符设备)以允许内核模块与用户空间帮助程序进行对话。该用户空间帮助程序可以执行任何所需的操作。

您还可以实现系统调用(或类似方法)以获取在用户空间中打开的文件描述符,并从内核读取/写入它。

这可能比尝试在内核空间中打开文件更整洁。

还有一些其他事情已经从内核空间打开了文件,您可以看看它们(循环驱动程序浮现在脑海了吗?)。


所有内核开发人员都说内核空间中的文件I / O不好(特别是如果您通过它们的路径引用这些文件),但是主流内核在加载固件时会这样做。如果您只需要读取文件,请使用

1
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中引用其大小。如果需要以null终止的字符串,请创建一个长度为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()kernel_write_file_from_path()函数。您可以查看Linux内核源代码树中fs/exec.c文件中的代码,其中定义了kernel_read_file()kernel_read_file_from_path()来编写您自己的kernel_write_file()kernel_write_file_from_path()函数,这些函数可以包含在模块中。

与往常一样,通过此函数,可以通过强制转换将文件的内容存储在char指针中,而不是void指针中。


/ proc文件系统也很适合私人使用,而且很容易。
http://www.linuxtopia.org/online_books/Linux_Kernel_Module_Programming_Guide/x773.html


您还可以在本《 Linux内核模块编程指南》中找到有关sys_call_open的一些信息。