"Linux Kernel Design and Implementation" Reading Notes-Page Cache and Page Writeback

Page cache

Page cache is a disk cache implemented by the Linux kernel, and its main function is to reduce IO operations on the disk.

The page cache is composed of physical pages in memory, whose contents correspond to physical blocks on the disk.

When the kernel starts a read operation, it will first check whether the required data is in the page cache.

There are several strategies for write caching:

  • Do not cache
  • Update memory cache and disk files at the same time;
  • Write back: data is written directly to the memory cache, and disk write is processed later in the write-back process (completed by the flusher thread, and can be completed by the sync() and fsync() system calls in the user process);

The page cache can be dynamically adjusted.

When it needs to make room for other places, it will adopt a cache recovery strategy to reclaim the memory cache.

Linux adopts a double-chain strategy.

The page cache caches any page-based objects, including various types of files and various types of memory mapping. (As mentioned earlier, it is mainly for disk caching, but there are actually many that can be cached)

 

address_space object

The Linux page cache uses the address_space structure to manage cache entries and page IO operations.

The address_space structure is as follows:

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))));

Among them, a_ops points to the operation function table in the address space object:

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 *);
};

 

Guess you like

Origin blog.csdn.net/jiangwei0512/article/details/106153195