内核态文件写入失败(-22)问题及日志轮转功能需求咨询
问题分析与解决方案
写入失败错误码-22(EINVAL)的原因及修复
错误码-22对应内核中的EINVAL(非法参数),你的代码存在两个关键问题:
- 未初始化
pos变量:直接将未赋值的pos传给write函数,导致参数非法 - 直接调用
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
相关产品推荐
相关产品推荐

