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 ret; 39 40 /* Nothing to be found before or beyond the end of the file. */ 41 if (offset < 0 || offset >= size) 42 return -ENXIO; 43 44 while (offset < size) { 45 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT, 46 ops, &offset, iomap_seek_hole_actor); 47 if (ret < 0) 48 return ret; 49 if (ret == 0) 50 break; 51 offset += ret; 52 } 53 54 return offset; 55 } 56 EXPORT_SYMBOL_GPL(iomap_seek_hole); 57 58 static loff_t 59 iomap_seek_data_actor(struct inode *inode, loff_t start, loff_t length, 60 void *data, struct iomap *iomap, struct iomap *srcmap) 61 { 62 loff_t offset = start; 63 64 switch (iomap->type) { 65 case IOMAP_HOLE: 66 return length; 67 case IOMAP_UNWRITTEN: 68 offset = mapping_seek_hole_data(inode->i_mapping, start, 69 start + length, SEEK_DATA); 70 if (offset < 0) 71 return length; 72 fallthrough; 73 default: 74 *(loff_t *)data = offset; 75 return 0; 76 } 77 } 78 79 loff_t 80 iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops) 81 { 82 loff_t size = i_size_read(inode); 83 loff_t ret; 84 85 /* Nothing to be found before or beyond the end of the file. */ 86 if (offset < 0 || offset >= size) 87 return -ENXIO; 88 89 while (offset < size) { 90 ret = iomap_apply(inode, offset, size - offset, IOMAP_REPORT, 91 ops, &offset, iomap_seek_data_actor); 92 if (ret < 0) 93 return ret; 94 if (ret == 0) 95 return offset; 96 offset += ret; 97 } 98 99 /* We've reached the end of the file without finding data */ 100 return -ENXIO; 101 } 102 EXPORT_SYMBOL_GPL(iomap_seek_data); 103