fget()函数的功能是通过文件描述符查找并返回file结构体。本函数是从当前进程中获得file_struct结构体,然后通过fcheck_files()函数,传入参数为file_struct结构体和文件描述符fd来获取相对应的file结构体。在此期间,还用到了rcu锁进行文件读写操作的控制。
fget文件包含
#include <linux/file.h>
fget函数定义
在内核源码中的位置:linux-3.19.3/fs/f ile.c
函数定义格式:
struct file *fget(unsigned int fd)
注:RCU是Read-Copy-Update的缩写,也就是读-拷贝-修改。对于被RCU保护的共享数据结构,读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然后对副本进行修改,最后使用一个回调(callback)机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据。
fget输入参数说明
fd
:这是一个整型变量,表示file结构体所对应的文件描述符。
fget返回参数说明
fget()
函数的返回值是一个file结构体,是与文件描述符fd所对应的文件描述结构体file。结构体file在内核源码中的定义见文件linux-3.19.3/include/linux/fs.h,如下:
struct file {
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
struct inode *f_inode;
const struct file_operations *f_op; /*文件的操作函数*/
spinlock_t f_lock; /*保护f_ep_links链表的自旋锁*/
atomic_long_t f_count; /*文件对象的引用计数器*/
unsigned int f_flags; /*当打开文件时所指定的标志*/
fmode_t f_mode; /*进程的访问方式*/
struct mutex f_pos_lock;
loff_t f_pos; /*当前的文件位移量*/
struct fown_struct f_owner; /* 通过信号进行I/O事件通知的数据*/
const struct cred *f_cred;
struct file_ra_state f_ra; /*文件预读状态*/
u64 f_version; /*版本号*/
#ifdef CONFIG_SECURITY
void *f_security; /*指向文件对象的安全结构的指针*/
#endif
void *private_data; /*指向特定文件系统或设备驱动程序所需的数据的指针*/
#ifdef CONFIG_EPOLL
struct list_head f_ep_links;
struct list_head f_tfile_llink; /*文件的事件轮询等待者链表的头*/
#endif
struct address_space *f_mapping; /*指向文件地址空间对象的指针*/
}; __attribute__((aligned(4)));
fget实例解析
编写测试文件:fget.c
头文件声明如下:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/path.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
模块初始化函数:
int fget_init(void)
{
// 查找文件描述符为0的文件所对应的file结构体
struct file *fs1=fget(0);
printk("In the first exec: returned value of f_flags is :%d.\n", fs1->f_flags);
// 查找文件描述符为2的文件所对应的file结构体
struct file *fs2=fget(2);
printk("In the second exec: returned value of f_flags is :%d.\n", fs2->f_flags);
// 查找文件描述符为1000的文件所对应的file结构体
/*struct file *fs3=fget(1000);
if(fs3==NULL)
printk("There is no file which fd is 1000\n");
else
printk("In the third exec: returned value of f_flags is :%d. \n", fs3->f_flags);
*/
return 0;
}
模块退出函数:
void fget_exit(void)
{
printk("Goodbye fget\n");
}
模块初始化及退出函数调用:
module_init(fget_init);
module_exit(fget_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod fget.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
通过传入文件描述符fd(值为0),来获取文件(即file结构体),并显示结果为其中的字段file->f_flags为32770,说明该file结构体是存在的(若不存在则会返回NULL),即通过文件描述符0找到了该f ile结构体。对于fd=2也是如此。
扩展分析:
去掉对fd=1000的部分代码的注释,重新编译模块,执行命令insmod fget.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。从输出结果可以看出,文件描述符的值为1000的文件不存在。