内核态的文件操作函数:filp_open、filp_close、vfs_read、vfs_write、set_fs、get_fs
创始人
2024-03-28 02:45:27
0

关于用户态的文件操作函数我们知道有open、read、write这些。但是这些的实现都是依赖于库的实现,但是在内核态是没有库函数可用的。最近做测试,在内核态中,需要学习一下在内核态里面的文件操作函数。分为三对出现。

感谢前辈的优秀文章,参考链接在文末

这些的函数就在linux/fs.h和asm/uaccess.h中存在。

1、第一对:filp_open、filp_close–文件开关操作

filp_open

struct file* filp_open(const char* filename, int open_mode, int mode);
第一个参数表明要打开或创建文件的名称(包括路径部分)。第二个参数文件的打开方式,其取值与标准库中的open相应参数类似,可以取O_CREAT,O_RDWR,O_RDONLY等。第三个参数创建文件时使用,设置创建文件的读写权限,其它情况可以设为0

filp_close

int filp_close(struct file *filp, fl_owner_t id);
第一个参数是filp_open返回的file结构体指针第二个参数基本上都是NULL

2、第二对:vfs_read、vfs_write–文件读写操作

//读文件
ssize_t vfs_read(struct file *filp, char __user *buffer, size_t len, loff_t *pos);
//写文件
ssize_t vfs_write(struct file *filp, const char __user *buffer, size_t len, loff_t *pos);
filp:文件指针,由filp_open()函数返回。buffer:缓冲区,从文件中读出的数据放到这个缓冲区,向文件中写入数据也在这个缓冲区。len:从文件中读出或者写入文件的数据长度。pos:为文件指针的位置,即从什么地方开始对文件数据进行操作。

3、第三队:set_fs、get_fs

在buffer前面都有一个__user修饰符,这要求buffer指针应该指向用户的空间地址。如果在内核中使用上述的两个函数直接进行文件操作,将内核空间的指针传入的时候,函数会返回失败EFAULT。但在Linux内核中,一般不容易生成用户空间的指针,或者不方便独立使用用户空间内存。为了使这两个函数能够正常工作,必须使得这两个函数能够处理内核空间的地址。

使用set_fs()函数可以指定上述两个函数对缓冲区地址的处理方式,原型如下:

  • 这个函数改变内核对内存检查的处理方式,将内存地址的检查方式设置为用户指定的方式。参数fs取的值有两个:USER_DS和KERNEL_DS。分别代表用户空间和内核空间。
  • 在默认情况下,内核对地址的检查方式为USER_DS,即按照用户空间进行地址检查并进行用户地址空间到内核地址空间的变换。如果函数中要使用内核地址空间,需要使用set_fs(KERNEL_DS)函数进行设置。与set_fs()函数对应,get_fs()函数获得当前的设置,在使用set_fs()之前先调用get_fs()函数获得之前的设置对文件进行操作后,使用set_fs()函数还原之前的设置。

内核空间文件续写的框架为:

mm_segmen_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
...
set_fs(old_fs)

**注意:**使用vfs_read()和vfs_write()的时候,要注意最后的参数loff_t *pos,pos所指向的值必须要进行初始化,表明从文件的什么位置进行读写。使用此参数可以对续写文件的位置进行设定,这可以完成用户空间中lseek()函数的功能

整个栗子

1、简单版

下面是一个使用内核空间的文件读函数从文件中读取数据的例子:

ssize_t ReadFile(struct file *filp, char __user *buffer, size_t len, loff_t *pos)
{ssize_t count = 0;oldfs = get_fs();set_fs(KERNEL_DS);count = file->f_op->read(filp, buf, len, &file->f_pos);set_fs(oldfs);return count;
}

2、进阶版

源码

