f2fs有三种inode,meta_inode,node_inode和普通的文件inode,前两种inode只存在于vfs层,且数量只有一个。meta_inode对应于SIT,NAT,SSA,checkpoint和super block这些文件系统元数据,node inode对应于main area的node segment的数据,普通文件inode读写的区域对应于main area的data segment。所以,所有的f2fs数据的读写都是通过vfs层的inode的。这些inode的保存在f2fs_sb_info中,在文件系统初始化时f2fs_fill_super生成。再看inode的初始化过程,在函数inode.c/f2fs_iget中:

struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
{struct f2fs_sb_info *sbi = F2FS_SB(sb);struct inode *inode;int ret = 0;inode = iget_locked(sb, ino);if (!inode)return ERR_PTR(-ENOMEM);if (!(inode->i_state & I_NEW)) {trace_f2fs_iget(inode);return inode;}if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi))goto make_now;ret = do_read_inode(inode);if (ret)goto bad_inode;
make_now:if (ino == F2FS_NODE_INO(sbi)) {inode->i_mapping->a_ops = &f2fs_node_aops;mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);} else if (ino == F2FS_META_INO(sbi)) {inode->i_mapping->a_ops = &f2fs_meta_aops;mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);} else if (S_ISREG(inode->i_mode)) {inode->i_op = &f2fs_file_inode_operations;inode->i_fop = &f2fs_file_operations;inode->i_mapping->a_ops = &f2fs_dblock_aops;} else if (S_ISDIR(inode->i_mode)) {inode->i_op = &f2fs_dir_inode_operations;inode->i_fop = &f2fs_dir_operations;inode->i_mapping->a_ops = &f2fs_dblock_aops;mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);} else if (S_ISLNK(inode->i_mode)) {inode->i_op = &f2fs_symlink_inode_operations;inode->i_mapping->a_ops = &f2fs_dblock_aops;} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {inode->i_op = &f2fs_special_inode_operations;init_special_inode(inode, inode->i_mode, inode->i_rdev);} else {ret = -EIO;goto bad_inode;}unlock_new_inode(inode);trace_f2fs_iget(inode);return inode;bad_inode:iget_failed(inode);trace_f2fs_iget_exit(inode, ret);return ERR_PTR(ret);
}

初始化过程区别对待了meta_inode和node_inode,再看看它们的address_space_operation:

const struct address_space_operations f2fs_node_aops = {.writepage  = f2fs_write_node_page,.writepages = f2fs_write_node_pages,.set_page_dirty    = f2fs_set_node_page_dirty,.invalidatepage = f2fs_invalidate_node_page,.releasepage   = f2fs_release_node_page,
};
const struct address_space_operations f2fs_meta_aops = {.writepage  = f2fs_write_meta_page,.writepages = f2fs_write_meta_pages,.set_page_dirty    = f2fs_set_meta_page_dirty,
};

也许大家会觉得奇怪,为什么只有writepage而没有readpage呢,那它们是怎么读磁盘上的数据呢?文件系统实现了两个函数node.c/get_node_page和checkpoint.c/get_meta_page,这两个函数的流程类似,都是首先使用grab_cache_page去获取特定位置的页,grab_cache_page首先会查找address_space的基数树,如果找到该页则返回,如果找不到,则从伙伴系统分配一个新的页;然后调用f2fs_readpage读取磁盘上该页的内容。

struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
{struct address_space *mapping = sbi->meta_inode->i_mapping;struct page *page;
repeat:page = grab_cache_page(mapping, index);if (!page) {cond_resched();goto repeat;}if (PageUptodate(page))goto out;if (f2fs_readpage(sbi, page, index, READ_SYNC))goto repeat;lock_page(page);if (page->mapping != mapping) {f2fs_put_page(page, 1);goto repeat;}
out:mark_page_accessed(page);return page;
}

get_meta_page的参数index,直接对应了该页在磁盘上的块地址,所以可以直接作为f2fs_readpage的参数。以读取SSA的一个实例看,如功能函数get_sum_page,该函数实现很简单,通过GET_SUM_BLOCK(sbi, segno)获取summary page的块地址,该宏展开为

#define GET_SUM_BLOCK(sbi, segno)                \((sbi->sm_info->ssa_blkaddr) + segno)

sbi->sm_info->ssa_blkaddr是SSA区域的起始地址,segno是segment number,由于一个segment的summary存储在一个page上,因此直接相加就是块地址。

struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
{return get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno));
}

而get_node_page稍稍有点不同:

struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
{struct address_space *mapping = sbi->node_inode->i_mapping;struct page *page;int err;
repeat:page = grab_cache_page(mapping, nid);if (!page)return ERR_PTR(-ENOMEM);err = read_node_page(page, READ_SYNC);if (err < 0)return ERR_PTR(err);else if (err == LOCKED_PAGE)goto got_it;lock_page(page);if (!PageUptodate(page)) {f2fs_put_page(page, 1);return ERR_PTR(-EIO);}if (page->mapping != mapping) {f2fs_put_page(page, 1);goto repeat;}
got_it:BUG_ON(nid != nid_of_node(page));mark_page_accessed(page);return page;
}

