mm/filemap.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 60a7b9275741..ba11f018ca6b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2792,20 +2792,37 @@ 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; + 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; } }