Chinaunix首页 | 论坛 | 博客
  • 博客访问: 96844
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-09-01 19:43
文章分类
文章存档

2017年(4)

2015年(24)

2014年(1)

我的朋友

分类: LINUX

2015-07-11 13:57:42

原文地址:fsyn,数据读入 作者:zixin

(3) some func

static inline void set_page_dirty(struct page * page)color=green>

   +

__set_page_dirty :标记页面为dirty,调整页面在page cache中(mapping)队列

的位置,并标记相关inode节点为dirty状态.调用者保证page在page cache之中.



void invalidate_inode_pages(struct inode * inode):color=green>

好像没有人用,正好也不看了.





(4)file truncate related

   truncate_inode_pages ( service entry for file truncate in filemap.c)

    +--->truncate_list_pages

          +-->truncate_partial_page

          +-->truncate_complete_page


这组函数和系统调用 truncate 相关(truncate file to specified len).入口

在 fs/open.c

asmlinkage long sys_truncate(const char * path, unsigned long length)

{

return do_sys_truncate(path, length);

}


经过一系列的函数周转到do_truncate->notify_change->inode_setattr(ext2文

件系统没有提供setattr,采用通用逻辑)->vmtruncate,最终利用truncate_inode

_pages清除page cache中相关的缓冲数据. 关于truncate不想再多说,只来看看:

static int truncate_list_pages(struct list_head *head, unsigned long


start, unsigned *partial)

/*注意一下加锁的顺序*/

{

.........

while (curr != head) {

unsigned long offset;



page = list_entry(curr, struct page, list);

curr = curr->next;

offset = page->index;



/* Is one of the pages to truncate? */

if ((offset >= start) || (*partial && (offset + 1) == start)) {

if (TryLockPage(page)) {

page_cache_get(page); /*先增加页面引用计数*/

spin_unlock(&pagecache_lock);/*然后才释放锁*/color=blue>

wait_on_page(page);

page_cache_release(page);

return 1;

}

/*先增加页面引用计数,然后才释放锁,注意这个顺序*/color=blue>

page_cache_get(page);

spin_unlock(&pagecache_lock);

                   .........

        }

}

return 0;

}


    

         

(5)fsync, fdatasync

  这两个系统调用将内核缓冲的文件数据同步到磁盘.系统调用的入口在buffer.c

sys_fsync,sys_fdatasync.区别在于sys_fsync将meta data也刷新到磁盘(atime

等),而sys_fdatasync只刷新"文件内容".两个系统调用都不保证包含他们的上级

目录的同步.如果需要,要明确的对对应目录调用fsync.

  filemap.c中相关的函数是filemap_fdatasync,filemap_fdatawait.其作用是同

步page cache中的dirty页(mapping->dirty_pages)到磁盘.而inode meta data的

同步依赖于特定的文件系统(见buffer.c sys_fsync,注意page cache无meta数据).

filemap_fdatasync遍历dirty页面,提交系统驱动处理(mapping->a_ops->writepage

对ext2文件系统来讲就是ext2_aops -> ext2_writepage ->block_write_full_page

此函数也在buffer.c,请阅读此函数,注意page上的buffers并没有加入buffer cache)

filemap_fdatawait等待驱动完成page io操作.

   不再列出相关代码,阅读时候体会一下加锁和增加页面引用计数的顺序.

  



(6)page cache: 数据读入

  函数static inline int page_cache_read(struct file * file, unsigned

long offset)分配一个页面并提交磁盘驱动读入文件制定偏移的内容到page

cache, 同时考虑到了其他执行流先于我们读入的情况.仔细阅读此函数调用的

add_to_page_cache_unique->__add_to_page_cache,注意在__add_to_page_cache

中对page加了锁. 这个锁比较隐蔽,还以为page_cache_read在未加锁的情况下

启动了page io呢.

   这是一个异步读取函数,应用于预读和其他需要异步读取的函数.

   函数read_cluster_nonblocking调用page_cache_read异步读区整个cluster.

   read_cache_page从mapping读取指定的内容到页面,所不同的是使用指定的方

式更新页面的内容.同样考虑到了各种race的情况.他使用用的函数有点拗口,来

看看:

static inline

struct page *__read_cache_page(struct address_space *mapping,

unsigned long index,

int (*filler)(void *,struct page*),

void *data)

{

struct page **hash = page_hash(mapping, index);

struct page *page, *cached_page = NULL;

int err;

repeat:

page = __find_get_page(mapping, index, hash);

if (!page) {/*未找到指定页面*/

if (!cached_page) {

cached_page = page_cache_alloc();

if (!cached_page)

return ERR_PTR(-ENOMEM);

}

page = cached_page;

     /*

        *add_to_page_cache_unique->__add_to_page_cache对页面进行了加锁

    */


if (add_to_page_cache_unique(page, mapping, index, hash))

goto repeat;color=blue>/*新页面加入cache的时候发现cache已经有了指定页面*/


cached_page = NULL;

err = filler(data, page); /*用指定方式更新页面*/

if (err < 0) {

page_cache_release(page);

page = ERR_PTR(err);

}

}

if (cached_page)

page_cache_free(cached_page);

return page;

}


从语义上讲函数read_cache_page应该是"读取到page cache".

   还有一个逻辑上比较类似的函数grab_cache_page,此函数只是锁定一个指定

区间的页面,返回给调用者.而不管是否update,也不提交给驱动读取页面.
阅读(1827) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~