Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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! 

Obviously insmod cannot load the module because linking does not happen correctly.

Questions:

  • 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?
like image 840
Methos Avatar asked Jul 26 '09 10:07

Methos


People also ask

How do I write a kernel module to a file?

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.

How do I open a kernel file?

If you cannot open your KERNEL file correctly, try to right-click or long-press the file. Then click "Open with" and choose an application.

What is Linux kernel programming?

The Linux® kernel is the main component of a Linux operating system (OS) and is the core interface between a computer's hardware and its processes. It communicates between the 2, managing resources as efficiently as possible.


1 Answers

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:

Includes:

#include <linux/fs.h> #include <asm/segment.h> #include <asm/uaccess.h> #include <linux/buffer_head.h> 

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)  {     filp_close(file, NULL); } 

Reading data from a file (similar to pread):

int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)  {     mm_segment_t oldfs;     int ret;      oldfs = get_fs();     set_fs(get_ds());      ret = vfs_read(file, data, size, &offset);      set_fs(oldfs);     return ret; }    

Writing data to a file (similar to pwrite):

int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)  {     mm_segment_t oldfs;     int ret;      oldfs = get_fs();     set_fs(get_ds());      ret = vfs_write(file, data, size, &offset);      set_fs(oldfs);     return ret; } 

Syncing changes a file (similar to fsync):

int file_sync(struct file *file)  {     vfs_fsync(file, 0);     return 0; } 

[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.

like image 74
dmeister Avatar answered Sep 21 '22 13:09

dmeister