文件对象表示进程已打开的文件。进程直接处理的是文件,而不是超级块、索引节点或目录项。
文件对象是已打开文件在内存的表示。该对象(不是物理文件)由相应的open()系统调用创建,由close()系统调用销毁,所有这些文件相关的调用实际上都是文件操作表中定义的方法。
因为多个进程可以同时打开和操作同一个文件,所以同一个文件也可能存在多个对应的文件对象。文件对象仅仅在进程观点上代表已打开的文件,它反过来指向目录项对象(目录项对象反过来指向索引节点),其实只有目录项对象才表示已打开的实际文件。虽然一个文件对应的文件对象不是唯一的,但对应的索引节点和目录项对象是唯一的。
文件对象由file结构体表示:
- 在<Fs.h(include/linux)>中
- struct file {
- /*
- * fu_list becomes invalid after file_free is called and queued via
- * fu_rcuhead for RCU freeing
- */
- union {
- struct list_head fu_list;
- struct rcu_head fu_rcuhead;
- } f_u;
- struct path f_path;
- #define f_dentry f_path.dentry
- #define f_vfsmnt f_path.mnt
- const struct file_operations *f_op;
- atomic_t f_count;
- unsigned int f_flags;
- mode_t f_mode;
- loff_t f_pos;
- struct fown_struct f_owner;
- unsigned int f_uid, f_gid;
- struct file_ra_state f_ra;
- unsigned long f_version;
- #ifdef CONFIG_SECURITY
- void *f_security;
- #endif
- /* needed for tty driver, and maybe others */
- void *private_data;
- #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 */
- struct address_space *f_mapping;
- };
类似于目录项对象,文件对象实际上没有对应的磁盘数据。所以在结构体中没有代表其对象是否为脏,是否需要写回磁盘的标志。文件对象通过f_dentry指针执行相关的目录项对象。目录项会执行相关的索引节点,索引节点会记录文件是否为脏。
- 文件操作
- /*
- * NOTE:
- * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
- * can be called without the big kernel lock held in all filesystems.
- */
- struct file_operations {
- struct module *owner;
- /*该函数用于更新偏移量指针。由系统调用llseek()调用它*/
- loff_t (*llseek) (struct file *, loff_t, int);
- /*该函数从给定文件的偏移处读取第三个参数指定大小的字节数据到第二个参数指定的缓冲中,同时更新文件指针。由系统调用read()调用它。*/
- ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- /*该函数从给定的缓冲区中取出指定字节的数据写入指定文件的偏移处,同时更新文件指针。由系统调用write()调用它。*/
- ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- /*该函数从第一个参数指定的文件中,以同步方式读取指定字节的数据到缓冲区中。由系统调用ait_read()调用它*/
- ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- /*该函数以同步方式从给定的缓冲区中取出指定字节的数据,写入第一个参数指定的文件中。由系统调用aio_write()调用它*/
- ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
- /*该函数返回目录列表中的下一个目录。由系统调用readdir()调用它。*/
- int (*readdir) (struct file *, void *, filldir_t);
- /*该函数睡眠等待给定文件的活动。由系统调用poll()调用它*/
- unsigned int (*poll) (struct file *, struct poll_table_struct *);
- /*该函数用来给设备发送命令参数对。当文件是一个被打开的设备节点时,可以通过它进行设置操作。由系统调用ioctl()调用它。*/
- int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
- /*该函数*/
- long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
- /**/
- long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
- /*该函数将给定的文件映射到指定的地址空间上。由系统调用mmap()调用它*/
- int (*mmap) (struct file *, struct vm_area_struct *);
- /*该函数创建一个新的文件对象,并将它和相应索引节点对象关联起来。由系统调用open()调用它*/
- int (*open) (struct inode *, struct file *);
- /*当已打开文件的引用计数减少时,该函数被VFS调用。它的作用根据具体文件系统而定*/
- int (*flush) (struct file *, fl_owner_t id);
- /*当文件的最后一个引用被注销时,该函数会被VFS调用。它的作用根据具体文件系统而定*/
- int (*release) (struct inode *, struct file *);
- /*将给定文件的所有被缓存的数据写回磁盘。该函数由fsync()调用*/
- int (*fsync) (struct file *, struct dentry *, int datasync);
- /*将第一个参数指定的文件的所有被缓存数据写回到磁盘。该函数由系统调用aio_fsync()调用*/
- int (*aio_fsync) (struct kiocb *, int datasync);
- /*该函数用于打开或关闭异步I/O的通告信号*/
- int (*fasync) (int, struct file *, int);
- /*该函数用于给指定文件上锁*/
- int (*lock) (struct file *, int, struct file_lock *);
- /*该函数用于从一个文件拷贝数据到另一个文件中,它执行的拷贝操作完全在内核中完成,避免了向用户空间进行不必要的拷贝。由系统调用sendfile()调用*/
- ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
- /*该函数用来从一个文件向另一个文件发送数据*/
- ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
- /*该函数用于获取未使用的地址空间来映射给定的文件*/
- unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
- /*当给出SETFL命令时,这个函数用来检查传递给fcntl()系统调用的标志的有效性。*/
- int (*check_flags)(int);
- /**/
- int (*dir_notify)(struct file *filp, unsigned long arg);
- /*该函数用来实现flock()系统调用,该调用提供忠告锁*/
- int (*flock) (struct file *, int, struct file_lock *);
- /**/
- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
- /**/
- ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
- };
具体的文件系统可以为每一种操作做专门的实现,如果存在通用操作,也可以使用通用操作。