mirror of https://gitee.com/openkylin/linux.git
xfs: Fix missed holes in SEEK_HOLE implementation
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.
CC: stable@vger.kernel.org
Fixes: d126d43f63
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>
This commit is contained in:
parent
8affebe16d
commit
5375023ae1
|
@ -1076,17 +1076,6 @@ xfs_find_get_desired_pgoff(
|
||||||
break;
|
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++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
struct page *page = pvec.pages[i];
|
struct page *page = pvec.pages[i];
|
||||||
loff_t b_offset;
|
loff_t b_offset;
|
||||||
|
@ -1098,18 +1087,18 @@ xfs_find_get_desired_pgoff(
|
||||||
* file mapping. However, page->index will not change
|
* file mapping. However, page->index will not change
|
||||||
* because we have a reference on the page.
|
* because we have a reference on the page.
|
||||||
*
|
*
|
||||||
* Searching done if the page index is out of range.
|
* If current page offset is beyond where we've ended,
|
||||||
* If the current offset is not reaches the end of
|
* we've found a hole.
|
||||||
* the specified search range, there should be a hole
|
|
||||||
* between them.
|
|
||||||
*/
|
*/
|
||||||
if (page->index > end) {
|
if (type == HOLE_OFF && lastoff < endoff &&
|
||||||
if (type == HOLE_OFF && lastoff < endoff) {
|
lastoff < page_offset(pvec.pages[i])) {
|
||||||
*offset = lastoff;
|
found = true;
|
||||||
found = true;
|
*offset = lastoff;
|
||||||
}
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
/* Searching done if the page index is out of range. */
|
||||||
|
if (page->index > end)
|
||||||
|
goto out;
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue