公司如何建立微网站,wordpress描述引用,免费crm在线看系统,大庆开发网站公司Linux文件系统FAQ2010年03月25日最近实验室搞了一些列讲座#xff0c;阿福师兄关于文件系统的讲座帮我弄清楚了一些以前不清楚的问题#xff0c;以问答的形式对文件系统常见的问题进行了总结。Q: 文件系统如何看待底层物理块设备#xff1f;文件系统把块设备简单的看做线性的…Linux文件系统FAQ2010年03月25日最近实验室搞了一些列讲座阿福师兄关于文件系统的讲座帮我弄清楚了一些以前不清楚的问题以问答的形式对文件系统常见的问题进行了总结。Q: 文件系统如何看待底层物理块设备文件系统把块设备简单的看做线性的组合即对文件系统而言块设备是一系列可以读写的块。文件系统不需要知道这些物理设备的实际布局及如何读写这些是设备驱动的工作。Q: 跟文件系统相关的系统调用主要有那些打开文件open读取文件read写文件write关闭文件close删除文件unlink创建目录mkdir删除目录rmdir等linux通过VFS提供了符合POSIX标准的接口。Q: 如何实现一个文件系统?实现VFS提供的一组文件系统操作接口向内核注册实现用户空间文件系统或堆叠式文件系统Q: VFS如何管理super_blockinodedentryfilevfsmount等主要数据结构参见http://blog.chinaunix.net/u2/87570/showart_2126000 .htmlQ: 哪些接口必须实现VFS实现了很多通用接口如基本所有的读写操作都可直接使用generic_file_aio_readgeneric_file_aio_write接口(我的内核版本为2.6.19)ext2的读写就是使用该接口但各个文件系统必须实现自己的read_page方法用于从磁盘读取一页的数据(还可实现read_pages一次读取多页以提高效率)如果要实现direct_io访问必须实现direct_IO接口。read_page的实现需要基于文件系统实际的数据组织它将用户的文件请求位置(逻辑页号)转换为物理块号并向通用块层发送请求。Q: ext2文件系统如何组织文件的数据ext2使用长度为15的数组(ext2_inode的一个字段)其中前12个数组元素记录直接块映射即其内容即为文件前12个块的地址第13个元素记录一级索引关系即该元素的内容为一个块的地址这个块的内容为一系列块的地址第1415个元素分别为二级索引三级索引。Q: 内核如何根据用户态传递的路径名得到文件的inodedentry信息通过路径名查找可以通过路径名得到inodedentry的信息Linux提供了path_lookup接口来实现路径名的解析其具体实现以下工作1. 获取路径名查找的起点当前目录或是根目录2. 以/为分隔符解析每个目录项。3. 针对每个目录项首先查找目录项高速缓存判断当前的目录项对象是否在缓存中如果在则直接从缓存中获取结果如果不在则需要在上一级目录中调用实际文件系统实现的lookup方法查找并读取目录项对应的inode信息填充dentry结构并将该结构加入到高速缓存。Q: 内核如何根据路径名查找的结果得到file结构通过dentry_open实现具体执行以下工作1. 分配一个文件对象2. 根据传递进来的dentry信息vfsmnt信息初始化file对象的f_fentryf_vfsmnt3. 以索引节点的i_fop填充f_op。4. 将文件对象插入到文件系统超级块的s_files字段所指向的链表中。Q: 索引节点的i_fopi_opi_mapping的a_ops字段何时被初始化具体文件系统读取索引节点时初始化如ext2的ext2_read_inode方法在ext2_read_inode中根据文件的类型不同将i_fopi_opi_mapping的a_ops初始化为相应的方法。1. 对于普通的文件三者的值分别为ext2_file_operationsext2_file_inode_operationsext2_aops2. 对于目录三者的值分别为ext2_dir_operationsext2_dir_inode_operationsext2_aops;3. 对于链接文件i_op被赋值为ext2_symlink_inode_operationsbdget()根据块设备号初始化一个block_device结构该结构字段的bd_inode的i_data被初始化为def_blk_aops的地址当不同过文件系统读取块设备时def_blk_ops会被调用def_blk_aops的read_page方法调用block_read_full_page以一次读一块的方式读取整个页的数据。Q: 对于打开的文件在用户态以fd标识在内核态以file结构标识fd与 file如何对应每一个进程由一个task_struct结构描述其中的files字段是一个files_struct的结构主要描述文件打开的文件信息包括fd使用位图files对象数组fd_array其中fd_array的下标即对应着该file对象对应的fd。当进程通过路径名获取到file对象后会将file对象的指针放入fd_array数组的相应位置Q: direct io是怎么回事直接IO(direct io)是指读写文件系统数据时绕过页高速缓存。具体文件系统支持直接IO需要实现a_ops中的direct_IO方法不管是直接IO还是经过页高速缓存的IO操作都是将请求通过bio发到通用块层来实现的。Q: 高速缓存页分哪些类型含有普通文件数据或目录的页含有直接从块设备文件跳过文件系统层读出来的数据的页含有用户态进程数据的页但页中的数据已经被交换到磁盘属于特殊文件系统的页如共享内存的IPC所使用的特殊文件系统shmQ: 页高速缓存中页的数据都是不同的么页高速缓存可以包含同一磁盘数据的多个副本可以一下两种方式可以访问普通文件的同一块1. 读文件此时数据包含在普通文件索引节点所拥有的页中2. 从文件所在的设备文件(磁盘分区)读取块此时数据就包含在块设备文件的主索引节点所拥有的块中。Q: 页高速缓存如何组织Linux支持TB级的文件访问大文件时页高速缓存中可能充满太多的文件页因此需要对这些页进行高效的组织使得内核能迅速高效的查找页。Linux采用基树(radix tree)对页高速缓存进行组织添加删除查找页的操作的时间复杂度都为O(1)。Linux提供一组方法方法用于处理页高速缓存find_get_page()接受address_space对象指针及偏移量返回对应的页描述符find_get_pages()查找一组具有相邻索引的页add_to_page_cache()把一个新页的描述符插入到页高速缓存remove_from_page_cache()将页从高速缓存中移除read_cache_page()确保高速缓存中包含最新版本的指定页Q: 缓冲区页于页内缓冲区的关系如下图所示page结构的private字段指向第一个缓冲区首部各个缓冲区首部通过b_this_page链接并通过b_page指向包含自己的page结构b_data为其相对于页的位置。当页在高端内存时b_data为缓冲区块在业内的偏移量否则b_data为缓冲区的线性地址因高端内存页没有固定的映射。Q: 什么情况下内核会创建缓冲区页当读或写的文件页在磁盘块上不相邻时,即文件系统为文件分配了非连续的块或者因为文件有洞在块大小与页大小相等的情况下这种情况不会出现。当访问一个单独的磁盘块时(如读超级块或索引节点块)。Q: 如何创建和释放缓冲区页调用grow_buffers()其具体执行如下步骤1 如果对应的页不在块设备的基树中需创建新的页。2 调用alloc_page_buffer()为页创建缓冲区一次创建页能容纳的所有缓冲区并建立好链接关系进行必要的初始化。调用try_to_free_page()释放缓冲区页。Q: 如何在页高速缓存中搜索块将块号转换成页号索引并通过基树提供的接口进行查找。__find_get_block(), __getblk()接口提供搜索块的接口根据给定的设备信息及块号块大小返回块对应的buffer_head结构后者在块所在的缓冲区页不存在时会分配缓冲区页创建缓冲区块并返回对应块的buffer_head结构。为了提高系统性能内核维持了一个小的磁盘高速缓存数组bh_lrus(每CPU变量),数组包含8个元素指向最近访问过的缓冲区首部。Q: 如何向通用块层提交缓冲区首部使用submit_bh()向通用块层传递一个缓冲区首部使用ll_rw_block可向通用块层传递一组缓冲区首部两者都附带读写传输方向标志。sumbit_bh()根据缓冲区首部内容创建一个bio具体执行如下步骤1 调用bio_alloc分配一个bio描述符2 将bi_sector字段赋值为bh-b_blocknr * bh-b_size / 512;3 将bi_bdev字段赋值为bh-b_bdev4 把bi_size设置为块大小bh-b_size5 初始化bi_io_vec的第一个元素以使该段对应于块缓冲区bi_io_vec[0].bv_page bh-b_page;bi_io_vec[0].bv_len bh-b_size;bi_io_vec[0].bv_offset bh-b_data;6. 将bi_cnt字段置1并把bi_idx置为07. 将bi_end_io字段赋值为end_bh_bio_syncbi_private字段赋值为缓冲区首部地址。作为数据传输完毕后的执行方法数据传输完后通过bi_private获取buffer_head结构执行期bi_end_io字段的方法。8. 调用submit_bio将bio提交到通用块层。ll_rw_block对数组中每个buffer_head调用submit_bh。Q: 页高速缓存何时被刷新基于性能考虑linux系统采用延迟写策略即将把脏缓冲区写入块设备的操作延迟执行基于延迟写几次写操作可能只需要一次物理更新。从而使得物理块设备平均为读请求服务的时间多于写请求。以下条件会触发把脏页写到磁盘1. 页高速缓存变得太满但还需要更多的页或者脏页的数量已经太多2. 从页变成脏页的时间太长超过某一阈值3. 进程请求或者特定文件系统特定的变化。如同过sync(),fsync(),fdatasync()系统调用实现Linux通过pdflush内核线程系统地扫描页高速缓存以刷新脏页pdflush线程的数量随着系统运行动态调整具体原则如下1. 必须有至少两个之多八个pdflush内核线程2. 如果到最近的1s期间没有空闲的pdflush就应该创建新的pdflush3. 如果最近一次pdflush变为空闲的时间超过1s就应该删除一个pdflush4. 通过定期唤醒的pdflush保证陈旧的页及时写回页保持脏状态的最长时间为30sQ: sync(), fsync(),fdatasync()系统调用区别sync()把所有的脏缓冲区刷新到磁盘fsync()把属于特定打开文件的所有块刷新到磁盘fdatasync()与fsync()类似但不刷新文件的索引节点块Q: linux文件系统如何预读取为了保证预读命中率linux只对顺序读进行预读内核通过如下条件判断read()是否为顺序读1. 这是文件被打开后的第一次读并且从文件头开始读2. 当前的读请求与前一次读请求在文件内的位置是连续的否则为随机读任何一次随机读将终止预读而不是缩减预读窗口。当确定了需要进行预读时就需要确定合适的预读大小预读粒度太小效果提升不明显预读太多可能载入太多不需要的页面而造成资源浪费linux的策略是1. 首次预读readahead_size read_size * 2; // or *42. 后续预读readahead_size readahead_size * 23. 系统设定的最大预读大小为128K该值可配置