lkml.org 
[lkml]   [2017]   [Jun]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.11 093/115] xfs: Fix missed holes in SEEK_HOLE implementation
    Date
    4.11-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jan Kara <jack@suse.cz>

    commit 5375023ae1266553a7baa0845e82917d8803f48c upstream.

    XFS SEEK_HOLE implementation could miss a hole in an unwritten extent as
    can be seen by the following command:

    xfs_io -c "falloc 0 256k" -c "pwrite 0 56k" -c "pwrite 128k 8k"
    -c "seek -h 0" file
    wrote 57344/57344 bytes at offset 0
    56 KiB, 14 ops; 0.0000 sec (49.312 MiB/sec and 12623.9856 ops/sec)
    wrote 8192/8192 bytes at offset 131072
    8 KiB, 2 ops; 0.0000 sec (70.383 MiB/sec and 18018.0180 ops/sec)
    Whence Result
    HOLE 139264

    Where we can see that hole at offset 56k was just ignored by SEEK_HOLE
    implementation. The bug is in xfs_find_get_desired_pgoff() which does
    not properly detect the case when pages are not contiguous.

    Fix the problem by properly detecting when found page has larger offset
    than expected.

    Fixes: d126d43f631f996daeee5006714fed914be32368
    Signed-off-by: Jan Kara <jack@suse.cz>
    Reviewed-by: Brian Foster <bfoster@redhat.com>
    Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/xfs/xfs_file.c | 29 +++++++++--------------------
    1 file changed, 9 insertions(+), 20 deletions(-)

    --- a/fs/xfs/xfs_file.c
    +++ b/fs/xfs/xfs_file.c
    @@ -1076,17 +1076,6 @@ xfs_find_get_desired_pgoff(
    break;
    }

    - /*
    - * At lease we found one page. If this is the first time we
    - * step into the loop, and if the first page index offset is
    - * greater than the given search offset, a hole was found.
    - */
    - if (type == HOLE_OFF && lastoff == startoff &&
    - lastoff < page_offset(pvec.pages[0])) {
    - found = true;
    - break;
    - }
    -
    for (i = 0; i < nr_pages; i++) {
    struct page *page = pvec.pages[i];
    loff_t b_offset;
    @@ -1098,18 +1087,18 @@ xfs_find_get_desired_pgoff(
    * file mapping. However, page->index will not change
    * because we have a reference on the page.
    *
    - * Searching done if the page index is out of range.
    - * If the current offset is not reaches the end of
    - * the specified search range, there should be a hole
    - * between them.
    + * If current page offset is beyond where we've ended,
    + * we've found a hole.
    */
    - if (page->index > end) {
    - if (type == HOLE_OFF && lastoff < endoff) {
    - *offset = lastoff;
    - found = true;
    - }
    + if (type == HOLE_OFF && lastoff < endoff &&
    + lastoff < page_offset(pvec.pages[i])) {
    + found = true;
    + *offset = lastoff;
    goto out;
    }
    + /* Searching done if the page index is out of range. */
    + if (page->index > end)
    + goto out;

    lock_page(page);
    /*

    \
     
     \ /
      Last update: 2017-06-12 00:24    [W:6.315 / U:0.624 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site