I'm writing a Linux kernel module that needs to open and read files. What's the best way to accomplish that?
问题:
回答1:
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.
回答2:
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.
回答3:
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?).
回答4:
You can also find some informations about sys_call_open in this Linux Kernel Module Programing Guide.
回答5:
/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
回答6:
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.