1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2017 Red Hat, Inc. 4 * Copyright (c) 2018 Christoph Hellwig. 5 */ 6 #include <linux/module.h> 7 #include <linux/compiler.h> 8 #include <linux/fs.h> 9 #include <linux/iomap.h> 10 #include <linux/pagemap.h> 11 #include <linux/pagevec.h> 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 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, 122 void *data, struct iomap *iomap) 123 { 124 switch (iomap->type) { 125 case IOMAP_UNWRITTEN: 126 offset = page_cache_seek_hole_data(inode, offset, length, 127 SEEK_HOLE); 128 if (offset < 0) 129 return length; 130 /* fall through */ 131 case IOMAP_HOLE: 132 *(loff_t *)data = offset; 133 return 0; 134 default: 135 return length; 136 } 137 } 138 139 loff_t 140 iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops) 141 { 142 loff_t size = i_size_read(inode); 143 loff_t length = size - offset; 144 loff_t ret; 145 146 /* Nothing to be found before or beyond the end of the file. */ 147 if (offset < 0 || offset >= size) 148 return -ENXIO; 149 150 while (length > 0) { 151 ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops, 152 &offset, iomap_seek_hole_actor); 153 if (ret < 0) 154 return ret; 155 if (ret == 0) 156 break; 157 158 offset += ret; 159 length -= ret; 160 } 161 162 return offset; 163 } 164 EXPORT_SYMBOL_GPL(iomap_seek_hole); 165 166 static loff_t 167 iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length, 168 void *data, struct iomap *iomap) 169 { 170 switch (iomap->type) { 171 case IOMAP_HOLE: 172 return length; 173 case IOMAP_UNWRITTEN: 174 offset = page_cache_seek_hole_data(inode, offset, length, 175 SEEK_DATA); 176 if (offset < 0) 177 return length; 178 /*FALLTHRU*/ 179 default: 180 *(loff_t *)data = offset; 181 return 0; 182 } 183 } 184 185 loff_t 186 iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops) 187 { 188 loff_t size = i_size_read(inode); 189 loff_t length = size - offset; 190 loff_t ret; 191 192 /* Nothing to be found before or beyond the end of the file. */ 193 if (offset < 0 || offset >= size) 194 return -ENXIO; 195 196 while (length > 0) { 197 ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops, 198 &offset, iomap_seek_data_actor); 199 if (ret < 0) 200 return ret; 201 if (ret == 0) 202 break; 203 204 offset += ret; 205 length -= ret; 206 } 207 208 if (length <= 0) 209 return -ENXIO; 210 return offset; 211 } 212 EXPORT_SYMBOL_GPL(iomap_seek_data); 213