前言
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
这是我在网上看到的关于文件操作的文章的一个整理和集合,这是第一版。
主要参考:
其原文或有重复,或不妥当之处,均按我的理解在文中做了修改。
第一部分 文件的结构
一,文件的定义
struct file结构体定义在/linux/include/linux/fs.h(Linux <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2.6.11内核)中,其原型是:
二、作用:
文件结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的
struct file
。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,
struct file
的指针通常被命名为
file
或
filp
。
三、各个字段详解:
1
、
union {
struct list_head fu_list;
struct rcu_head rcuhead;
}f_u;
其中的 struct list_head 定义在 linux/include/linux/list.h 中,原型为:
union {
struct list_head fu_list;
struct rcu_head rcuhead;
}f_u;
其中的 struct list_head 定义在 linux/include/linux/list.h 中,原型为:
list_head
是内核中最常用的建立双向循环链表的结构,在此用于通用文件对象链表的指针。
struct rcu_head 定义在 linux/include/linux/rcupdate.h 中,其原型为:
struct rcu_head 定义在 linux/include/linux/rcupdate.h 中,其原型为:
在此用于更新文件。
fu_list
在
file_free()
函数被调用以后就无效了,队列通过
rcu_head
来释放
RCU
。
2 、 struct path f_path;
被定义在 linux/include/linux/namei.h 中,其原型为:
2 、 struct path f_path;
被定义在 linux/include/linux/namei.h 中,其原型为:
在早些版本的内核中并没有此结构,而是直接将
path
的两个数据成员作为
struct file
的数据成员,
struct vfsmount *mnt 的作用是指出该文件的已安装文件系统,
struct dentry *dentry 是与文件相关的目录项对象。
3 、 const struct file_operations *f_op;
被定义在 linux/include/linux/fs.h 中,其中包含着与文件关联的操作,如 :
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。当打开一个文件时,内核就创建一个与该文件相关联的 struct file 结构,其中的 *f_op 就指向的是具体对该文件进行操作的函数。例如用户调用系统调用 read 来读取该文件的内容时,那么系统调用 read 最终会陷入内核调用 sys_read 函数,而 sys_read 最终会调用与该文件关联的 struct file 结构中的 f_op->read 函数对文件内容进行读取。
4 、 atomic_t f_count;
atomic_t 被定义为:
typedef struct { volatile int counter; } atomic_t;
volatile 修饰字段告诉 gcc 不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。本质是 int 类型,之所以这样写是让编译器对基于该类型变量的操作进行严格的类型检查。此处 f_count 的作用是记录对文件对象的引用计数,也即当前有多少个使用 CLONE_FILES 标志克隆的进程在使用该文件。典型的应用是在 POSIX 线程中。就像在内核中普通的引用计数模块一样,最后一个进程调用 put_files_struct() 来释放文件描述符。
5 、 unsigned int f_flags;
当打开文件时指定的标志,对应系统调用 open 的 int flags 参数。驱动程序为了支持非阻塞型操作需要检查这个标志。
六、 mode_t f_mode;
对文件的读写模式,对应系统调用 open 的 mod_t mode 参数。如果驱动程序需要这个值,可以直接读取这个字段。
mod_t 被定义为:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t mode_t;
7 、 loff_t f_pos;
当前的文件指针位置,即文件的读写位置。
loff_t 被定义为:
typedef long long __kernel_loff_t;
typedef __kernel_loff_t loff_t;
8 、 struct fown_struct f_owner;
struct fown_struct 在 linux/include/linux/fs.h 被定义,原型为 :
struct vfsmount *mnt 的作用是指出该文件的已安装文件系统,
struct dentry *dentry 是与文件相关的目录项对象。
3 、 const struct file_operations *f_op;
被定义在 linux/include/linux/fs.h 中,其中包含着与文件关联的操作,如 :
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。当打开一个文件时,内核就创建一个与该文件相关联的 struct file 结构,其中的 *f_op 就指向的是具体对该文件进行操作的函数。例如用户调用系统调用 read 来读取该文件的内容时,那么系统调用 read 最终会陷入内核调用 sys_read 函数,而 sys_read 最终会调用与该文件关联的 struct file 结构中的 f_op->read 函数对文件内容进行读取。
4 、 atomic_t f_count;
atomic_t 被定义为:
typedef struct { volatile int counter; } atomic_t;
volatile 修饰字段告诉 gcc 不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。本质是 int 类型,之所以这样写是让编译器对基于该类型变量的操作进行严格的类型检查。此处 f_count 的作用是记录对文件对象的引用计数,也即当前有多少个使用 CLONE_FILES 标志克隆的进程在使用该文件。典型的应用是在 POSIX 线程中。就像在内核中普通的引用计数模块一样,最后一个进程调用 put_files_struct() 来释放文件描述符。
5 、 unsigned int f_flags;
当打开文件时指定的标志,对应系统调用 open 的 int flags 参数。驱动程序为了支持非阻塞型操作需要检查这个标志。
六、 mode_t f_mode;
对文件的读写模式,对应系统调用 open 的 mod_t mode 参数。如果驱动程序需要这个值,可以直接读取这个字段。
mod_t 被定义为:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t mode_t;
7 、 loff_t f_pos;
当前的文件指针位置,即文件的读写位置。
loff_t 被定义为:
typedef long long __kernel_loff_t;
typedef __kernel_loff_t loff_t;
8 、 struct fown_struct f_owner;
struct fown_struct 在 linux/include/linux/fs.h 被定义,原型为 :
该结构的作用是通过信号进行
I/O
时间通知的数据。
9 、 unsigned int f_uid, f_gid;
标识文件的所有者 id ,所有者所在组的 id.
10 、 struct file_ra_state f_ra;
struct file_ra_state 结构被定义在 /linux/include/linux/fs.h 中,原型为:
9 、 unsigned int f_uid, f_gid;
标识文件的所有者 id ,所有者所在组的 id.
10 、 struct file_ra_state f_ra;
struct file_ra_state 结构被定义在 /linux/include/linux/fs.h 中,原型为:
文件预读状态,文件预读算法使用的主要数据结构,当打开一个文件时,
f_ra
中除了
perv_page(
默认为-
1)
和
ra_apges(
对该文件允许的最大预读量
)
这两个字段外,其他的所有字端都置为
0
。
11 、 unsigned long f_version;
记录文件的版本号,每次使用后都自动递增。
12 、
11 、 unsigned long f_version;
记录文件的版本号,每次使用后都自动递增。
12 、
#ifdef CONFIG_SECURITY
void *f_security;
#endif
此处我的理解是如果在编译内核时配置了安全措施,那么 struct file 结构中就会有 void *f_security 数据项,用来描述安全措施或者是记录与安全有关的信息。
13 、 void *private_data;
系统在调用驱动程序的 open 方法前将这个指针置为 NULL 。驱动程序可以将这个字段用于任意目的,也可以忽略这个字段。驱动程序可以用这个字段指向已分配的数据,但是一定要在内核释放 file 结构前的 release 方法中清除它。
14 、
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
被用在 fs/eventpoll.c 来链接所有钩到这个文件上。其中 f_ep_links 是文件的事件轮询等待者链表的头, f_ep_lock 是保护 f_ep_links 链表的自旋锁。
15 、 struct address_space *f_mapping;
struct address_space 被定义在 /linux/include/linux/fs.h 中,此处是指向文件地址空间的指针。
四、应用:
在驱动开发中,文件读 / 写模式 mode 、标志 f_flags 都是设备驱动关心的内容,而私有数据指针 private_data 在驱动中被广泛使用,大多被指向设备驱动自定义的用于描述设备的结构体。驱动程序中常用如下类似的代码来检测用户打开文件的读写方式:
if (file->f_mode & FMODE_WRITE) // 用户要求可写
{
}
if (file->f_mode & FMODE_READ) // 用户要求可读
{
}
下面的代码可用于判断以阻塞还是非阻塞方式打开设备文件:
if (file->f_flags & O_NONBLOCK) // 非阻塞
pr_debug("open:non-blocking\n");
else // 阻塞
pr_debug("open:blocking\n");
void *f_security;
#endif
此处我的理解是如果在编译内核时配置了安全措施,那么 struct file 结构中就会有 void *f_security 数据项,用来描述安全措施或者是记录与安全有关的信息。
13 、 void *private_data;
系统在调用驱动程序的 open 方法前将这个指针置为 NULL 。驱动程序可以将这个字段用于任意目的,也可以忽略这个字段。驱动程序可以用这个字段指向已分配的数据,但是一定要在内核释放 file 结构前的 release 方法中清除它。
14 、
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
被用在 fs/eventpoll.c 来链接所有钩到这个文件上。其中 f_ep_links 是文件的事件轮询等待者链表的头, f_ep_lock 是保护 f_ep_links 链表的自旋锁。
15 、 struct address_space *f_mapping;
struct address_space 被定义在 /linux/include/linux/fs.h 中,此处是指向文件地址空间的指针。
四、应用:
在驱动开发中,文件读 / 写模式 mode 、标志 f_flags 都是设备驱动关心的内容,而私有数据指针 private_data 在驱动中被广泛使用,大多被指向设备驱动自定义的用于描述设备的结构体。驱动程序中常用如下类似的代码来检测用户打开文件的读写方式:
if (file->f_mode & FMODE_WRITE) // 用户要求可写
{
}
if (file->f_mode & FMODE_READ) // 用户要求可读
{
}
下面的代码可用于判断以阻塞还是非阻塞方式打开设备文件:
if (file->f_flags & O_NONBLOCK) // 非阻塞
pr_debug("open:non-blocking\n");
else // 阻塞
pr_debug("open:blocking\n");
转载于:https://blog.51cto.com/norawoo/287654