Re: [PATCH] mm/filemap: do not allocate cache pages beyond end of file at read

From: Linus Torvalds
Date: Mon Oct 28 2019 - 08:40:08 EST


On Mon, Oct 28, 2019 at 10:59 AM Konstantin Khlebnikov
<khlebnikov@xxxxxxxxxxxxxx> wrote:
>
> Page cache could contain pages beyond end of file during write or
> if read races with truncate. But generic_file_buffered_read() always
> allocates unneeded pages beyond eof if somebody reads here and one
> extra page at the end if file size is page-aligned.

I wonder if we could just do something like this instead:

diff --git a/mm/filemap.c b/mm/filemap.c
index 85b7d087eb45..80b08433c93a 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2013,7 +2013,7 @@ static ssize_t generic_file_buffered_read(
struct address_space *mapping = filp->f_mapping;
struct inode *inode = mapping->host;
struct file_ra_state *ra = &filp->f_ra;
- loff_t *ppos = &iocb->ki_pos;
+ loff_t *ppos = &iocb->ki_pos, size;
pgoff_t index;
pgoff_t last_index;
pgoff_t prev_index;
@@ -2021,9 +2021,10 @@ static ssize_t generic_file_buffered_read(
unsigned int prev_offset;
int error = 0;

- if (unlikely(*ppos >= inode->i_sb->s_maxbytes))
+ size = i_size_read(inode);
+ if (unlikely(*ppos >= size))
return 0;
- iov_iter_truncate(iter, inode->i_sb->s_maxbytes);
+ iov_iter_truncate(iter, size);

index = *ppos >> PAGE_SHIFT;
prev_index = ra->prev_pos >> PAGE_SHIFT;

and yes, we still need to re-check the inode size after we've read the
page cache page (since it might have changed during the IO), but the
above seems fairly benign and simple.

Hmm?

Linus