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);
关键修正点说明
- 内核内存分配:用
kmalloc分配缓冲区,指定GFP_KERNEL标志(允许睡眠分配内存,适合进程上下文),分配后检查是否成功,避免空指针 - 文件大小获取:通过
vfs_getattr获取输入文件的大小,然后取文件大小和缓冲区最大值的较小值,避免分配过大内存 - 修正kernel_write参数:第二个参数传入实际存储数据的
in_buf,第三个参数传入kernel_read返回的实际读取字节数(确保写入的内容和读取的一致) - 完善错误处理:用
goto cleanup统一处理错误路径,确保所有已打开的文件和已分配的内存都能被正确清理 - 优化文件打开标志:输入文件用
O_RDONLY,输出文件用O_WRONLY | O_CREAT | O_TRUNC,确保文件不存在时创建,存在时清空原有内容 - 内存泄漏防护:在模块退出函数里也检查并释放缓冲区,防止模块异常退出时的内存泄漏
内容的提问来源于stack exchange,提问作者jackson
相关产品推荐
相关产品推荐

