Read/write files within a Linux kernel module

后端 未结 2 698
一个人的身影
一个人的身影 2020-11-22 03:29

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 anyw

相关标签:
2条回答
  • 2020-11-22 04:15

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

    0 讨论(0)
  • 2020-11-22 04:16

    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.

    0 讨论(0)
提交回复
热议问题