免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7613 | 回复: 2
打印 上一主题 下一主题

address_space是干吗的? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-25 19:29 |只看该作者 |倒序浏览
20可用积分
文件系统中的inode有个字段的结构是address_space
不知道它有什么作用
请高手指点一下

最佳答案

查看完整内容

和页缓存(page cache)相关的。页高速缓存(cache)是 Linux内核实现的一种主要磁盘缓存。它主要用来减少对磁盘的I/O操作。具体地讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问。下面这一段是Linux kernel development上面的15.1节对address_space的讲解:另外,在Understanding the linux kernel上面的第15章也对这个结构有详细的讲解。

论坛徽章:
0
2 [报告]
发表于 2009-03-25 19:29 |只看该作者
原帖由 St.小糊涂神 于 2009-3-25 19:29 发表
文件系统中的inode有个字段的结构是address_space
不知道它有什么作用
请高手指点一下


和页缓存(page cache)相关的。
页高速缓存(cache)是 Linux内核实现的一种主要磁盘缓存。它主要用来减少对磁盘的I/O操作。具体地讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的访问变为对物理内存的访问。

下面这一段是Linux kernel development上面的15.1节对address_space的讲解:

  1. 15.1     页高速缓存

  2. 从它的名字就可以看出来,页高速缓存缓存的是页面。缓存中的页来自对正规文件、块设备文件和内存映射文件的读写,如此一来,页高速缓存内就包含了最近被访问过的文件的全部页面。在执行I/O操作前,比如read()操作,内核会检查数据是否已经在页高速缓存中了,如果所需数据确实在高速缓存中,那么内核就可以马上从缓存中得到所需的页,而不需要从磁盘读取数据。

  3. address_space对象

  4. 一个物理页可能由多个不连续的物理磁盘块组成。也正是由于页面中映射的磁盘块不一定连续,所以在页高速缓存中检测特定数据是否已被缓存是件非常困难的工作。因此不能用设备名称和块号来做页高速缓存中数据的索引,要不然这可是最简单的解决办法。

  5. 另外,Linux页高速缓存对被缓存页的范围定义非常宽。实际上,在最初SystemV Release 4引入页高速缓存时,仅仅只缓存文件系统的数据,所以SVR4的页高速缓存使用它的等价文件对象(被称为 vnode结构体)管理页高速缓存。Linux页高速缓存的目标是缓存任何基于页的对象,这包含各种类型的文件和各种类型的内存映射。

  6. 为了满足普遍性要求,Linux页高速缓存使用address_space结构体描述页高速缓存中的页面。该结构定义在文件<linux/fs.h>中,下面给出具体形式:

  7. struct address_space {

  8. struct inode                 *host;           /*拥有节点*/

  9. struct radix_tree_root       page_tree;       /*包含全部页面的radix树 */

  10. spinlock_t                   tree_lock;       /*保护page_tree的自旋锁*/

  11. unsigned int                 i_mmap_writable;  /* VM_SHARED计数*/

  12. struct prio_tree_root        i_mmap;          /*私有映射链表*/

  13. struct list_head             i_mmap_nonlinear; /* VM_NONLINEAR 链表*/

  14. spinlock_t                   i_mmap_lock;      /* 保护i_mmap的自旋锁 */

  15. atomic_t                     truncate_count;   /* 截断计数*/

  16.      unsigned long                nrpages;          /* 页总数*/

  17. pgoff_t                      writeback_index;  /* 回写的起始偏移*/

  18. struct address_space_operations    *a_ops;     /* 操作表*/

  19. unsigned long                flags;           /* gfp_mask 掩码与错误标识*/

  20. struct backing_dev_info      *backing_dev_info;    /*预读信息*/

  21. spinlock_t                   private_lock;     /*私有address_space锁*/

  22. struct list_head              private_list;    /*私有address_space链表*/

  23. struct address_space         *assoc_mapping;  /*相关的缓冲*/

  24. };

  25. 其中i_mmap字段是一个优先搜索树,它的搜索范围包含了在address_space中所有共享的与私有的映射页面。优先搜索树是一种巧妙的将堆与radix树结合的快速检索树。address space空间大小由nrpages字段描述。

  26. address_space结构往往会和某些内核对象关联。通常情况下,会与一个索引节点(inode)关联,这时host域就会指向该索引节点;如果关联对象不是一个索引节点的话,比如address_space和swapper关联时,host域会被置为NULL。

  27. a_ops域指向地址空间对象中的操作函数表,这与VFS对象及其操作表关系类似,操作函数表定义在文件<linux/fs.h>中,由address_space_operations结构体来表示:

  28. struct address_space_operations {

  29.     int (*writepage)(struct page *, struct writeback_control *);

  30.     int (*readpage)(struct file *, struct page *);

  31.     int (*sync_page)(struct page *);

  32.     int (*writepages)(struct address_space *,struct writeback_control *);

  33.     int (*set_page_dirty)(struct page *);

  34.     int (*readpages)(struct file *, struct address_space *,

  35.                      struct list_head *, unsigned);

  36.     int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);

  37.     int (*commit_write)(struct file *, struct page *, unsigned, unsigned);

  38.     sector_t (*bmap)(struct address_space *, sector_t);

  39.     int (*invalidatepage) (struct page *, unsigned long);

  40.     int (*releasepage) (struct page *, int);

  41.     int (*direct_IO)(int, struct kiocb *, const struct iovec *,

  42.                      loff_t, unsigned long);

  43. };

  44. 这里面readpage()和writepage()两个方法最为重要。我们下面就来看看一个页面的读操作会包含哪些步骤。

  45. 首先,一个address_space对象和一个偏移量会被传给readpage()方法,这两个参数用来在页高速缓存中搜索需要的数据:

  46. page = find_get_page(mapping ,index);

  47. mapping是指定的地址空间,index是文件中的指定位置。

  48. 如果搜索的页并没在高速缓存中,那么内核将分配一个新页面,然后将其加入到页高速缓存中。

  49.     struct page *cached_page;

  50.     int error;

  51.      cached_page = page_cache_alloc_cold(mapping);

  52.      if(!cached_page)

  53.        /*内存分配出错*/

  54. error = add_to_page_cache_lru(cached_page,mapping,index,GFP_KERNEL);

  55. if(error)

  56.        /*页面被加入到页面高速缓存时,出错*/

  57. 最后,需要的数据从磁盘被读入,再被加入页高速缓存,然后返回给用户:

  58. error= mapping->a_ops->readpage(file,page);

  59. 写操作和读操作有少许不同。对于文件映射来说,当页被修改了,VM仅仅需要调用

  60. SetPageDirty(page);

  61. 内核会在晚些时候通过 writepage()方法把页写出。对特定文件的写操作比较复杂—它的代码在文件mm/filemap.c中,通常写操作路径基本上要包含以下各步:

  62. page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);

  63. status = a_ops->prepare_write(file,page,offset,offset+bytes);

  64. page_fault = filemap_copy_from_user(page,offset,buf,bytes);

  65. status = a_ops->commit_write(file,page,offset,offset+bytes);

  66. 首先,在页高速缓存中搜索需要的页,如果需要的页不在高速缓存中,那么内核在高速缓存中新分配一空闲项;下一步,prepare_write()方法被调用,创建一个写请求;接着数据被从用户空间拷贝到了内核缓冲;最后通过commit_write()函数将数据写入磁盘。

  67. 因为所有的页I/O操作都要执行上面这些步骤,这就保证了所有的页I/O操作必然都是通过页高速缓存进行的。因此,内核也总是试图先通过页高速缓存来满足所有的读请求。如果在页高速缓存中未搜索到需要的页,则内核将从磁盘读入需要的页,然后将该页加入到页高速缓存中;对于写操作,页高速缓存更像是一个存储平台,所有要被写出的页都要被加入页高速缓存中。

复制代码


另外,在Understanding the linux kernel上面的第15章也对这个结构有详细的讲解。

论坛徽章:
0
3 [报告]
发表于 2009-03-25 20:22 |只看该作者
太感谢版主了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP