《Linux内核设计与实现》读书笔记——页高速缓存和页回写

页高速缓存

页高速缓存是Linux内核实现磁盘缓存,它的主要作用是减少对磁盘的IO操作。

页高速缓存是由内存中的物理页组成的,其内容对应磁盘上的物理块。

当内核开始一个读操作时,会先检查需要的数据是否在页高速缓存中。

写缓存有几种策略:

  • 不缓存;
  • 同时更新内存缓存和磁盘文件;
  • 回写:数据直接写到内存缓存,而磁盘写放到回写进程中稍后处理(由flusher线程完成,用户进程中可以通过sync()和fsync()系统调用来完成);

页高速缓存能够动态调整。

当需要腾出空间给其它地方使用是,会采用的是缓存回收策略回收内存缓存。

Linux采用双链策略。

页高速缓存缓存任何基于页的对象,包括各种类型的文件和各种类型的内存映射。(前面有提到主要是为了磁盘缓存,但是实际上可以缓存的有很多)

 

address_space对象

Linux页高速缓存使用address_space结构体管理缓存项和页IO操作。

address_space结构体如下:

struct address_space {
    struct inode        *host;      /* owner: inode, block_device */
    struct radix_tree_root  page_tree;  /* radix tree of all pages */
    spinlock_t      tree_lock;  /* and lock protecting it */
    unsigned int        i_mmap_writable;/* count VM_SHARED mappings */
    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 */
    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 */
    struct list_head    private_list;   /* ditto */
    struct address_space    *assoc_mapping; /* ditto */
} __attribute__((aligned(sizeof(long))));

其中a_ops指向地址空间对象中的操作函数表:

struct address_space_operations {
    int (*writepage)(struct page *page, struct writeback_control *wbc);
    int (*readpage)(struct file *, struct page *);
    void (*sync_page)(struct page *);
    /* Write back some dirty pages from this mapping. */
    int (*writepages)(struct address_space *, struct writeback_control *);
    /* Set a page dirty.  Return true if this dirtied it */
    int (*set_page_dirty)(struct page *page);
    int (*readpages)(struct file *filp, struct address_space *mapping,
            struct list_head *pages, unsigned nr_pages);
    int (*write_begin)(struct file *, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata);
    int (*write_end)(struct file *, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned copied,
                struct page *page, void *fsdata);
    /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
    sector_t (*bmap)(struct address_space *, sector_t);
    void (*invalidatepage) (struct page *, unsigned long);
    int (*releasepage) (struct page *, gfp_t);
    ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
            loff_t offset, unsigned long nr_segs);
    int (*get_xip_mem)(struct address_space *, pgoff_t, int,
                        void **, unsigned long *);
    /* migrate the contents of a page to the specified target */
    int (*migratepage) (struct address_space *,
            struct page *, struct page *);
    int (*launder_page) (struct page *);
    int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
                    unsigned long);
    int (*error_remove_page)(struct address_space *, struct page *);
};

 

猜你喜欢

转载自blog.csdn.net/jiangwei0512/article/details/106153195