diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 91a5fa814d75..19feb4cabb55 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3716,6 +3716,7 @@ static int check_direct_read(struct btrfs_fs_info *fs_info, static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); + size_t prev_left = 0; ssize_t read = 0; ssize_t ret; @@ -3753,18 +3754,23 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to) read = ret; if (iov_iter_count(to) > 0 && (ret == -EFAULT || ret > 0)) { + const size_t left = iov_iter_count(to); + /* * We have more data left to read. Try to fault in as many as * possible of the remainder pages and retry. - * - * Unlike for direct IO writes, in case the iov refers to the - * file and range we are reading from (due to a mmap), we don't - * need to worry about an infinite loop (see btrfs_direct_write()) - * because iomap does not invalidate pages for reads, only does - * it for writes. */ - fault_in_iov_iter_writeable(to, iov_iter_count(to)); - goto again; + if (prev_left == 0 || left < prev_left) { + fault_in_iov_iter_writeable(to, left); + prev_left = left; + goto again; + } + /* + * If we didn't make any progress since the last attempt, fallback + * to a buffered read for the remainder of the range. + * This is just to avoid any possibility of looping for too long. + */ + ret = read; } btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED); return ret < 0 ? ret : read;