//kernel
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//user#define DBGPRINT printk//内核程序使用file_open来打开文件
struct file *SIPFW_OpenFile(const char *filename, int flags, int mode)
{struct file *f = NULL;DBGPRINT("==>SIPFW_OpenFile\n");f = filp_open(filename, flags, 0);if (!f || IS_ERR(f)){f = NULL;}DBGPRINT("<==SIPFW_OpenFile\n");return f;
}ssize_t SIPFW_ReadLine(struct file *f, char *buf, size_t len)
{
#define EOF (-1)ssize_t count = -1;mm_segment_t oldfs;struct inode *inode;//DBGPRINT("==>SIPFW_ReadLine\n");if (!f || IS_ERR(f) || !buf || len <= 0) {goto out_error;}if (!f || !f->f_inode){goto out_error;}inode = f->f_inode;if (!(f->f_mode & FMODE_READ)){goto out_error;}if (f->f_op /*&& f->f_op->read*/) {oldfs = get_fs();set_fs(KERNEL_DS);count = 0;if (vfs_read(f, buf, 1, &f->f_pos) <= 0){DBGPRINT("file read failure\n");goto out;}if (*buf == EOF){DBGPRINT("file EOF\n");goto out;}count = 1;while (*buf != EOF && *buf != '\0' && *buf != '\n' && *buf != '\r' && count < len  && f->f_pos <= inode->i_size){buf 	+= 1;count 	+= 1;if (vfs_read(f, buf, 1, &f->f_pos) <= 0) {count -= 1;break;}}} else{DBGPRINT("goto out_error\n");goto out_error;}if (*buf == '\r'|| *buf =='\n' ||*buf == EOF ) {*buf = '\0';count -= 1;} else{buf += 1;*buf = '\0';}out:set_fs(oldfs);
out_error://DBGPRINT("<==SIPFW_ReadLine %d\n", count);return count;
}// ssize_t SIPFW_WriteLine(struct file *f, char *buf, size_t len)
// {
// 	ssize_t count = -1;
// 	mm_segment_t oldfs;
// 	struct inode *inode;
// 	DBGPRINT("==>SIPFW_WriteLine\n");// 	if (!f || IS_ERR(f) || !buf || len <= 0) 
// 	{
// 		goto out_error;
// 	}// 	if (!f || !f->f_dentry || !f->f_dentry->d_inode)
// 	{
// 		goto out_error;
// 	}// 	inode = f->f_dentry->d_inode;// 	if (!(f->f_mode & FMODE_WRITE) || !(f->f_mode & FMODE_READ) )
// 	{
// 		goto out_error;
// 	}// 	if (f->f_op && f->f_op->read && f->f_op->write) 
// 	{
// 		//f->f_pos = f->f_count;
// 		oldfs = get_fs();
// 		set_fs(KERNEL_DS);
// 		count = 0;// 		count = f->f_op->write(f, buf, len, &f->f_pos) ;// 		if (count == -1)
// 		{
// 			goto out;
// 		}		
// 	} 
// 	else	
// 	{
// 		goto out_error;
// 	}// out:
// 	set_fs(oldfs);
// out_error:
// 	DBGPRINT("<==SIPFW_WriteLine\n");
// 	return count;
// }void SIPFW_CloseFile(struct file *f)
{DBGPRINT("==>SIPFW_CloseFile\n");if(!f)return;filp_close(f, current->files);DBGPRINT("<==SIPFW_CloseFile\n");
}int SIPFW_HandleConf(void)
{int retval = 0,count;int l = 0;char *pos = NULL;struct file *f = NULL;char line[256] = { 0 };DBGPRINT("==>SIPFW_HandleConf\n");//	提前建一个/etc/sipfw.conf文件吧f = SIPFW_OpenFile("/etc/sipfw.conf", O_RDWR, 0);if(f == NULL){retval = -1;DBGPRINT("SIPFW_OpenFile called failure\n");goto EXITSIPFW_HandleConf;}while((count = SIPFW_ReadLine(f, line, 256)) > 0){pos = line;DBGPRINT("line = %d, data: %s\n", l, line);\l++;memset(line, 0, sizeof(line));}SIPFW_CloseFile(f);	EXITSIPFW_HandleConf:DBGPRINT("<==SIPFW_HandleConf\n");return retval;
}static int __init SIPFW_Init(void)
{int ret = -1;DBGPRINT("==>SIPFW_Init\n");ret = SIPFW_HandleConf();DBGPRINT("<==SIPFW_Init\n");return ret;
}static void __exit SIPFW_Exit(void)
{DBGPRINT("==>SIPFW_Exit\n");DBGPRINT("<==SIPFW_Exit\n");
}module_init(SIPFW_Init);
module_exit(SIPFW_Exit);
MODULE_LICENSE("GPL/BSD");

Makefile:

MODULE_NAME :=main_file
obj-m :=$(MODULE_NAME).oKERNELDIR = /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)all:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesclean:$(MAKE) -C $(KERNELDIR) M=$(PWD) clean

测试中读取的文件:(/etc/sipfw.conf)

在这里插入图片描述

运行效果:
https://www.freesion.com/images/776/0b01da97ef33a4353bbbd347575fd938.png

参考链接:
https://blog.csdn.net/weixin_42343585/article/details/81205246
https://www.freesion.com/article/4416178909/

相关内容

热门资讯

北京专业离婚律师服务分析(20... 随着社会经济结构的变化与个人权利意识的增强,婚姻家事法律服务需求日益呈现出专业化、精细化的趋势。在北...
海南自贸港封关超十日 多项政策... 本月18日,海南自由贸易港正式启动全岛封关运作,到今天(28日)已超过10天,多项从封关起实施的“升...
涉嫌恶意串通,伪造借条提起诉讼... 为逃避债务、规避法院执行 田某华串通亲友、伪造借条 向海南省海口市美兰区人民法院 提起诉讼 美兰法院...
原创 在... 在古代,被皇帝赐死其实是一种特殊的待遇,而不仅仅是死亡本身值得关注,更应看赐字所体现的意义。 首...
原创 2... 近日,拥有287万粉丝的抖音网红主播王某强(账号名:某某超市)因被曝多次犯下刑事罪行引发舆论哗然,相...
全球货币政策为何出现明显分化? 2025年岁末,全球金融市场出现“超级央行周”。 从12月10日开始,美国、日本、英国、欧盟、俄罗斯...
广汽自主品牌“三担责”政策发布 IT之家 12 月 28 日消息,广汽集团今日正式发布自主品牌“三担责”政策:三电问题自燃、电池衰减...
原创 他... John McAvoy 是一位来自英国的铁人三项运动员,创造了多个世界纪录,其中包括100,000米...
原创 高... 12月26日这一天,对日本右翼势力来说,具有非常特殊的意义,甚至可能成为东亚局势的一个重要导火索。日...
石景山检察院:侵犯知识产权犯罪... 新京报讯(记者张静姝)12月24日上午,北京市石景山区人民检察院(以下简称“石景山区检察院”)在中关...