[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210120160611.26853-3-jack@suse.cz>
Date: Wed, 20 Jan 2021 17:06:10 +0100
From: Jan Kara <jack@...e.cz>
To: <linux-fsdevel@...r.kernel.org>
Cc: Matthew Wilcox <willy@...radead.org>, <linux-ext4@...r.kernel.org>,
Jan Kara <jack@...e.cz>
Subject: [PATCH 2/3] mm: Provide address_space operation for filling pages for read
Provide an address_space operation for filling pages needed for read
into page cache. Filesystems can use this operation to seriealize
page cache filling with e.g. hole punching properly.
Signed-off-by: Jan Kara <jack@...e.cz>
---
include/linux/fs.h | 5 +++++
mm/filemap.c | 32 ++++++++++++++++++++++++++------
2 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index fd47deea7c17..1d3f963d0d99 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -381,6 +381,9 @@ 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 *);
+ /* Fill in uptodate pages for kiocb into page cache and pagep array */
+ int (*fill_pages)(struct kiocb *, size_t len, bool partial_page,
+ struct page **pagep, unsigned int nr_pages);
int (*write_begin)(struct file *, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
@@ -2962,6 +2965,8 @@ extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *);
extern int generic_write_check_limits(struct file *file, loff_t pos,
loff_t *count);
extern int generic_file_rw_checks(struct file *file_in, struct file *file_out);
+extern int generic_file_buffered_read_get_pages(struct kiocb *iocb, size_t len,
+ bool partial_page, struct page **pages, unsigned int nr);
extern ssize_t generic_file_buffered_read(struct kiocb *iocb,
struct iov_iter *to, ssize_t already_read);
extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
diff --git a/mm/filemap.c b/mm/filemap.c
index 7029bada8e90..5b594dd245e0 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2333,10 +2333,24 @@ generic_file_buffered_read_no_cached_page(struct kiocb *iocb)
return generic_file_buffered_read_readpage(iocb, filp, mapping, page);
}
-static int generic_file_buffered_read_get_pages(struct kiocb *iocb,
- size_t len, bool partial_page,
- struct page **pages,
- unsigned int nr)
+/**
+ * generic_file_buffered_read_get_pages - generic routine to fill in page cache
+ * pages for a read
+ * @iocb: the iocb to read
+ * @len: number of bytes to read
+ * @partial_page: are partially uptodate pages accepted by read?
+ * @pages: array where to fill in found pages
+ * @nr: number of pages in the @pages array
+ *
+ * Fill pages into page cache and @pages array needed for a read of length @len
+ * described by @iocb.
+ *
+ * Return:
+ * Number of pages filled in the array
+ */
+int generic_file_buffered_read_get_pages(struct kiocb *iocb, size_t len,
+ bool partial_page,
+ struct page **pages, unsigned int nr)
{
struct file *filp = iocb->ki_filp;
struct address_space *mapping = filp->f_mapping;
@@ -2419,6 +2433,7 @@ static int generic_file_buffered_read_get_pages(struct kiocb *iocb,
*/
goto find_page;
}
+EXPORT_SYMBOL(generic_file_buffered_read_get_pages);
/**
* generic_file_buffered_read - generic file read routine
@@ -2447,6 +2462,8 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
unsigned int nr_pages = min_t(unsigned int, 512,
((iocb->ki_pos + iter->count + PAGE_SIZE - 1) >> PAGE_SHIFT) -
(iocb->ki_pos >> PAGE_SHIFT));
+ int (*fill_pages)(struct kiocb *, size_t, bool, struct page **,
+ unsigned int) = mapping->a_ops->fill_pages;
int i, pg_nr, error = 0;
bool writably_mapped;
loff_t isize, end_offset;
@@ -2456,6 +2473,9 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
if (unlikely(!iov_iter_count(iter)))
return 0;
+ if (!fill_pages)
+ fill_pages = generic_file_buffered_read_get_pages;
+
iov_iter_truncate(iter, inode->i_sb->s_maxbytes);
if (nr_pages > ARRAY_SIZE(pages_onstack))
@@ -2478,8 +2498,8 @@ ssize_t generic_file_buffered_read(struct kiocb *iocb,
iocb->ki_flags |= IOCB_NOWAIT;
i = 0;
- pg_nr = generic_file_buffered_read_get_pages(iocb, iter->count,
- !iov_iter_is_pipe(iter), pages, nr_pages);
+ pg_nr = fill_pages(iocb, iter->count, !iov_iter_is_pipe(iter),
+ pages, nr_pages);
if (pg_nr < 0) {
error = pg_nr;
break;
--
2.26.2
Powered by blists - more mailing lists