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