|
10 | 10 | #include <linux/pagemap.h>
|
11 | 11 | #include <linux/pagevec.h>
|
12 | 12 |
|
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 |
| - */ |
73 | 13 | 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, |
122 | 15 | void *data, struct iomap *iomap, struct iomap *srcmap)
|
123 | 16 | {
|
| 17 | + loff_t offset = start; |
| 18 | + |
124 | 19 | switch (iomap->type) {
|
125 | 20 | 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) |
129 | 24 | return length;
|
130 | 25 | fallthrough;
|
131 | 26 | case IOMAP_HOLE:
|
@@ -164,15 +59,17 @@ iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
|
164 | 59 | EXPORT_SYMBOL_GPL(iomap_seek_hole);
|
165 | 60 |
|
166 | 61 | 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, |
168 | 63 | void *data, struct iomap *iomap, struct iomap *srcmap)
|
169 | 64 | {
|
| 65 | + loff_t offset = start; |
| 66 | + |
170 | 67 | switch (iomap->type) {
|
171 | 68 | case IOMAP_HOLE:
|
172 | 69 | return length;
|
173 | 70 | 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); |
176 | 73 | if (offset < 0)
|
177 | 74 | return length;
|
178 | 75 | fallthrough;
|
|
0 commit comments