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 456 : static loff_t iomap_seek_hole_iter(const struct iomap_iter *iter, 14 : loff_t *hole_pos) 15 : { 16 456 : loff_t length = iomap_length(iter); 17 : 18 456 : switch (iter->iomap.type) { 19 108 : case IOMAP_UNWRITTEN: 20 216 : *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping, 21 108 : iter->pos, iter->pos + length, SEEK_HOLE); 22 108 : if (*hole_pos == iter->pos + length) 23 4 : return length; 24 : return 0; 25 158 : case IOMAP_HOLE: 26 158 : *hole_pos = iter->pos; 27 158 : return 0; 28 : default: 29 : return length; 30 : } 31 : } 32 : 33 : loff_t 34 326 : iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops) 35 : { 36 326 : loff_t size = i_size_read(inode); 37 326 : struct iomap_iter iter = { 38 : .inode = inode, 39 : .pos = pos, 40 : .flags = IOMAP_REPORT, 41 : }; 42 326 : int ret; 43 : 44 : /* Nothing to be found before or beyond the end of the file. */ 45 326 : if (pos < 0 || pos >= size) 46 : return -ENXIO; 47 : 48 298 : iter.len = size - pos; 49 754 : while ((ret = iomap_iter(&iter, ops)) > 0) 50 456 : iter.processed = iomap_seek_hole_iter(&iter, &pos); 51 298 : if (ret < 0) 52 0 : return ret; 53 298 : if (iter.len) /* found hole before EOF */ 54 262 : return pos; 55 : return size; 56 : } 57 : EXPORT_SYMBOL_GPL(iomap_seek_hole); 58 : 59 413545 : static loff_t iomap_seek_data_iter(const struct iomap_iter *iter, 60 : loff_t *hole_pos) 61 : { 62 413545 : loff_t length = iomap_length(iter); 63 : 64 413545 : switch (iter->iomap.type) { 65 : case IOMAP_HOLE: 66 : return length; 67 47011 : case IOMAP_UNWRITTEN: 68 94022 : *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping, 69 47011 : iter->pos, iter->pos + length, SEEK_DATA); 70 47011 : if (*hole_pos < 0) 71 41010 : return length; 72 : return 0; 73 163597 : default: 74 163597 : *hole_pos = iter->pos; 75 163597 : return 0; 76 : } 77 : } 78 : 79 : loff_t 80 218517 : iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops) 81 : { 82 218517 : loff_t size = i_size_read(inode); 83 218517 : struct iomap_iter iter = { 84 : .inode = inode, 85 : .pos = pos, 86 : .flags = IOMAP_REPORT, 87 : }; 88 218517 : int ret; 89 : 90 : /* Nothing to be found before or beyond the end of the file. */ 91 218517 : if (pos < 0 || pos >= size) 92 : return -ENXIO; 93 : 94 181629 : iter.len = size - pos; 95 595174 : while ((ret = iomap_iter(&iter, ops)) > 0) 96 413545 : iter.processed = iomap_seek_data_iter(&iter, &pos); 97 181629 : if (ret < 0) 98 0 : return ret; 99 181629 : if (iter.len) /* found data before EOF */ 100 169598 : 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);