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