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

发布于 2024-07-07 22:23:30 字数 53 浏览 8 评论 0原文

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

I'm writing a Linux kernel module that needs to open and read files. What's the best way to accomplish that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

南笙 2024-07-14 22:23:31

我能问一下你为什么要打开文件吗?

我喜欢关注Linux开发(出于好奇,我不是内核开发人员,我是做Java的),而且我以前看过关于这个问题的讨论。 我找到了关于此的 LKML 消息,基本上提到了这通常是个坏主意。 我几乎可以肯定 LWN 去年曾报道过它,但我找不到这篇文章。

如果这是一个私有模块(例如某些自定义硬件,并且该模块不会分发),那么您可以这样做,但我的印象是,如果您要将代码提交到主线,那么它可能不会被接受。

Evan Teran 提到了 sysfs,这对我来说似乎是个好主意。 如果你确实需要做更难的自定义事情,你总是可以创建新的 ioctrls。

编辑:

好的,我找到了我正在寻找的文章,它来自 Linux Journal。 它解释了为什么做这种事情通常是一个坏主意,然后继续告诉您到底如何做。

Can I ask why are you trying to open a file?

I like to follow Linux development (out of curiosity, I'm not a kernel developer, I do Java), and I've seen discussion of this question before. I was able to find a LKML message about this, basically mentioning it's usually a bad idea. I'm almost positive that LWN covered it in the last year, but I'm having trouble finding the article.

If this is a private module (like for some custom hardware and the module won't be distributed) then you can do this, but I'm under the impression that if you are going to submit your code to the mainline then it may not be accepted.

Evan Teran mentioned sysfs, which seems like a good idea to me. If you really need to do harder custom stuff you could always make new ioctrls.

EDIT:

OK, I found the article I was looking for, it's from Linux Journal. It explains why doing this kind of stuff is generally a bad idea, then goes on to tell you exactly how to do it anyway.

白芷 2024-07-14 22:23:31

假设您可以获得指向 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_*”函数指针。 我确信有更好的方法,但我相信这会起作用。

assuming you can get pointers to the relavent function pointers to the open/read/close system calls, you can do something like this:

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);

you will need to create the "syscall_*" function pointers I have shown though. I am sure there is a better way, but I believe that this would work.

因为看清所以看轻 2024-07-14 22:23:31

一般来说,如果您需要从内核模块读取/写入文件,那么您在架构上就做错了。

存在允许内核模块与用户空间帮助程序进程对话的机制(例如 netlink - 或者只是注册字符设备)。 该用户空间帮助进程可以做任何它想做的事情。

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

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

还有一些其他东西已经从内核空间打开文件,您可以查看它们(想到了循环驱动程序?)。

Generally speaking, if you need to read/write files from a kernel module, you're doing something wrong architecturally.

There exist mechanisms (netlink for example - or just register a character device) to allow a kernel module to talk to a userspace helper process. That userspace helper process can do whatever it wants.

You could also implement a system call (or such like) to take a file descriptor opened in userspace and read/write it from the kernel.

This would probably be neater than trying to open files in kernel space.

There are some other things which already open files from kernel space, you could look at them (the loop driver springs to mind?).

臻嫒无言 2024-07-14 22:23:31

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

/proc filesystem is also good for private use, and it's easy.
http://www.linuxtopia.org/online_books/Linux_Kernel_Module_Programming_Guide/x773.html

清醇 2024-07-14 22:23:31

所有内核开发人员都说来自内核空间的文件 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 中引用其大小。 如果您需要它以 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()< /code>),但没有 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 指针中。

All of the kernel developers say that file I/O from kernel space is bad (especially if you're referring to these files by their paths) but the mainstream kernel does this when you load firmware. If you just need to read from files, use the

kernel_read_file_from_path(const char *path, void **buf, loff_t *size, loff_t max_size, enum kernel_read_file_id id)

function, which is what the firmware loader code uses, declared in include/linux/fs.h. This function returns a negative value on error.

I'm not really sure of the point of the id variable at the end, if you look at the code it's not really used, so just put something like READING_FIRMWARE there (no quotes).

buf is not null terminated, instead refer to its size in size. If you need it to be null terminated, create a string size + 1 bytes long and copy it over or rewrite the kernel_read_file() function (used by kernel_read_file_from_path(), defined in fs/exec.c) and add one to i_size where memory is allocated. (If you want to do this, you can redefine the kernel_read_file() function in your module with a different function name to avoid modifying the whole kernel.)

If you need to write to files, there is a kernel_write() function (analogous to kernel_read(), which is used by kernel_read_file() and therefore also by kernel_read_file_from_path()), but there is no kernel_write_file() or kernel_write_file_from_path() function. You can look at the code in the fs/exec.c file in the Linux kernel source tree where kernel_read_file() and kernel_read_file_from_path() are defined to write your own kernel_write_file() and kernel_write_file_from_path() functions that you can include in your module.

And as always, you can store a file's contents in a char pointer instead of a void pointer with this function by casting it.

傲性难收 2024-07-14 22:23:31

You can also find some informations about sys_call_open in this Linux Kernel Module Programing Guide.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文