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