mm: add readahead address space operation
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 2 Jun 2020 04:46:44 +0000 (21:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 2 Jun 2020 17:59:06 +0000 (10:59 -0700)
This replaces ->readpages with a saner interface:
 - Return void instead of an ignored error code.
 - Page cache is already populated with locked pages when ->readahead
   is called.
 - New arguments can be passed to the implementation without changing
   all the filesystems that use a common helper function like
   mpage_readahead().

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: John Hubbard <jhubbard@nvidia.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
Cc: Chao Yu <yuchao0@huawei.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
Cc: Darrick J. Wong <darrick.wong@oracle.com>
Cc: Dave Chinner <dchinner@redhat.com>
Cc: Eric Biggers <ebiggers@google.com>
Cc: Gao Xiang <gaoxiang25@huawei.com>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Cc: Miklos Szeredi <mszeredi@redhat.com>
Link: http://lkml.kernel.org/r/20200414150233.24495-12-willy@infradead.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/filesystems/locking.rst
Documentation/filesystems/vfs.rst
include/linux/fs.h
mm/readahead.c

index 5057e4d9dcd1d6c8799dafac8ef0ebab022e695d..0af2e0e11461d04bc9a6c33377e29474c945f67e 100644 (file)
@@ -239,6 +239,7 @@ prototypes::
        int (*readpage)(struct file *, struct page *);
        int (*writepages)(struct address_space *, struct writeback_control *);
        int (*set_page_dirty)(struct page *page);
+       void (*readahead)(struct readahead_control *);
        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,
@@ -271,7 +272,8 @@ writepage:          yes, unlocks (see below)
 readpage:              yes, unlocks
 writepages:
 set_page_dirty         no
-readpages:
+readahead:             yes, unlocks
+readpages:             no
 write_begin:           locks the page           exclusive
 write_end:             yes, unlocks             exclusive
 bmap:
@@ -295,6 +297,8 @@ the request handler (/dev/loop).
 ->readpage() unlocks the page, either synchronously or via I/O
 completion.
 
+->readahead() unlocks the pages that I/O is attempted on like ->readpage().
+
 ->readpages() populates the pagecache with the passed pages and starts
 I/O against them.  They come unlocked upon I/O completion.
 
index 7d4d09dd5e6dec98bfb062da7e11d9996dd106d5..ed17771c212b8e49520acbb587cd24fd806c274b 100644 (file)
@@ -706,6 +706,7 @@ cache in your filesystem.  The following members are defined:
                int (*readpage)(struct file *, struct page *);
                int (*writepages)(struct address_space *, struct writeback_control *);
                int (*set_page_dirty)(struct page *page);
+               void (*readahead)(struct readahead_control *);
                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,
@@ -781,12 +782,26 @@ cache in your filesystem.  The following members are defined:
        If defined, it should set the PageDirty flag, and the
        PAGECACHE_TAG_DIRTY tag in the radix tree.
 
+``readahead``
+       Called by the VM to read pages associated with the address_space
+       object.  The pages are consecutive in the page cache and are
+       locked.  The implementation should decrement the page refcount
+       after starting I/O on each page.  Usually the page will be
+       unlocked by the I/O completion handler.  If the filesystem decides
+       to stop attempting I/O before reaching the end of the readahead
+       window, it can simply return.  The caller will decrement the page
+       refcount and unlock the remaining pages for you.  Set PageUptodate
+       if the I/O completes successfully.  Setting PageError on any page
+       will be ignored; simply unlock the page if an I/O error occurs.
+
 ``readpages``
        called by the VM to read pages associated with the address_space
        object.  This is essentially just a vector version of readpage.
        Instead of just one page, several pages are requested.
        readpages is only used for read-ahead, so read errors are
        ignored.  If anything goes wrong, feel free to give up.
+       This interface is deprecated and will be removed by the end of
+       2020; implement readahead instead.
 
 ``write_begin``
        Called by the generic buffered write code to ask the filesystem
index f2fb5b7406b9f4bbc324bffc22365261f1203c53..1434ed801b809a3b2d5ab7801b8a8ecc31e50717 100644 (file)
@@ -292,6 +292,7 @@ enum positive_aop_returns {
 struct page;
 struct address_space;
 struct writeback_control;
+struct readahead_control;
 
 /*
  * Write life time hint values.
@@ -375,6 +376,7 @@ struct address_space_operations {
         */
        int (*readpages)(struct file *filp, struct address_space *mapping,
                        struct list_head *pages, unsigned nr_pages);
+       void (*readahead)(struct readahead_control *);
 
        int (*write_begin)(struct file *, struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
index e52b3a7b9da58ca3f8c13134f978c1575b31edb6..d01531ef9f3c6a4a21fc300d27b889b11b52ad8c 100644 (file)
@@ -125,7 +125,14 @@ static void read_pages(struct readahead_control *rac, struct list_head *pages,
 
        blk_start_plug(&plug);
 
-       if (aops->readpages) {
+       if (aops->readahead) {
+               aops->readahead(rac);
+               /* Clean up the remaining pages */
+               while ((page = readahead_page(rac))) {
+                       unlock_page(page);
+                       put_page(page);
+               }
+       } else if (aops->readpages) {
                aops->readpages(rac->file, rac->mapping, pages,
                                readahead_count(rac));
                /* Clean up the remaining pages */
@@ -233,7 +240,8 @@ void force_page_cache_readahead(struct address_space *mapping,
        struct file_ra_state *ra = &filp->f_ra;
        unsigned long max_pages;
 
-       if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
+       if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages &&
+                       !mapping->a_ops->readahead))
                return;
 
        /*