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

内核态文件写入失败(-22)问题及日志轮转功能需求咨询

问题分析与解决方案

写入失败错误码-22(EINVAL)的原因及修复

错误码-22对应内核中的EINVAL(非法参数),你的代码存在两个关键问题:

  1. 未初始化pos变量:直接将未赋值的pos传给write函数,导致参数非法
  2. 直接调用file->f_op->write未处理O_APPEND逻辑:O_APPEND标志需要内核自动维护文件写入位置,直接调用文件操作的write方法会绕过这个逻辑,应该使用内核提供的vfs_write函数

新增功能实现(文件大小限制、旧文件转存、清空原文件)

要实现你需要的三个功能,核心逻辑是:每次写入前获取当前文件实际大小,计算写入后总大小,若超过10KB(10240字节)则转存原文件到SLID_FILE_PATH.old,再清空原文件后写入新数据。

修改后的完整代码

#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#define MAX_FILE_SIZE 10240  // 10KB
#define OLD_FILE_PATH SLID_FILE_PATH ".old"

static int writeMsgToFile(const char *data) {
    struct file *file, *old_file;
    mm_segment_t old_fs;
    loff_t curr_size, write_size, total_size;
    int ret, read_ret, write_old_ret;
    char *buf;

    // 打开目标文件,使用O_RDWR以便后续截断
    file = filp_open(SLID_FILE_PATH, O_RDWR | O_CREAT, 0666);
    if (IS_ERR(file)) {
        printk(KERN_ERR "Failed to open file: %ld\n", PTR_ERR(file));
        return PTR_ERR(file);
    }

    old_fs = get_fs();
    set_fs(get_ds());

    // 获取当前文件实际大小
    curr_size = vfs_llseek(file, 0, SEEK_END);
    if (curr_size < 0) {
        printk(KERN_ERR "Failed to get file size: %lld\n", curr_size);
        ret = curr_size;
        goto close_file;
    }

    write_size = strlen(data);
    total_size = curr_size + write_size;

    // 检查是否超过大小限制,若超过则转存旧文件
    if (total_size > MAX_FILE_SIZE) {
        // 打开旧文件,覆盖写入
        old_file = filp_open(OLD_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (IS_ERR(old_file)) {
            printk(KERN_ERR "Failed to open old file: %ld\n", PTR_ERR(old_file));
            ret = PTR_ERR(old_file);
            goto close_file;
        }

        // 分配缓冲区读取原文件内容
        buf = kmalloc(curr_size, GFP_KERNEL);
        if (!buf) {
            printk(KERN_ERR "Failed to allocate buffer\n");
            ret = -ENOMEM;
            goto close_old_file;
        }

        // 回到文件开头读取内容
        vfs_llseek(file, 0, SEEK_SET);
        read_ret = vfs_read(file, buf, curr_size, &curr_size);
        if (read_ret < 0) {
            printk(KERN_ERR "Failed to read file content: %d\n", read_ret);
            ret = read_ret;
            goto free_buf;
        }

        // 将读取的内容写入旧文件
        write_old_ret = vfs_write(old_file, buf, read_ret, &curr_size);
        if (write_old_ret < 0) {
            printk(KERN_ERR "Failed to write to old file: %d\n", write_old_ret);
            ret = write_old_ret;
            goto free_buf;
        }

        // 截断原文件到0大小
        ret = vfs_truncate(file, 0);
        if (ret < 0) {
            printk(KERN_ERR "Failed to truncate file: %d\n", ret);
            goto free_buf;
        }

        // 重置当前文件大小为0,准备写入新数据
        curr_size = 0;

free_buf:
        kfree(buf);
close_old_file:
        filp_close(old_file, NULL);
        if (ret < 0) {
            goto close_file;
        }
    }

    // 移动到文件末尾写入新数据
    vfs_llseek(file, curr_size, SEEK_SET);
    ret = vfs_write(file, data, write_size, &curr_size);
    if (ret < 0) {
        printk(KERN_ERR "Failed to write to file: %d\n", ret);
    } else {
        printk(KERN_INFO "Data written successfully\n");
    }

close_file:
    set_fs(old_fs);
    filp_close(file, NULL);
    return ret;
}

关键代码说明

  • 使用vfs_write/vfs_read/vfs_llseek替代直接调用文件操作方法,确保内核处理文件标志(如O_APPEND)和指针位置的逻辑正确
  • 通过vfs_truncate实现清空原文件的操作
  • 使用kmalloc动态分配缓冲区读取原文件内容,转存到file.old后释放内存
  • 每次操作都检查返回值,确保错误能被及时捕获和处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:55:29