mm/filemap.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 60a7b9275741..541273388512 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2697,7 +2697,7 @@ static void filemap_end_dropbehind_read(struct folio *folio) } } -static inline unsigned long filemap_fast_read(struct address_space *mapping, +static unsigned long filemap_fast_read(struct address_space *mapping, loff_t pos, char *buffer, size_t size) { @@ -2792,20 +2792,38 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, * any compiler initialization would be pointless since this * can fill it will garbage. */ - if (iov_iter_count(iter) <= sizeof(area)) { + if (iov_iter_count(iter) <= PAGE_SIZE) { size_t count = iov_iter_count(iter); + size_t fast_read = 0; /* Let's see if we can just do the read under RCU */ rcu_read_lock(); - count = filemap_fast_read(mapping, iocb->ki_pos, area.buffer, count); + pagefault_disable(); + do { + size_t copied = min(count, sizeof(area)); + + copied = filemap_fast_read(mapping, iocb->ki_pos, area.buffer, copied); + if (!copied) + break; + copied = copy_to_iter(area.buffer, copied, iter); + if (!copied) + break; + fast_read += copied; + iocb->ki_pos += copied; + already_read += copied; + count -= copied; + } while (count); + pagefault_enable(); rcu_read_unlock(); - if (count) { - size_t copied = copy_to_iter(area.buffer, count, iter); - if (unlikely(!copied)) - return already_read ? already_read : -EFAULT; - ra->prev_pos = iocb->ki_pos += copied; + + if (fast_read) { + ra->prev_pos += fast_read; + already_read += fast_read; file_accessed(filp); - return copied + already_read; + + /* All done? */ + if (!count) + return already_read; } }