Linux内核中的文件描述符(一)

Kernel version:2.6.14

CPU architecture:ARM920T

作为文件的使用者,进程理所当然的要将所使用的文件记录于自己的控制块中,也就是task_struct。另外,由于进程所对应的程序也是一个文件,因此进程控制块还必须记录这个文件的相关信息。由于OS要对所有进程提供服务,因此OS还要维护一个记录所有进程打开的文件的总表。

1.文件对象

当进程通过open系统调用打开一个文件时,该系统调用找到这个文件后,会把文件封装到一个file结构的实例中提供给进程,这个实例称为file对象。file结构的定义如下:

struct file {
 struct list_head f_list;        //所有打开文件的链表
 struct dentry  *f_dentry;      //文件的dentry
 struct vfsmount        *f_vfsmnt;      //文件目录的VFS安装点指针
 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;  //文件所有者ID和用户组ID
 struct file_ra_state f_ra;

unsigned long  f_version;
 void   *f_security;

/* 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;
 struct rcu_head  f_rcuhead;
};

结构中的域f_uid为文件所有者的ID,f_gid为文件所有者所在组的ID。这样就使得一个文件可能面临三种用户的访问:

文件所有者;

同组用户;

其他用户。

内核在处理一个进程或用户访问一个文件的请求时,要根据进程的f_uid和f_gid以及访问模式来确定该进程是否具有访问这个文件的权限。对于一个用户来说,可以有读、写和执行三种文件权限,这三种权限和三种用户就共有9中组合,即文件的访问权限可以用9个bit来表示,并将其保存在文件的dentry中。

结构中的域f_pos记录了进程对文件读写位置的当前值,可以通过调用函数llseek进程移动。

结构中的f_op执向结构file_operations,该结构封装了对文件进行操作的函数,定义如下:

struct file_operations {
 struct module *owner;
 loff_t (*llseek) (struct file *, loff_t, int);
 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
 ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
 int (*readdir) (struct file *, void *, filldir_t);
 unsigned int (*poll) (struct file *, struct poll_table_struct *);
 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);
 int (*mmap) (struct file *, struct vm_area_struct *);
 int (*open) (struct inode *, struct file *);
 int (*flush) (struct file *);
 int (*release) (struct inode *, struct file *);
 int (*fsync) (struct file *, struct dentry *, int datasync);
 int (*aio_fsync) (struct kiocb *, int datasync);
 int (*fasync) (int, struct file *, int);
 int (*lock) (struct file *, int, struct file_lock *);
 ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
 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);
 int (*check_flags)(int);
 int (*dir_notify)(struct file *filp, unsigned long arg);
 int (*flock) (struct file *, int, struct file_lock *);
};

从上面的代码可以看到,结构中是一系列函数的指针,这里有我们比较熟悉的read、open、write和close等函数的指针。进程就是通过这些函数访问一个文件的,file_operations是linux虚拟文件系统VFS和进程之间的接口。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/4f999d3c33bfa4d6670a57a4ed24fd31.html