该函数的参数是node的number,在f2fs中,node number的实际块地址在NAT中存储,因此还需要读取NAT的数据,获得该node的块地址,这些工作在read_node_page中完成。

总的来说,f2fs通过这三种inode把它的全部数据都管理起来,不得不说这是非常巧妙的设计啊

f2fs文件系统的页缓存相关推荐

  1. 关闭linux系统中读写页缓存,Linux文件系统FAQ

    Linux文件系统FAQ 2010年03月25日 最近实验室搞了一些列讲座,阿福师兄关于文件系统的讲座帮我弄清楚了一些以前不清楚的问题,以问答的形式对文件系统常见的问题进行了总结. Q: 文件系统如何 ...

  2. linux 更改ctime_Linux 的文件系统及文件缓存知识点整理

    Linux的文件系统特点 文件系统要有严格的组织形式,使得文件能够以块为单位进行存储. 文件系统中也要有索引区,用来方便查找一个文件分成的多个块都存放在了什么位置. 如果文件系统中有的文件是热点文件, ...

  3. _Linux 的文件系统及文件缓存知识点整理

    Linux的文件系统特点 文件系统要有严格的组织形式,使得文件能够以块为单位进行存储. 文件系统中也要有索引区,用来方便查找一个文件分成的多个块都存放在了什么位置. 如果文件系统中有的文件是热点文件, ...

  4. Linux的文件系统及文件缓存知识点整理

    Table of Contents Linux的文件系统 文件系统的特点 ext系列的文件系统的格式 inode与块的存储 inode位图和块位图 文件系统的格式 目录的存储格式 Linux中的文件缓 ...

  5. F2FS文件系统架构与原理分析(五)——元数据组织及管理

    from : http://blog.chinaunix.net/uid-28989651-id-3911126.html 1. 元数据区域 元数据区域包含以下几种元数据(参见博文:F2FS文件系统架 ...

  6. linux 页缓存 块缓存,页缓存和块缓存

    页缓存和块缓存 独立的缓冲区–LRU块缓存 1.操作方式 为什么采用LRU? LRU代表最近最少使用(least recently used),指的是一种一般方法,可用于有效管理一个集合中最常使用的那 ...

  7. linux系统页面缓存,Linux 页缓存

    (虚拟地址空间是相对磁盘空间到物理内存空间的映射而言来说的). 经内存映射的文件每次只读取一页内容,读取后的页保存在页缓存中,利用页缓存,可提高文件的访问速度.如图 10-6 所示,页缓存由 page ...

  8. linux文件系统的页高速缓存page cache中的核心数据结构address_space

    address_space对象是文件系统中关于内存中页高速缓存的核心数据结构.这篇博客以address_space对象为切入点,分析文件系统的页高速缓存.(这里大部分都是从原作者那里复制过来的,外加上 ...

  9. vue如何实现单页缓存方案分析

    实现全站的页面缓存,前进刷新,返回走缓存,并且能记住上一页的滚动位置,参考了很多技术实现,github上的导航组件实现的原理要么使用的keep-alive,要么参考了keep-alive的源码,但是只 ...

  10. linux系统页面缓存,Linux缓存机制之页缓存

    内核采用一种通用的地址空间方案,来建立缓存数据与其来源之间的关联. 1)  内存中的页分配到每个地址空间.这些页的内容可以由用户进程或内核本身使用各式各样的方法操作.这些数据表示了缓存中的内容: 2) ...

最新文章

  1. c++返回值 注意事项
  2. 网站优化必知的五大发文注意事项
  3. python学习-使用制表符或者换行符来添加空白
  4. CF1594F-Ideal Farm【构造】
  5. linux suse11 nfs,suse11 nfsserver服务安装
  6. 飞秋下载2010正式版_飞秋下载
  7. Hive 元数据库表信息
  8. python计算N维数据的笛卡尔积
  9. 基于GTID Replication主从数据不一致操作
  10. 使用BetterZip结合自动操作工具和预设设置创建电影解压程序
  11. 淘宝最新签名算法分析(1)
  12. 卢卡奇总体性原则_读书笔记|卢卡奇物化与无产阶级意识无产阶级的立场(1)...
  13. vue3的语法使用总结api
  14. 山东大学计算机图形学实验(Opengl实现):Loop Subdivision算法对模型进行细分
  15. zebra扫码枪复位_条码扫描枪设置使用说明详解
  16. voip 客户端 android,基于Android平台的VoIP客户端开发与性能改进
  17. Android 11源码 修改系统App后进行编译
  18. IAP之boot实现
  19. AutoVue使用教程:如何在64位Linux上安装AutoVue
  20. 数据中心远程集中解决方案有哪些?

热门文章

  1. kuangbin字典树
  2. 记一次ARM CHINA面试
  3. aws s3 上传文件 html,javascript 上传文件到 aws s3存储桶
  4. 如何按页进行PDF文档拆分
  5. Hadoop环境搭建
  6. Win10专业工作站版的Ghost备份与还原
  7. 人工智能—产生式系统(专家系统)
  8. CAPL可以读写的几种文件
  9. 行政区划编码转换区域名工具类
  10. Scala下载和安装