Skip to content

Commit ed98b01

Browse files
Hugh Dickinstorvalds
authored andcommitted
mm/filemap: fix mapping_seek_hole_data on THP & 32-bit
No problem on 64-bit, or without huge pages, but xfstests generic/285 and other SEEK_HOLE/SEEK_DATA tests have regressed on huge tmpfs, and on 32-bit architectures, with the new mapping_seek_hole_data(). Several different bugs turned out to need fixing. u64 cast to stop losing bits when converting unsigned long to loff_t (and let's use shifts throughout, rather than mixed with * and /). Use round_up() when advancing pos, to stop assuming that pos was already THP-aligned when advancing it by THP-size. (This use of round_up() assumes that any THP has THP-aligned index: true at present and true going forward, but could be recoded to avoid the assumption.) Use xas_set() when iterating away from a THP, so that xa_index stays in synch with start, instead of drifting away to return bogus offset. Check start against end to avoid wrapping 32-bit xa_index to 0 (and to handle these additional cases, seek_data or not, it's easier to break the loop than goto: so rearrange exit from the function). [hughd@google.com: remove unneeded u64 casts, per Matthew] Link: https://lkml.kernel.org/r/alpine.LSU.2.11.2104221347240.1170@eggly.anvils Link: https://lkml.kernel.org/r/alpine.LSU.2.11.2104211737410.3299@eggly.anvils Fixes: 41139aa ("mm/filemap: add mapping_seek_hole_data") Signed-off-by: Hugh Dickins <hughd@google.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Dave Chinner <dchinner@redhat.com> Cc: Jan Kara <jack@suse.cz> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: William Kucharski <william.kucharski@oracle.com> Cc: Yang Shi <yang.shi@linux.alibaba.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 2d11e73 commit ed98b01

1 file changed

Lines changed: 11 additions & 10 deletions

File tree

mm/filemap.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,7 +2678,7 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
26782678
loff_t end, int whence)
26792679
{
26802680
XA_STATE(xas, &mapping->i_pages, start >> PAGE_SHIFT);
2681-
pgoff_t max = (end - 1) / PAGE_SIZE;
2681+
pgoff_t max = (end - 1) >> PAGE_SHIFT;
26822682
bool seek_data = (whence == SEEK_DATA);
26832683
struct page *page;
26842684

@@ -2687,33 +2687,34 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
26872687

26882688
rcu_read_lock();
26892689
while ((page = find_get_entry(&xas, max, XA_PRESENT))) {
2690-
loff_t pos = xas.xa_index * PAGE_SIZE;
2690+
loff_t pos = (u64)xas.xa_index << PAGE_SHIFT;
2691+
unsigned int seek_size;
26912692

26922693
if (start < pos) {
26932694
if (!seek_data)
26942695
goto unlock;
26952696
start = pos;
26962697
}
26972698

2698-
pos += seek_page_size(&xas, page);
2699+
seek_size = seek_page_size(&xas, page);
2700+
pos = round_up(pos + 1, seek_size);
26992701
start = page_seek_hole_data(&xas, mapping, page, start, pos,
27002702
seek_data);
27012703
if (start < pos)
27022704
goto unlock;
2705+
if (start >= end)
2706+
break;
2707+
if (seek_size > PAGE_SIZE)
2708+
xas_set(&xas, pos >> PAGE_SHIFT);
27032709
if (!xa_is_value(page))
27042710
put_page(page);
27052711
}
2706-
rcu_read_unlock();
2707-
27082712
if (seek_data)
2709-
return -ENXIO;
2710-
goto out;
2711-
2713+
start = -ENXIO;
27122714
unlock:
27132715
rcu_read_unlock();
2714-
if (!xa_is_value(page))
2716+
if (page && !xa_is_value(page))
27152717
put_page(page);
2716-
out:
27172718
if (start > end)
27182719
return end;
27192720
return start;

0 commit comments

Comments
 (0)