在Linux内核模块中读/写文件

Met*_*hos 89 c file-io kernel-module linux-kernel

我知道所有关于为什么不应该从内核读/写文件的讨论,而是如何使用/ procnetlink来做到这一点.无论如何我想读/写.我也读过" 驾驶我的坚果 - 你应该在内核中做的事情".

但问题是2.6.30不能导出sys_read().相反,它包含在内SYSCALL_DEFINE3.因此,如果我在我的模块中使用它,我会收到以下警告:

WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!
Run Code Online (Sandbox Code Playgroud)

显然insmod无法加载模块,因为链接没有正确发生.

问题:

  • 如何在2.6.22之后在内核中读/写(哪里sys_read()/ sys_open()不导出)?
  • 一般来说,如何使用SYSCALL_DEFINEn()内核中包含宏的系统调用?

dme*_*ter 114

您应该知道,应尽可能避免文件I/O. 主要思想是"更深层次"并直接调用VFS级别函数而不是syscall处理程序:

包括:

#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
Run Code Online (Sandbox Code Playgroud)

打开文件(类似于打开):

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;
}
Run Code Online (Sandbox Code Playgroud)

关闭文件(类似于关闭):

void file_close(struct file *file) 
{
    filp_close(file, NULL);
}
Run Code Online (Sandbox Code Playgroud)

从文件中读取数据(类似于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;
}   
Run Code Online (Sandbox Code Playgroud)

将数据写入文件(类似于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;
}
Run Code Online (Sandbox Code Playgroud)

同步更改文件(类似于fsync):

int file_sync(struct file *file) 
{
    vfs_fsync(file, 0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

[编辑]最初,我建议使用file_fsync,它在较新的内核版本中消失了.感谢可怜的家伙提出改变,但他的改变被拒绝了.在我审核之前,编辑被拒绝了.

  • 我在内核2.6.30(Ubuntu 9.04)中尝试了这段代码并且读取文件会导致系统崩溃.有人经历过同样的问题吗? (5认同)
  • 谢谢.我想通过复制sys_read/sys_open功能来做类似的事情.但这是很有帮助的.好奇心,有没有办法使用SYSCALL_DEFINE声明的系统调用? (2认同)
  • 这立即提出了"你为什么要做FS跳舞,btw"的问题,这里的答案相当不错:http://www.linuxjournal.com/node/8110/print"修复地址空间"部分. (2认同)

Tsy*_*rev 11

由于Linux内核的版本4.14,vfs_readvfs_write功能都不再出口在模块一起使用。而是提供了专门用于内核文件访问的功能:

# 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);
Run Code Online (Sandbox Code Playgroud)

另外,filp_open不再接受用户空间字符串,因此可以将其直接用于内核访问(无需与跳舞set_fs)。