1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > linux系统内核文百科 Linux之内核中的文件系统 -电脑资料

linux系统内核文百科 Linux之内核中的文件系统 -电脑资料

时间:2020-03-08 02:10:02

相关推荐

linux系统内核文百科 Linux之内核中的文件系统 -电脑资料

文件描述符

一般说起文件和文件系统的时候,都会下意识的想到它们存在于磁盘上,管理各种文件呢?即运行时文件系统在内核中的表示。

我们知道,进程是操作系统分配资源的基本单位,文件也是在进程中被处理的。比如用vim写代码,那么vim这个程序就成为操作系统中的一个进程,vim处理的对象就是一个代码文件。操作系统用PCB来管理进程,PCB从代码的角度看就是task_struct结构体,这个结构体中有一个指针指向files_struct结构体,这就是所谓的文件描述符表,其代码如下:struct files_struct { atomic_t count; /* 共享该表的进程数 */ rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/ int max_fds; /*当前文件对象的最大数*/ int max_fdset; /*当前文件描述符的最大数*/ int next_fd; /*已分配的文件描述符加1*/ struct file ** fd; /* 指向文件对象指针数组的指针 */ fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/ fd_set *open_fds; /*指向打开文件描述符的指针*/ fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初值集合*/ fd_set open_fds_init; /*文件描述符的初值集合*/ struct file * fd_array[32];/* 文件对象指针的初始化数组*/};

这个表是每个进程私有的,每个进程都有一个,它也称为用户打开文件表,这是为了区别系统打开文件表。我们主要关注最后一个成员:struct file * fd_array[32];,这是一个指针数组,数组的每个成员都指向一个file结构体,file结构体中保存着该进程已经打开的文件的信息。由于一个进程可以打开多个文件,所以用一个指针数组来保存它们的信息。对于在数组中有入口地址的每个文件来说,数组的索引就是文件描述符(file descriptor)。通常,数组的第一个元素(索引为0)是进程的标准输入文件,数组的第二个元素(索引为1)是进程的标准输出文件,数组的第三个元素(索引为2)是进程的标准错误文件。这三个文件是操作系统为每个进程默认打开的,如果进程需要打开其他文件,那么进程描述符将从3开始。文件描述符是系统的一个重要资源,虽然说系统内存有多少就可以打开多少的文件描述符,但是在实际实现过程中内核是会做相应的处理的,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制),查看系统级别的最大打开文件数可以使用sysctl -a | grep fs.file-max命令查看。与此同时,内核为了不让某一个进程消耗掉所有的文件资源,其也会对单个进程最大打开文件数做默认值处理(称之为用户级限制),默认值一般是1024,使用ulimit -n命令可以查看。

在Linux中,进程是通过文件描述符(file descriptors,简称fd)而不是文件名来访问文件的,文件描述符实际上是一个整数。虚拟文件系统

下面来看一下file结构体,代码如下:struct file{ struct list_head f_list; /*所有打开的文件形成一个链表*/ struct dentry *f_dentry; /*指向相关目录项的指针*/ struct vfsmount *f_vfsmnt; /*指向VFS安装点的指针*/ struct file_operations *f_op; /*指向文件操作表的指针*/ mode_t f_mode; /*文件的打开模式*/ loff_t f_pos; /*文件的当前位置*/ unsigned short f_flags; /*打开文件时所指定的标志*/ unsigned short f_count; /*使用该结构的进程数*/ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin; /*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数*/ int f_owner; /* 通过信号进行异步I/O数据的传送*/ unsigned int f_uid, f_gid; /*用户的UID和GID*/ int f_error; /*网络写操作的错误码*/ unsigned long f_version; /*版本号*/ void *private_data; /* tty驱动程序所需 */};

file结构体并不与实际的文件一一对应,例如,当一个进程多次打开同一文件的时候,都会分配一个不同的file结构体以及相应的文件描述符,尽管这些file结构体最终都指向同一个实际物理文件,Linux之内核中的文件系统》()。可以看出,内存中的文件和磁盘中的文件实现方式还是不太一样的,内存中的文件是动态的,因为要不停的读写,所以只是一份拷贝,所有的操作针对的只是这份拷贝,操作完成后,把结果写回到磁盘文件中;写回这个动作执行之前,所有的改动只存在与内存中,并不会实时反应到磁盘上,可以用vim和cat同时操作一个文件来验证一下。懂了这个道理之后,再看为啥每次打开文件要分配不同的file结构体:因为每次打开意味着要对同一个文件进行不同的操作,并希望不同操作的结果都能写回到磁盘文件中;如果使用同一个file,那么就有可能后面的操作覆盖掉前面的操作。

覆盖的可能性来自于file结构体的成员loff_t f_pos;它表示文件当前的读写位置。每个文件都有一个32位的数字来表示下一个读写的字节位置,这个数字叫做文件位置。每次打开一个文件,除非明确要求,否则文件位置都被置为0,即文件的开始处,此后的读或写操作都将从文件的开始处执行,可以通过执行系统调用LSEEK(随机存储)对这个文件位置进行修改。所以,如果两次操作是针对同一文件的不同位置,使用同一个file结构体将使它们拥有同样的读写位置,这显然无法达到目的。这还是同一进程的不同操作,更何况不同进程的不同操作呢?于是,每次打开文件几乎都要分配一个新的file结构体。可以说,file结构体主要保存的就是这个读写位置。

上面使用了“几乎”,那就表示有例外情况:生成一个新进程时,子进程要共享父进程的所有信息,包括file结构体,其成员unsigned short f_count;就表示了当前有多少进程在使用这个结构体,只有当它的值为0时,才从内存中销毁这它。

file结构体中的第一个成员是 struct list_head f_list;它使file结构形成一个双链表,称为系统打开文件表,其最大长度是NR_FILE,在fs.h中定义为8192。

那么文件描述符表、系统打开文件表和实际文件之间的关系可以如下图:

然后我们看看file结构体如何指向最终的实际文件,这要涉及到第二个成员:struct dentry *f_dentry; 其代码如下:struct dentry {atomic_t d_count; /* 目录项引用计数器 */unsigned int d_flags; /* 目录项标志 */struct inode * d_inode; /* 与文件名关联的索引节点 */struct dentry * d_parent; /* 父目录的目录项 */struct list_head d_hash; /* 目录项形成的哈希表 */struct list_head d_lru; /*未使用的 LRU 链表 */struct list_head d_child; /*父目录的子目录项所形成的链表 */struct list_head d_subdirs; /* 该目录项的子目录所形成的链表*/struct list_head d_alias; /* 索引节点别名的链表*/int d_mounted; /* 目录项的安装点 */struct qstr d_name; /* 目录项名(可快速查找) */unsigned long d_time; /* 由 d_revalidate函数使用 */struct dentry_operations *d_op; /* 目录项的函数集*/struct super_block * d_sb; /* 目录项树的根 (即文件的超级块)*/unsigned long d_vfs_flags; void * d_fsdata; /* 具体文件系统的数据 */unsigned char d_iname[DNAME_INLINE_LEN]; /* 短文件名 */};

这个结构体保存了路径信息,包括文件名。我在介绍ln命令时说过,操作系统根据inode号寻找文件,而人类根据文件名,故需要从这个结构体中找到二者之间的对应关系。我们可以利用这两个成员:struct inode * d_inode;和struct qstr d_name;。前者指向了与真正的文件相关的inode结构体,它保存着从磁盘分区的inode读上来信息。至此,进程中文件描述符指向了最终的磁盘文件,我猜file结构体最终要依靠inode结构体写回磁盘。

完。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。