diff mbox series

btrfs: fix infinite loop with dio faulting

Message ID 27a36e2b4cf30de8f7a04e718ba47bb9e98ddb85.1658419807.git.josef@toxicpanda.com (mailing list archive)
State New, archived
Headers show
Series btrfs: fix infinite loop with dio faulting | expand

Commit Message

Josef Bacik July 21, 2022, 4:10 p.m. UTC
Filipe removed the check for the case where we are constantly trying to
fault in the buffer from user space for DIO reads.  He left it for
writes, but for reads you can end up in this infinite loop trying to
fault in a page that won't fault in.  This is the patch I applied ontop
of his patch, without this I was able to get generic/475 to get stuck
infinite looping.

This patch is currently staged so we can probably just fold this into
his actual patch.

Fixes: 5ad7531dbe67 ("btrfs: fault in pages for direct io reads/writes in a more controlled way")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/file.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

Comments

David Sterba Aug. 2, 2022, 5:17 p.m. UTC | #1
On Thu, Jul 21, 2022 at 12:10:14PM -0400, Josef Bacik wrote:
> Filipe removed the check for the case where we are constantly trying to
> fault in the buffer from user space for DIO reads.  He left it for
> writes, but for reads you can end up in this infinite loop trying to
> fault in a page that won't fault in.  This is the patch I applied ontop
> of his patch, without this I was able to get generic/475 to get stuck
> infinite looping.
> 
> This patch is currently staged so we can probably just fold this into
> his actual patch.

Folded to the patch, thanks.
Filipe Manana Aug. 2, 2022, 6:08 p.m. UTC | #2
On Thu, Jul 21, 2022 at 5:12 PM Josef Bacik <josef@toxicpanda.com> wrote:
>
> Filipe removed the check for the case where we are constantly trying to
> fault in the buffer from user space for DIO reads.  He left it for
> writes, but for reads you can end up in this infinite loop trying to
> fault in a page that won't fault in.

Yes, and the removal was intentional (not by accident).

Adding the check back makes the same check at dio_fault_in_size()
useless and redundant.

> This is the patch I applied ontop
> of his patch, without this I was able to get generic/475 to get stuck
> infinite looping.

This doesn't answer why the infinite loop happens.
Why can't we faultin at least one page? Have you checked why this happens?

So I'd rather not fold this into the original patch, and instead
revert it until we know exactly why we end in the infinite loop.

Thanks.

> This patch is currently staged so we can probably just fold this into
> his actual patch.
>
> Fixes: 5ad7531dbe67 ("btrfs: fault in pages for direct io reads/writes in a more controlled way")
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> ---
>  fs/btrfs/file.c | 15 ++++++++-------
>  1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 1876072dee9d..79f866e36368 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3806,20 +3806,21 @@ 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)) {
> -               if (iter_is_iovec(to)) {
> -                       const size_t left = iov_iter_count(to);
> -                       const size_t size = dio_fault_in_size(iocb, to, prev_left);
> +               const size_t left = iov_iter_count(to);
>
> -                       fault_in_iov_iter_writeable(to, size);
> -                       prev_left = left;
> -                       goto again;
> -               } else {
> +               if (left == prev_left) {
>                         /*
>                          * fault_in_iov_iter_writeable() only works for iovecs,
>                          * return with a partial read and fallback to buffered
>                          * IO for the rest of the range.
>                          */
>                         ret = read;
> +               } else {
> +                       const size_t size = dio_fault_in_size(iocb, to, prev_left);
> +
> +                       fault_in_iov_iter_writeable(to, size);
> +                       prev_left = left;
> +                       goto again;
>                 }
>         }
>         btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
> --
> 2.26.3
>
Filipe Manana Aug. 2, 2022, 6:09 p.m. UTC | #3
On Tue, Aug 2, 2022 at 7:00 PM David Sterba <dsterba@suse.cz> wrote:
>
> On Thu, Jul 21, 2022 at 12:10:14PM -0400, Josef Bacik wrote:
> > Filipe removed the check for the case where we are constantly trying to
> > fault in the buffer from user space for DIO reads.  He left it for
> > writes, but for reads you can end up in this infinite loop trying to
> > fault in a page that won't fault in.  This is the patch I applied ontop
> > of his patch, without this I was able to get generic/475 to get stuck
> > infinite looping.
> >
> > This patch is currently staged so we can probably just fold this into
> > his actual patch.
>
> Folded to the patch, thanks.

Please don't, revert instead the original patch.
See my previous reply to the patch.

Thanks.
David Sterba Aug. 2, 2022, 6:16 p.m. UTC | #4
On Tue, Aug 02, 2022 at 07:09:28PM +0100, Filipe Manana wrote:
> On Tue, Aug 2, 2022 at 7:00 PM David Sterba <dsterba@suse.cz> wrote:
> >
> > On Thu, Jul 21, 2022 at 12:10:14PM -0400, Josef Bacik wrote:
> > > Filipe removed the check for the case where we are constantly trying to
> > > fault in the buffer from user space for DIO reads.  He left it for
> > > writes, but for reads you can end up in this infinite loop trying to
> > > fault in a page that won't fault in.  This is the patch I applied ontop
> > > of his patch, without this I was able to get generic/475 to get stuck
> > > infinite looping.
> > >
> > > This patch is currently staged so we can probably just fold this into
> > > his actual patch.
> >
> > Folded to the patch, thanks.
> 
> Please don't, revert instead the original patch.

OK, patch removed from misc-next, no need to revert.
diff mbox series

Patch

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 1876072dee9d..79f866e36368 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3806,20 +3806,21 @@  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)) {
-		if (iter_is_iovec(to)) {
-			const size_t left = iov_iter_count(to);
-			const size_t size = dio_fault_in_size(iocb, to, prev_left);
+		const size_t left = iov_iter_count(to);
 
-			fault_in_iov_iter_writeable(to, size);
-			prev_left = left;
-			goto again;
-		} else {
+		if (left == prev_left) {
 			/*
 			 * fault_in_iov_iter_writeable() only works for iovecs,
 			 * return with a partial read and fallback to buffered
 			 * IO for the rest of the range.
 			 */
 			ret = read;
+		} else {
+			const size_t size = dio_fault_in_size(iocb, to, prev_left);
+
+			fault_in_iov_iter_writeable(to, size);
+			prev_left = left;
+			goto again;
 		}
 	}
 	btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);