File open in linux kernel

File I/O in a Linux kernel module

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

6 Answers 6

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.

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.

It’s a custom module, it won’t be distributed. I need to open a file that contains a mapping of inodes => checksums.

@mipadi: I found the article I was thinking of, it explains exactly how to open and read a file from the kernel (after the «don’t do this» part). I’ve edited my post to reflect that and contain the link. Good luck.

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.

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.

Читайте также:  Virtualbox linux забыл пароль

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?).

I’ve actually altered the mechanism to read from a file in /proc, so I probably won’t need to read a file directly.

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.

Читайте также:  Linux router on usb

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.

Источник

Read/write files within a Linux kernel module

I know all the discussions about why one should not read/write files from kernel, instead how to use /proc or netlink to do that. I want to read/write anyway. I have also read Driving Me Nuts — Things You Never Should Do in the Kernel. However, the problem is that 2.6.30 does not export sys_read() . Rather it’s wrapped in SYSCALL_DEFINE3 . So if I use it in my module, I get the following warnings:

WARNING: "sys_read" [xxx.ko] undefined! WARNING: "sys_open" [xxx.ko] undefined! 
  • How to read/write within kernel after 2.6.22 (where sys_read() / sys_open() are not exported)?
  • In general, how to use system calls wrapped in macro SYSCALL_DEFINEn() from within the kernel?

2 Answers 2

You should be aware that you should avoid file I/O from within Linux kernel when possible. The main idea is to go «one level deeper» and call VFS level functions instead of the syscall handler directly:

#include #include #include #include 

Opening a file (similar to open):

struct file *file_open(const char *path, int flags, int rights) < struct file *filp = NULL; mm_segment_t oldfs; int err = 0; oldfs = get_fs(); set_fs(get_ds()); filp = filp_open(path, flags, rights); set_fs(oldfs); if (IS_ERR(filp)) < err = PTR_ERR(filp); return NULL; >return filp; > 

Close a file (similar to close):

void file_close(struct file *file)

Reading data from a file (similar to pread):

int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)

Writing data to a file (similar to pwrite):

int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)

Syncing changes a file (similar to fsync):

int file_sync(struct file *file)

[Edit] Originally, I proposed using file_fsync, which is gone in newer kernel versions. Thanks to the poor guy suggesting the change, but whose change was rejected. The edit was rejected before I could review it.

Thank you. I was thinking to do something similar by replicating sys_read/sys_open functionality. But this is great help. A curiosity, is there any way to use system calls declared using SYSCALL_DEFINE?

I tried this code in kernel 2.6.30 (Ubuntu 9.04) and reading the file crashes the system. Anyone experienced the same issue?

Читайте также:  Поменять имя компьютера linux mint

@Enrico Detoma? Oh, wow. This there any way that you can give me the module you used? Never seen that before?

That immediately raise the question of «why are you doing that FS dance, btw», which is answered quite nicely here: linuxjournal.com/node/8110/print under «Fixing the Address Space» section.

Since version 4.14 of Linux kernel, vfs_read and vfs_write functions are no longer exported for use in modules. Instead, functions exclusively for kernel’s file access are provided:

# Read the file from the kernel space. ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos); # Write the file from the kernel space. ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos); 

Also, filp_open no longer accepts user-space string, so it can be used for kernel access directly (without dance with set_fs ).

What alternatives do we have other than filp_open ? I know we shouldn’t do file operations on userspace files through the kernel, but let’s say we want to.

When I try to open a userspace file, it just fails claiming it was trying to derefernce a null pointer probably because it cannot access a file that is placed in userspace area. E.g ~/.text

There is no such thing like a «file placed in userspace area». All files (including the ones under ~ ) are stored in the single namespace. But the ~ is the concept of the shell: this character is not processed by the kernel and non-shell programs. The kernel is even not aware about a user’s home directory: this concept is maintained by user space part of OS. For access a file under user’s home directory from the kernel you need to specify that directory as «normal» path. E.g. /home/tester/.text .

yea I mean ~/.text was just an example, any other abs path that I provide doesn’t seem to work at all, after debugging the kernel seems to abort with dereferencing a null pointer and it is indeed the first argument that causes it, but if you say so then ok.

Highly active question. Earn 10 reputation (not counting the association bonus) in order to answer this question. The reputation requirement helps protect this question from spam and non-answer activity.

Источник

Оцените статью
Adblock
detector