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


98

我知道所有关于为什么不应该从内核读取/写入文件,而是如何使用/ procnetlink来执行此操作的讨论。我还是想读/写。我还阅读了《 驾驶我的坚果》-内核中不应该做的事情

但是,问题在于2.6.30无法导出sys_read()。相反,它被包裹在SYSCALL_DEFINE3。因此,如果我在模块中使用它,则会收到以下警告:

WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!

显然insmod无法加载模块,因为链接未正确进行。

问题:

  • 2.6.22之后如何在内核中读取/写入(其中sys_read()/ sys_open()不导出)?
  • 通常,如何使用SYSCALL_DEFINEn()内核中包装在宏中的系统调用?

Answers:


121

您应该意识到,应尽可能避免在Linux内核中进行文件I / O。主要思想是“更深一层”并调用VFS级别的函数,而不是直接调用syscall处理程序:

包括:

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

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

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

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

void file_close(struct file *file) 
{
    filp_close(file, NULL);
}

从文件读取数据(类似于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;
}   

将数据写入文件(类似于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;
}

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

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

[编辑]最初,我建议使用file_fsync,在较新的内核版本中已不再使用。感谢那个可怜的家伙提出的改变,但拒绝了他的改变。该修改在我可以进行审核之前被拒绝。


2
谢谢。我正在考虑通过复制sys_read / sys_open功能来做类似的事情。但这是很大的帮助。出于好奇,有什么方法可以使用通过SYSCALL_DEFINE声明的系统调用?
Methos

5
我在内核2.6.30(Ubuntu 9.04)中尝试了此代码,并且读取文件使系统崩溃。有人遇到过同样的问题吗?
恩里科·德托玛

@Enrico Detoma?哦,哇 有什么办法可以给我您使用的模块?没见过吗?
dmeister

2
这立即引发了一个问题:“为什么您要做FS舞蹈,顺便说一句”,在这里很不错的回答:linuxjournal.com/node/8110/print,位于“固定地址空间”部分。
PypeBros 2011年

@dmeister,找不到适用于您的链接VFS级别功能的对象
2014年

18

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.