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