Linux内核中get_fs与sget_fc的区别及内核模块读取txt文件方法咨询
问题1:get_fs与sget_fc的区别
get_fs()、set_fs()、KERNEL_DS是Linux 5.10及更早版本内核的专用接口,作用是调整进程地址空间的访问权限上限。旧版本内核如果要在内核态直接调用vfs_read/vfs_write读写文件,需要先通过set_fs(KERNEL_DS)把地址访问上限修改为内核空间范围,避免系统调用的用户地址检查拦截内核地址。这套接口在5.10版本之后已经从内核主线完全移除,所以你使用5.11版本内核编译时会报隐式声明错误。- 编译器提示的
sget_fc是完全无关的内核接口,功能是获取文件系统超级块的上下文配置,和地址空间切换没有任何关联,只是函数名拼写和get_fs相近才被编译器当作候选推荐,不需要考虑使用该接口。
问题2:内核模块中正确读取文本文件的实现方案
5.10之后的内核已经提供了原生的kernel_read/kernel_write接口,不需要再手动切换地址空间,你调整后的代码思路是正确的,但存在以下几个问题需要修复:
- 输入缓冲区未分配内存:你定义的
void *in_buf仅为未初始化的空指针,直接传入读取接口会引发内核空指针崩溃,需要用kmalloc申请对应大小的内核内存,使用完成后通过kfree释放。 - 读写长度变量未初始化:
count1、count2都是未初始化的局部变量,值为随机栈垃圾数据,会导致读写长度异常,需要先给长度变量赋值为实际要读写的字节数。 - 日志打印的换行符错误:你代码里的
error/n应为error\n,否则不会正常换行。
以下是修正后的可运行代码:
#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/kernel.h> #include <linux/slab.h> MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Reversing text from Jackson"); MODULE_VERSION("0.1"); #define BUF_SIZE 4096 // 可按需调整缓冲区大小 static int __init test_start(void){ struct file *i_fp, *o_fp; loff_t pos; ssize_t read_cnt, write_cnt; char *in_buf; const char *test_out = "add"; printk(KERN_INFO "start converting...\n"); // 打开文件 i_fp = filp_open("/home/j0000/Desktop/file/input.txt", O_RDONLY, 0); o_fp = filp_open("/home/j0000/Desktop/file/output.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); if (IS_ERR(i_fp)){ printk(KERN_INFO "input file open error\n"); return PTR_ERR(i_fp); } if (IS_ERR(o_fp)){ printk(KERN_INFO "output file open error\n"); filp_close(i_fp, NULL); return PTR_ERR(o_fp); } // 分配缓冲区 in_buf = kmalloc(BUF_SIZE, GFP_KERNEL); if (!in_buf) { printk(KERN_INFO "kmalloc failed\n"); goto out_close; } // 读取文本文件 pos = 0; read_cnt = kernel_read(i_fp, in_buf, BUF_SIZE - 1, &pos); if (read_cnt < 0) { printk(KERN_INFO "kernel_read failed: %ld\n", read_cnt); goto out_free; } in_buf[read_cnt] = '\0'; // 文本末尾加字符串结束符 printk(KERN_INFO "read content: %s\n", in_buf); // 写入测试内容 pos = 0; write_cnt = kernel_write(o_fp, test_out, strlen(test_out), &pos); if (write_cnt < 0) { printk(KERN_INFO "kernel_write failed: %ld\n", write_cnt); } out_free: kfree(in_buf); out_close: filp_close(i_fp, NULL); filp_close(o_fp, NULL); return 0; } static void __exit test_end(void){ printk(KERN_INFO "Ending~\n"); } module_init(test_start); module_exit(test_end);
注意:内核态直接读写文件存在触发死锁、内存泄漏、文件系统不一致的风险,非特殊场景不建议使用,普通文件操作需求优先在用户态实现。
内容的提问来源于stack exchange,提问作者jackson
相关产品推荐
相关产品推荐

