You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux内核15.11版本下使用kernel_read与kernel_write实现文件读写的类型匹配问题求助

解决Linux内核模块中kernel_read/kernel_write的类型匹配及其他问题

我来帮你搞定代码里的这些问题——类型不匹配、未初始化变量这些都是内核模块开发里的常见坑,咱们一步步梳理并修正:

先说说你代码里的核心问题

  • in_buf未初始化:内核空间不能直接使用未分配的野指针,必须通过内核内存分配函数申请合法内存
  • count1未赋值:这个变量用来指定读取的字节数,没有值的话会导致读取行为不可预测
  • kernel_write参数错误:你把kernel_read返回的**读取字节数(ssize_t类型)**当成了缓冲区指针传入kernel_write,这完全是类型不匹配,kernel_write的第二个参数需要的是存储数据的缓冲区指针
  • 错误处理不完整:文件打开失败后没有清理已打开的资源,会造成内核资源泄漏
  • 缺少内存释放:申请的内核内存如果不释放,会导致内存泄漏
  • 文件打开标志不合理:读取input.txt不需要O_RDWR,用O_RDONLY足够;写入output.txt应该加上O_TRUNC,避免原有内容残留

修正后的完整代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>  // 用于kmalloc/kfree
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Copy text from input.txt to output.txt");
MODULE_VERSION("0.1");

#define BUF_MAX_SIZE 4096  // 设置最大缓冲区大小,避免分配过大内存
void *in_buf = NULL;

static int __init test_start(void){
    struct file *i_fp = NULL, *o_fp = NULL;
    loff_t pos = 0;
    size_t count1;
    ssize_t ret;
    struct kstat stat;

    printk(KERN_INFO "Start copying file content...\n");

    // 1. 打开输入文件,只读模式
    i_fp = filp_open("/home/j0000/Desktop/file/input.txt", O_RDONLY, 0644);
    if (IS_ERR(i_fp)){
        printk(KERN_ERR "Failed to open input file!\n");
        ret = PTR_ERR(i_fp);
        goto cleanup;
    }

    // 2. 获取输入文件大小,确定读取的字节数(不超过缓冲区最大值)
    if (vfs_getattr(&i_fp->f_path, &stat, STAT_SIZE, AT_STATX_SYNC_AS_STAT)) {
        printk(KERN_ERR "Failed to get input file size!\n");
        ret = -EIO;
        goto cleanup;
    }
    count1 = min((size_t)stat.size, BUF_MAX_SIZE);

    // 3. 分配内核缓冲区
    in_buf = kmalloc(count1, GFP_KERNEL);
    if (!in_buf) {
        printk(KERN_ERR "Failed to allocate kernel buffer!\n");
        ret = -ENOMEM;
        goto cleanup;
    }

    // 4. 读取输入文件内容到缓冲区
    pos = 0;
    ret = kernel_read(i_fp, in_buf, count1, &pos);
    if (ret < 0) {
        printk(KERN_ERR "Failed to read from input file! Error code: %zd\n", ret);
        goto cleanup;
    }
    printk(KERN_INFO "Successfully read %zd bytes from input file\n", ret);

    // 5. 打开输出文件,写入+创建+截断原有内容模式
    o_fp = filp_open("/home/j0000/Desktop/file/output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (IS_ERR(o_fp)){
        printk(KERN_ERR "Failed to open output file!\n");
        ret = PTR_ERR(o_fp);
        goto cleanup;
    }

    // 6. 将缓冲区内容写入输出文件
    pos = 0;
    ret = kernel_write(o_fp, in_buf, ret, &pos);  // 这里用实际读取的字节数作为写入长度
    if (ret < 0) {
        printk(KERN_ERR "Failed to write to output file! Error code: %zd\n", ret);
        goto cleanup;
    }
    printk(KERN_INFO "Successfully wrote %zd bytes to output file\n", ret);

    ret = 0;  // 执行成功,返回0

cleanup:
    // 关闭已打开的文件
    if (!IS_ERR_OR_NULL(i_fp)) {
        filp_close(i_fp, NULL);
    }
    if (!IS_ERR_OR_NULL(o_fp)) {
        filp_close(o_fp, NULL);
    }
    // 释放分配的内核缓冲区
    if (in_buf) {
        kfree(in_buf);
        in_buf = NULL;
    }
    return ret;
}

static void __exit test_end(void){
    // 退出时确保缓冲区已释放(防止异常退出时的内存泄漏)
    if (in_buf) {
        kfree(in_buf);
        in_buf = NULL;
    }
    printk(KERN_INFO "Module exited successfully~\n");
}

module_init(test_start);
module_exit(test_end);

关键修正点说明

  1. 内核内存分配:用kmalloc分配缓冲区,指定GFP_KERNEL标志(允许睡眠分配内存,适合进程上下文),分配后检查是否成功,避免空指针
  2. 文件大小获取:通过vfs_getattr获取输入文件的大小,然后取文件大小和缓冲区最大值的较小值,避免分配过大内存
  3. 修正kernel_write参数:第二个参数传入实际存储数据的in_buf,第三个参数传入kernel_read返回的实际读取字节数(确保写入的内容和读取的一致)
  4. 完善错误处理:用goto cleanup统一处理错误路径,确保所有已打开的文件和已分配的内存都能被正确清理
  5. 优化文件打开标志:输入文件用O_RDONLY,输出文件用O_WRONLY | O_CREAT | O_TRUNC,确保文件不存在时创建,存在时清空原有内容
  6. 内存泄漏防护:在模块退出函数里也检查并释放缓冲区,防止模块异常退出时的内存泄漏

内容的提问来源于stack exchange,提问作者jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 19:04:10