Skip to content

Commit 54fa39a

Browse files
Matthew Wilcox (Oracle)torvalds
authored andcommitted
iomap: use mapping_seek_hole_data
Enhance mapping_seek_hole_data() to handle partially uptodate pages and convert the iomap seek code to call it. Link: https://lkml.kernel.org/r/20201112212641.27837-9-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Christoph Hellwig <hch@lst.de> Cc: Dave Chinner <dchinner@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Jan Kara <jack@suse.cz> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> 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 41139aa commit 54fa39a

File tree

2 files changed

+43
-119
lines changed

2 files changed

+43
-119
lines changed

fs/iomap/seek.c

Lines changed: 11 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -10,122 +10,17 @@
1010
#include <linux/pagemap.h>
1111
#include <linux/pagevec.h>
1212

13-
/*
14-
* Seek for SEEK_DATA / SEEK_HOLE within @page, starting at @lastoff.
15-
* Returns true if found and updates @lastoff to the offset in file.
16-
*/
17-
static bool
18-
page_seek_hole_data(struct inode *inode, struct page *page, loff_t *lastoff,
19-
int whence)
20-
{
21-
const struct address_space_operations *ops = inode->i_mapping->a_ops;
22-
unsigned int bsize = i_blocksize(inode), off;
23-
bool seek_data = whence == SEEK_DATA;
24-
loff_t poff = page_offset(page);
25-
26-
if (WARN_ON_ONCE(*lastoff >= poff + PAGE_SIZE))
27-
return false;
28-
29-
if (*lastoff < poff) {
30-
/*
31-
* Last offset smaller than the start of the page means we found
32-
* a hole:
33-
*/
34-
if (whence == SEEK_HOLE)
35-
return true;
36-
*lastoff = poff;
37-
}
38-
39-
/*
40-
* Just check the page unless we can and should check block ranges:
41-
*/
42-
if (bsize == PAGE_SIZE || !ops->is_partially_uptodate)
43-
return PageUptodate(page) == seek_data;
44-
45-
lock_page(page);
46-
if (unlikely(page->mapping != inode->i_mapping))
47-
goto out_unlock_not_found;
48-
49-
for (off = 0; off < PAGE_SIZE; off += bsize) {
50-
if (offset_in_page(*lastoff) >= off + bsize)
51-
continue;
52-
if (ops->is_partially_uptodate(page, off, bsize) == seek_data) {
53-
unlock_page(page);
54-
return true;
55-
}
56-
*lastoff = poff + off + bsize;
57-
}
58-
59-
out_unlock_not_found:
60-
unlock_page(page);
61-
return false;
62-
}
63-
64-
/*
65-
* Seek for SEEK_DATA / SEEK_HOLE in the page cache.
66-
*
67-
* Within unwritten extents, the page cache determines which parts are holes
68-
* and which are data: uptodate buffer heads count as data; everything else
69-
* counts as a hole.
70-
*
71-
* Returns the resulting offset on successs, and -ENOENT otherwise.
72-
*/
7313
static loff_t
74-
page_cache_seek_hole_data(struct inode *inode, loff_t offset, loff_t length,
75-
int whence)
76-
{
77-
pgoff_t index = offset >> PAGE_SHIFT;
78-
pgoff_t end = DIV_ROUND_UP(offset + length, PAGE_SIZE);
79-
loff_t lastoff = offset;
80-
struct pagevec pvec;
81-
82-
if (length <= 0)
83-
return -ENOENT;
84-
85-
pagevec_init(&pvec);
86-
87-
do {
88-
unsigned nr_pages, i;
89-
90-
nr_pages = pagevec_lookup_range(&pvec, inode->i_mapping, &index,
91-
end - 1);
92-
if (nr_pages == 0)
93-
break;
94-
95-
for (i = 0; i < nr_pages; i++) {
96-
struct page *page = pvec.pages[i];
97-
98-
if (page_seek_hole_data(inode, page, &lastoff, whence))
99-
goto check_range;
100-
lastoff = page_offset(page) + PAGE_SIZE;
101-
}
102-
pagevec_release(&pvec);
103-
} while (index < end);
104-
105-
/* When no page at lastoff and we are not done, we found a hole. */
106-
if (whence != SEEK_HOLE)
107-
goto not_found;
108-
109-
check_range:
110-
if (lastoff < offset + length)
111-
goto out;
112-
not_found:
113-
lastoff = -ENOENT;
114-
out:
115-
pagevec_release(&pvec);
116-
return lastoff;
117-
}
118-
119-
120-
static loff_t
121-
iomap_seek_hole_actor(struct inode *inode, loff_t offset, loff_t length,
14+
iomap_seek_hole_actor(struct inode *inode, loff_t start, loff_t length,
12215
void *data, struct iomap *iomap, struct iomap *srcmap)
12316
{
17+
loff_t offset = start;
18+
12419
switch (iomap->type) {
12520
case IOMAP_UNWRITTEN:
126-
offset = page_cache_seek_hole_data(inode, offset, length,
127-
SEEK_HOLE);
128-
if (offset < 0)
21+
offset = mapping_seek_hole_data(inode->i_mapping, start,
22+
start + length, SEEK_HOLE);
23+
if (offset == start + length)
12924
return length;
13025
fallthrough;
13126
case IOMAP_HOLE:
@@ -164,15 +59,17 @@ iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
16459
EXPORT_SYMBOL_GPL(iomap_seek_hole);
16560

16661
static loff_t
167-
iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length,
62+
iomap_seek_data_actor(struct inode *inode, loff_t start, loff_t length,
16863
void *data, struct iomap *iomap, struct iomap *srcmap)
16964
{
65+
loff_t offset = start;
66+
17067
switch (iomap->type) {
17168
case IOMAP_HOLE:
17269
return length;
17370
case IOMAP_UNWRITTEN:
174-
offset = page_cache_seek_hole_data(inode, offset, length,
175-
SEEK_DATA);
71+
offset = mapping_seek_hole_data(inode->i_mapping, start,
72+
start + length, SEEK_DATA);
17673
if (offset < 0)
17774
return length;
17875
fallthrough;

mm/filemap.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,11 +2553,36 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
25532553
}
25542554
EXPORT_SYMBOL(generic_file_read_iter);
25552555

2556-
static inline bool page_seek_match(struct page *page, bool seek_data)
2556+
static inline loff_t page_seek_hole_data(struct xa_state *xas,
2557+
struct address_space *mapping, struct page *page,
2558+
loff_t start, loff_t end, bool seek_data)
25572559
{
2560+
const struct address_space_operations *ops = mapping->a_ops;
2561+
size_t offset, bsz = i_blocksize(mapping->host);
2562+
25582563
if (xa_is_value(page) || PageUptodate(page))
2559-
return seek_data;
2560-
return !seek_data;
2564+
return seek_data ? start : end;
2565+
if (!ops->is_partially_uptodate)
2566+
return seek_data ? end : start;
2567+
2568+
xas_pause(xas);
2569+
rcu_read_unlock();
2570+
lock_page(page);
2571+
if (unlikely(page->mapping != mapping))
2572+
goto unlock;
2573+
2574+
offset = offset_in_thp(page, start) & ~(bsz - 1);
2575+
2576+
do {
2577+
if (ops->is_partially_uptodate(page, offset, bsz) == seek_data)
2578+
break;
2579+
start = (start + bsz) & ~(bsz - 1);
2580+
offset += bsz;
2581+
} while (offset < thp_size(page));
2582+
unlock:
2583+
unlock_page(page);
2584+
rcu_read_lock();
2585+
return start;
25612586
}
25622587

25632588
static inline
@@ -2607,9 +2632,11 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
26072632
start = pos;
26082633
}
26092634

2610-
if (page_seek_match(page, seek_data))
2635+
pos += seek_page_size(&xas, page);
2636+
start = page_seek_hole_data(&xas, mapping, page, start, pos,
2637+
seek_data);
2638+
if (start < pos)
26112639
goto unlock;
2612-
start = pos + seek_page_size(&xas, page);
26132640
if (!xa_is_value(page))
26142641
put_page(page);
26152642
}

0 commit comments

Comments
 (0)