如何在内核代码中删除/tmp目录文件?内核驱动文件卸载后未删除怎么办?
在内核代码中删除文件的解决方案
一、内核态删除/tmp目录下任意文件的通用方法
在内核空间里,咱们没法直接调用用户态的unlink()系统调用,得用VFS(虚拟文件系统)层的vfs_unlink()函数来完成删除操作。具体步骤如下:
- 解析文件路径:用
kern_path()把用户可读的文件路径转换成内核能处理的struct path结构,这个结构包含了文件的目录项(dentry)和挂载信息(vfsmount)。 - 执行删除操作:调用
vfs_unlink(),需要传入父目录的inode、目标文件的dentry,属性参数一般传NULL就行。 - 清理资源:操作完成后用
path_put()释放struct path的引用,避免内存泄漏。
代码示例
#include <linux/fs.h> #include <linux/sched.h> int delete_tmp_file(const char *filename) { struct path path; char full_path[64]; int ret; // 拼接/tmp下的完整文件路径 snprintf(full_path, sizeof(full_path), "/tmp/%s", filename); // 解析路径,LOOKUP_FOLLOW表示自动跟随符号链接 ret = kern_path(full_path, LOOKUP_FOLLOW, &path); if (ret != 0) { pr_err("Failed to resolve path %s: error %d\n", full_path, ret); return ret; } // 可选:判断目标是否为普通文件,避免误删目录 if (!S_ISREG(path.dentry->d_inode->i_mode)) { pr_err("%s is not a regular file\n", full_path); path_put(&path); return -EINVAL; } // 调用vfs_unlink执行删除 ret = vfs_unlink(path.dentry->d_parent->d_inode, path.dentry, NULL); if (ret != 0) { pr_err("Failed to delete %s: error %d\n", full_path, ret); } else { pr_info("Successfully deleted %s\n", full_path); } // 释放路径引用 path_put(&path); return ret; }
关键注意事项
- 上下文限制:
kern_path()和vfs_unlink()都可能触发睡眠,绝对不能在中断上下文、持有自旋锁的原子上下文里调用这些函数。 - 安全策略:内核态操作权限很高,但如果系统开了SELinux/AppArmor这类安全模块,可能需要额外配置策略才能让模块顺利删除文件。
- 错误处理:一定要检查每个函数的返回值,比如文件不存在、权限不足这些情况都要妥善处理,别让模块崩了。
二、模块卸载时删除已创建的/tmp/output文件
你用filp_open()创建文件后,filp_close()只是关闭文件句柄,并不会删除文件本身。要实现模块卸载时自动删除它,只需要在模块的exit函数里加入删除逻辑就行。
完整模块示例片段
#include <linux/module.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/uaccess.h> static struct file *output_file; static int __init my_module_init(void) { // 创建并打开/tmp/output,权限设为0644 output_file = filp_open("/tmp/output", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (IS_ERR(output_file)) { pr_err("Failed to open /tmp/output: %ld\n", PTR_ERR(output_file)); return PTR_ERR(output_file); } // 可选:写入内容到文件 // char buf[] = "Hello from kernel module!"; // kernel_write(output_file, buf, sizeof(buf)-1, &output_file->f_pos); pr_info("Module loaded, /tmp/output created\n"); return 0; } static void __exit my_module_exit(void) { // 先关闭文件句柄(如果之前没关闭) if (output_file && !IS_ERR(output_file)) { filp_close(output_file, NULL); output_file = NULL; } // 删除/tmp/output文件 struct path path; int ret = kern_path("/tmp/output", LOOKUP_FOLLOW, &path); if (ret == 0) { ret = vfs_unlink(path.dentry->d_parent->d_inode, path.dentry, NULL); if (ret == 0) { pr_info("/tmp/output deleted on module unload\n"); } else { pr_err("Failed to delete /tmp/output: %d\n", ret); } path_put(&path); } else { pr_warn("/tmp/output does not exist, skip deletion\n"); } pr_info("Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Example module to create and auto-delete /tmp/output");
额外提示
- 如果模块运行中会多次操作这个文件,可以保存文件的
struct path或dentry引用(注意维护引用计数),不用每次删除都重新解析路径。 - 模块卸载时一定要清理所有资源,包括文件句柄、动态分配的内存等,避免留下资源泄漏的隐患。
内容的提问来源于stack exchange,提问作者arry
相关产品推荐
相关产品推荐

