File Read/Write in Linux Kernel Modules: From System Calls to VFS Layer Interfaces

Dec 08, 2025 · Programming · 10 views · 7.8

Keywords: Linux kernel module | file read/write | VFS interface | system call | kernel programming

Abstract: This paper provides an in-depth technical analysis of file read/write operations within Linux kernel modules. Addressing the issue of unexported system calls like sys_read() in kernel versions 2.6.30 and later, it details how to implement file operations through VFS layer functions. The article first examines the limitations of traditional approaches, then systematically explains the usage of core functions including filp_open(), vfs_read(), and vfs_write(), covering key technical aspects such as address space switching and error handling. Finally, it discusses API evolution across kernel versions, offering kernel developers a complete and secure solution for file operations.

Technical Background and Challenges of Kernel File Operations

In Linux kernel development, performing file read/write operations directly from kernel space is generally considered poor practice, primarily due to potential security vulnerabilities, kernel stability risks, and violations of kernel design philosophy. Standard alternatives involve handling file I/O in user space through the <code>/proc</code> filesystem or <code>netlink</code> sockets. However, certain specialized scenarios such as kernel debugging, system monitoring, or specific hardware drivers may genuinely require direct filesystem access from within the kernel.

Historical Evolution of System Call Exporting

Prior to Linux kernel version 2.6.22, developers could directly call exported system call functions like <code>sys_read()</code> and <code>sys_open()</code>. Starting with version 2.6.30, these functions were wrapped within the <code>SYSCALL_DEFINE3</code> macro and are no longer exported for use by kernel modules. Attempting to link against these unexported symbols results in compilation warnings and module loading failures:

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

Core Principles of the VFS Layer Solution

The correct solution involves going one level deeper and directly calling Virtual File System (VFS) layer functions. VFS provides a filesystem-independent abstraction interface, allowing kernel code to access various filesystems in a uniform manner. This approach avoids the system call layer encapsulation while maintaining necessary security boundaries.

Implementation Details of File Operations

Required Header Files

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

File Opening Operation

Use the <code>filp_open()</code> function as a replacement for the traditional <code>open()</code> system call. The key aspect is the temporary switching of address space limits:

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

The calls to <code>get_fs()</code> and <code>set_fs()</code> here temporarily relax address space checking, allowing kernel functions to handle user-space pointers.

File Reading Operation

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

File Writing Operation

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

File Synchronization and Closing

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

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

Kernel API Evolution and Compatibility Considerations

Starting with Linux kernel version 4.14, the <code>vfs_read()</code> and <code>vfs_write()</code> functions are no longer exported for use by kernel modules. The new API provides more specialized functions:

ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);
ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos);

Additionally, <code>filp_open()</code> can now directly accept kernel-space strings, eliminating the need for address space switching via <code>set_fs()</code>. This reflects the kernel's design evolution toward clearer security boundaries.

Best Practices and Important Considerations

1. Always prioritize user-space solutions and only perform file operations in the kernel when absolutely necessary.

2. Strictly check return values of all file operation functions, using <code>IS_ERR()</code> and <code>PTR_ERR()</code> for error handling.

3. Ensure timely closure of file descriptors to prevent resource leaks.

4. Consider kernel version compatibility, using conditional compilation or runtime detection to adapt to different API versions.

5. File operations may block; consider their impact on kernel real-time performance.

Conclusion

Performing file read/write operations within kernel modules requires a deep understanding of Linux kernel's VFS architecture. By directly calling VFS layer functions instead of system calls, developers can bypass symbol export limitations while maintaining code security and maintainability. As kernel versions evolve, APIs continue to be optimized, requiring developers to monitor these changes and adjust implementation strategies accordingly. Proper implementation of these techniques can satisfy special requirements while minimizing impact on kernel stability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.