Change all the callers of ->readpage to call ->read_folio in preference, if it exists. This is a transitional duplication, and will be removed by the end of the series. Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx> --- fs/btrfs/file.c | 2 +- fs/buffer.c | 5 ++++- fs/ceph/addr.c | 2 +- include/linux/fs.h | 1 + kernel/events/uprobes.c | 6 ++++-- mm/filemap.c | 9 +++++++-- mm/readahead.c | 14 +++++++++----- mm/swapfile.c | 2 +- 8 files changed, 28 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 380054c94e4b..59510d7b1c65 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2401,7 +2401,7 @@ static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) { struct address_space *mapping = filp->f_mapping; - if (!mapping->a_ops->readpage) + if (!mapping->a_ops->readpage && !mapping->a_ops->read_folio) return -ENOEXEC; file_accessed(filp); diff --git a/fs/buffer.c b/fs/buffer.c index 9737e0dbe3ec..225d03cd622d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2824,7 +2824,10 @@ int nobh_truncate_page(struct address_space *mapping, /* Ok, it's mapped. Make sure it's up-to-date */ if (!folio_test_uptodate(folio)) { - err = mapping->a_ops->readpage(NULL, &folio->page); + if (mapping->a_ops->read_folio) + err = mapping->a_ops->read_folio(NULL, folio); + else + err = mapping->a_ops->readpage(NULL, &folio->page); if (err) { folio_put(folio); goto out; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e65541a51b68..42bba2b5d98b 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1772,7 +1772,7 @@ int ceph_mmap(struct file *file, struct vm_area_struct *vma) { struct address_space *mapping = file->f_mapping; - if (!mapping->a_ops->readpage) + if (!mapping->a_ops->readpage && !mapping->a_ops->read_folio) return -ENOEXEC; file_accessed(file); vma->vm_ops = &ceph_vmops; diff --git a/include/linux/fs.h b/include/linux/fs.h index 2be852661a29..5ad942183a2c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -336,6 +336,7 @@ static inline bool is_sync_kiocb(struct kiocb *kiocb) struct address_space_operations { int (*writepage)(struct page *page, struct writeback_control *wbc); int (*readpage)(struct file *, struct page *); + int (*read_folio)(struct file *, struct folio *); /* Write back some dirty pages from this mapping. */ int (*writepages)(struct address_space *, struct writeback_control *); diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 6418083901d4..a340b1043efa 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -790,7 +790,7 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, * and in page-cache. If ->readpage == NULL it must be shmem_mapping(), * see uprobe_register(). */ - if (mapping->a_ops->readpage) + if (mapping->ops->read_folio || mapping->a_ops->readpage) page = read_mapping_page(mapping, offset >> PAGE_SHIFT, filp); else page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); @@ -1143,7 +1143,9 @@ static int __uprobe_register(struct inode *inode, loff_t offset, return -EINVAL; /* copy_insn() uses read_mapping_page() or shmem_read_mapping_page() */ - if (!inode->i_mapping->a_ops->readpage && !shmem_mapping(inode->i_mapping)) + if (!inode->i_mapping->a_ops->read_folio && + !inode->i_mapping->a_ops->readpage && + !shmem_mapping(inode->i_mapping)) return -EIO; /* Racy, just to catch the obvious mistakes */ if (offset > i_size_read(inode)) diff --git a/mm/filemap.c b/mm/filemap.c index c15cfc28f9ce..96e3d7ffd98e 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2419,7 +2419,10 @@ static int filemap_read_folio(struct file *file, struct address_space *mapping, */ folio_clear_error(folio); /* Start the actual read. The read will unlock the page. */ - error = mapping->a_ops->readpage(file, &folio->page); + if (mapping->a_ops->read_folio) + error = mapping->a_ops->read_folio(file, folio); + else + error = mapping->a_ops->readpage(file, &folio->page); if (error) return error; @@ -3447,7 +3450,7 @@ int generic_file_mmap(struct file *file, struct vm_area_struct *vma) { struct address_space *mapping = file->f_mapping; - if (!mapping->a_ops->readpage) + if (!mapping->a_ops->read_folio && !mapping->a_ops->readpage) return -ENOEXEC; file_accessed(file); vma->vm_ops = &generic_file_vm_ops; @@ -3505,6 +3508,8 @@ static struct folio *do_read_cache_folio(struct address_space *mapping, filler: if (filler) err = filler(data, &folio->page); + else if (mapping->a_ops->read_folio) + err = mapping->a_ops->read_folio(data, folio); else err = mapping->a_ops->readpage(data, &folio->page); diff --git a/mm/readahead.c b/mm/readahead.c index 60a28af25c4e..76024c20a5a5 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -15,7 +15,7 @@ * explicitly requested by the application. Readahead only ever * attempts to read folios that are not yet in the page cache. If a * folio is present but not up-to-date, readahead will not try to read - * it. In that case a simple ->readpage() will be requested. + * it. In that case a simple ->read_folio() will be requested. * * Readahead is triggered when an application read request (whether a * system call or a page fault) finds that the requested folio is not in @@ -78,7 +78,7 @@ * address space operation, for which mpage_readahead() is a canonical * implementation. ->readahead() should normally initiate reads on all * folios, but may fail to read any or all folios without causing an I/O - * error. The page cache reading code will issue a ->readpage() request + * error. The page cache reading code will issue a ->read_folio() request * for any folio which ->readahead() did not read, and only an error * from this will be final. * @@ -110,7 +110,7 @@ * were not fetched with readahead_folio(). This will allow a * subsequent synchronous readahead request to try them again. If they * are left in the page cache, then they will be read individually using - * ->readpage() which may be less efficient. + * ->read_folio() which may be less efficient. */ #include <linux/kernel.h> @@ -170,8 +170,11 @@ static void read_pages(struct readahead_control *rac) } folio_unlock(folio); } + } else if (aops->read_folio) { + while ((folio = readahead_folio(rac)) != NULL) + aops->read_folio(rac->file, folio); } else { - while ((folio = readahead_folio(rac))) + while ((folio = readahead_folio(rac)) != NULL) aops->readpage(rac->file, &folio->page); } @@ -302,7 +305,8 @@ void force_page_cache_ra(struct readahead_control *ractl, struct backing_dev_info *bdi = inode_to_bdi(mapping->host); unsigned long max_pages, index; - if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readahead)) + if (unlikely(!mapping->a_ops->read_folio && + !mapping->a_ops->readpage && !mapping->a_ops->readahead)) return; /* diff --git a/mm/swapfile.c b/mm/swapfile.c index 63c61f8b2611..7c19098b8b45 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -3041,7 +3041,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) /* * Read the swap header. */ - if (!mapping->a_ops->readpage) { + if (!mapping->a_ops->read_folio && !mapping->a_ops->readpage) { error = -EINVAL; goto bad_swap_unlock_inode; } -- 2.34.1