Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : /* 3 : * Copyright (C) 2017 Red Hat, Inc. 4 : * Copyright (c) 2018-2021 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 2178 : static loff_t iomap_seek_hole_iter(const struct iomap_iter *iter, 14 : loff_t *hole_pos) 15 : { 16 2178 : loff_t length = iomap_length(iter); 17 : 18 2178 : switch (iter->iomap.type) { 19 774 : case IOMAP_UNWRITTEN: 20 1548 : *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping, 21 774 : iter->pos, iter->pos + length, SEEK_HOLE); 22 774 : if (*hole_pos == iter->pos + length) 23 285 : return length; 24 : return 0; 25 755 : case IOMAP_HOLE: 26 755 : *hole_pos = iter->pos; 27 755 : return 0; 28 : default: 29 : return length; 30 : } 31 : } 32 : 33 : loff_t 34 1601 : iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops) 35 : { 36 1601 : loff_t size = i_size_read(inode); 37 1601 : struct iomap_iter iter = { 38 : .inode = inode, 39 : .pos = pos, 40 : .flags = IOMAP_REPORT, 41 : }; 42 1601 : int ret; 43 : 44 : /* Nothing to be found before or beyond the end of the file. */ 45 1601 : if (pos < 0 || pos >= size) 46 : return -ENXIO; 47 : 48 1433 : iter.len = size - pos; 49 3611 : while ((ret = iomap_iter(&iter, ops)) > 0) 50 2178 : iter.processed = iomap_seek_hole_iter(&iter, &pos); 51 1433 : if (ret < 0) 52 0 : return ret; 53 1433 : if (iter.len) /* found hole before EOF */ 54 1244 : return pos; 55 : return size; 56 : } 57 : EXPORT_SYMBOL_GPL(iomap_seek_hole); 58 : 59 435886 : static loff_t iomap_seek_data_iter(const struct iomap_iter *iter, 60 : loff_t *hole_pos) 61 : { 62 435886 : loff_t length = iomap_length(iter); 63 : 64 435886 : switch (iter->iomap.type) { 65 : case IOMAP_HOLE: 66 : return length; 67 47756 : case IOMAP_UNWRITTEN: 68 95512 : *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping, 69 47756 : iter->pos, iter->pos + length, SEEK_DATA); 70 47756 : if (*hole_pos < 0) 71 30303 : return length; 72 : return 0; 73 175474 : default: 74 175474 : *hole_pos = iter->pos; 75 175474 : return 0; 76 : } 77 : } 78 : 79 : loff_t 80 243021 : iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops) 81 : { 82 243021 : loff_t size = i_size_read(inode); 83 243021 : struct iomap_iter iter = { 84 : .inode = inode, 85 : .pos = pos, 86 : .flags = IOMAP_REPORT, 87 : }; 88 243021 : int ret; 89 : 90 : /* Nothing to be found before or beyond the end of the file. */ 91 243021 : if (pos < 0 || pos >= size) 92 : return -ENXIO; 93 : 94 204128 : iter.len = size - pos; 95 640014 : while ((ret = iomap_iter(&iter, ops)) > 0) 96 435886 : iter.processed = iomap_seek_data_iter(&iter, &pos); 97 204128 : if (ret < 0) 98 0 : return ret; 99 204128 : if (iter.len) /* found data before EOF */ 100 192927 : return pos; 101 : /* We've reached the end of the file without finding data */ 102 : return -ENXIO; 103 : } 104 : EXPORT_SYMBOL_GPL(iomap_seek_data);