Re: [PATCH] ext4: Fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2017-07-28 13:16 GMT+02:00 Jan Kara <jack@xxxxxxx>:
> ext4_find_unwritten_pgoff() does not properly handle a situation when
> starting index is in the middle of a page and blocksize < pagesize. The
> following command shows the bug on filesystem with 1k blocksize:
>
>   xfs_io -f -c "falloc 0 4k" \
>             -c "pwrite 1k 1k" \
>             -c "pwrite 3k 1k" \
>             -c "seek -a -r 0" foo
>
> In this example, neither lseek(fd, 1024, SEEK_HOLE) nor lseek(fd, 2048,
> SEEK_DATA) will return the correct result.
>
> Fix the problem by neglecting buffers in a page before starting offset.

This looks correct as a minimal fix for 4.13. We can later switch to
page_cache_seek_hole_data which does the same thing as
ext4_find_unwritten_pgoff, or directly to iomap_seek_{hole,data}.

> Reported-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx>
> CC: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Jan Kara <jack@xxxxxxx>
> ---
>  fs/ext4/file.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> This is an easy fix for the SEEK_HOLE/SEEK_DATA bug Andreas found. Longer
> term we want to move ext4 to use page_cache_seek_hole_data() however for
> stable backporting this is more suitable.
>
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index b221d0b546b0..8ba34cbe8fe7 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -530,6 +530,8 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
>                                 lastoff = page_offset(page);
>                                 bh = head = page_buffers(page);
>                                 do {
> +                                       if (lastoff + bh->b_size <= startoff)
> +                                               goto next;
>                                         if (buffer_uptodate(bh) ||
>                                             buffer_unwritten(bh)) {
>                                                 if (whence == SEEK_DATA)
> @@ -544,6 +546,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
>                                                 unlock_page(page);
>                                                 goto out;
>                                         }
> +next:
>                                         lastoff += bh->b_size;
>                                         bh = bh->b_this_page;
>                                 } while (bh != head);
> --
> 2.12.3

Thanks,
Andreas



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]