老哥学习网 - www.lg9.cn 2024年05月06日 09:20 星期一
当前位置 首页 >情感故事 >

Linux操作系统缓存机制之页缓存_

发布时间:2019-01-25 07:32:48 浏览数:

  Linux运用一个功能广泛的缓冲和缓存框架来提高系统的速度。缓冲和缓存利用一部分系统物理内存,确保最重要、最常使用的块设备数据在操作时可直接从主内存获取,而无需从低速设备读取。物理内存还用于存储从快设备读取的数据,使得随后对该数据的访问可直接在物理内存进行,而无需从外部设备再次取用。考虑系统中多种因素然后延迟写回在总体上改进了系统的性能。前面分析的部分,例如内存管理的slab缓存是一个内存到内存的缓存,其目地不是加速对低速设备的操作,而是对现有资源进行更简单、更高效的使用。文件系统的Dentry缓存也用于减少对低速块设备的访问,但他无法推广到通用场合,因为他是专门用于处理单一数据类型的。内核为块设备提供了两种通用的缓存方案:1)页缓存,针对以页为单位的所有操作,并考虑了特定体系结构上的页长度。一个主要的例子是内存映射技术。因为其他类型的文件访问也是基于内核中的这一技术实现的。所以页缓存实际上负责了块设备的大部分缓存工作。2)块缓存,以块为操作单位。在进行I/O操作时,存取的单位是设备的各个块,而不是整个内存页。尽管页长度对所有文件系统都是相同的,但块长度取决于特定的文件系统或其设置。因而,块缓存必须能够处理不同长度的块。目前用于块传输的标准数据结构已经演变为struct bio.用这种方式进行块传输更为高效,因为他可以合并同一请求中后续的块,加速处理的进行。在许多场合下,页缓存和块缓存是联合使用的。例如,一个缓存的页在写操作期间可以划分为不同的缓冲区,这样可以在更细的力度下,识别出页被修改的部分。好处在于,在将数据写回时,只需要回写被修改的部分,无需将这个页面传输回底层的块设备。页面缓存结构[cpp] view plaincopyprint?
  /*高速缓存的核心数据结构,对块设备的读写操作都放在该结构体里*/ structaddress_space {/*与地址空间所管理的区域之间的关联数据结构之一inode结构指定了后备存储器*/ struct inode *host; /* owner: inode, block_device */ /*与地址空间所管理的区域之间的关联之二,page_tree列出了地址空间中所有的物理内存页*/struct radix_tree_root page_
  tree;/*radix tree of all pages */ spinlock_t tree_lock;/*and lock protecting it */ /*所有用VM_SHARED属性创建的映射*/unsigned int i_mmap_writable;/* count VM_SHARED mappings */ /*基数根节点,该树包含了与该inode相关的所有普通内存映射。该树的任务在于,支持查找包含了给定区间中至少一页的所有内存区域*/ struct prio_tree_root i_mmap; /* tree of private and shared mappings */ /*包含所有在非线性映射中的页*/ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings*/ spinlock_t i_mmap_lock; /* protect tree, count,list */unsigned int truncate_count; /* Cover race condition with truncate */ /*缓存页的总数*/ unsigned long nrpages; /* number of total pages */ pgoff_t writeback_index;/* writeback starts here */ const struct address_space_operations *a_ops; /* methods */ /*集主要用于保存映射页所来自的GFP内存区的有关信息*/ unsigned long flags; /* error bits/gfp mask */ /*指向后备存储器结构,该结构包含了与地址空间相关的后备存储器的有关信息,后备存储器是指与地址空间相关的外部设备,用做地址空间中信息的来源。他通常是块设备*/ struct backing_dev_info *backing_dev_info; /* device readahead, etc */ spinlock_t private_lock; /* for use by the address_space */ /*用于将包含文件系统元数据(通常是间接块)的buffer_head实例彼此连接起来*/ struct list_head private_
  list; /* ditto */ /*指向相关的地址空间的指针*/ struct address_space *assoc_mappi
  ng; /* ditto */ }__attribute__(( aligned(siz
  eof(long))));后备存储信息[cpp] view plaincopyprint?
  Struct backing_dev_info { struct list_head bdi_list;struct rcu_head rcu_head;/*最大预读数量,单位为PAGE
  _CACHE_SIZE*/unsigned long ra_pages;
  /*max readahead in PAGE_CACHE_SIZE units */ /*对该成员,总是使用原子操作,指定了后备存储器的状态*/ unsigned long state; /* Always use atomic bitops on this *//*设备能力*/unsigned int capabiliti
  es;/* Device capabilities */ congested_fn *congested_fn; /* Function pointer if device is md/dm */ void *congested_data; /* Pointer to aux data for congested func */ void (*unplug_io_fn)(struct backing_dev_info *, struct page *);void *unplug_io_data;
  char *name;
  struct percpu_counter bdi_stat[NR_BDI_STAT_ITEMS];
  struct prop_local_percpu completions;int dirty_exceeded;
  unsigned int min_ratio;unsigned int max_ratio, max_prop_frac;
  struct bdi_writeback wb; /* default writeback info for this bdi */ spinlock_t wb_lock; /* protects update side of wb_list */ struct list_head wb_list; /* the flusher threads hanging off this bdi */ unsigned long wb_mask; /* bitmask of registered tasks */ unsigned int wb_cnt; /* number of registered tasks */
  struct list_head work_list;
  struct device *dev;
  #ifdef CONFIG_DEBUG_FS struct dentry *debug_dir;struct dentry *debug_stats;#endif };下图为地址空间与内核其他部分的关联。
  内核采用一种通用的地址空间方案,来建立缓存数据与其来源之间的关联。
  1)内存中的页分配到每个地址空间。这些页的内容可以由用户进程或内核本身使用各式各样的方法操作。这些数据表示了缓存中的内容;2)后备存储器struct backing_dev_info指定了填充地址空间中页的数据的来源。地址空间关联到处理器的虚拟地址空间,是由处理器在虚拟内存中管理的一个区域到设备device上对应位置之间的一个映射。
  如果访问了虚拟内存中的某个位置,该位置没有关联到物理内存页,内核可根据地址空间结构来找到读取数据的来源。
  为支持数据传输,每个地址空间都提供了一组操作,以容许地址空间所涉及双方面的交互。
  地址空间是内核中最关键的数据结构之一,对该数据结构的管理,已经演变为内核面对的最关键的问题之一。 页缓存的任务在于,获得一些物理内存页,以加速在块设备上按页为单位执行的操作。
  内核使用了基数树来管理与一个地址空间相关的所有页,以便尽可能降低开销。
  add_to_page_cache_locked, but used to add newly allocated pages:* the page is new, so we can just run __set_page_locked() against it. */ static inline int add_to_page_cache(struct page *page,struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask)
  /** * add_to_page_cache_locked - add a locked page to the pagecache * @page: page to add * @mapping: the page"s address_space * @offset: page index * @gfp_mask: page allocation mode * * This function is used to add a page to the pagecache. It must be locked. * This function does not add the page to the LRU. The caller must do that. */ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,pgoff_t offset, gfp_t gfp_mask)
  error=mem_cgroup_cache_charge(page, current->mm,gfp_mask & GFP_RECLAIM_MASK);if (error)
  
  
   LUPA开源社区

推荐访问:缓存 操作系统 机制 linux

相关文章:

Top