1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2010 Red Hat, Inc. 4 * Copyright (c) 2016-2021 Christoph Hellwig. 5 */ 6 #include <linux/iomap.h> 7 #include "trace.h" 8 9 static inline void iomap_iter_reset_iomap(struct iomap_iter *iter) 10 { 11 if (iter->fbatch) { 12 folio_batch_release(iter->fbatch); 13 kfree(iter->fbatch); 14 iter->fbatch = NULL; 15 } 16 17 iter->status = 0; 18 memset(&iter->iomap, 0, sizeof(iter->iomap)); 19 memset(&iter->srcmap, 0, sizeof(iter->srcmap)); 20 } 21 22 /* Advance the current iterator position and decrement the remaining length */ 23 int iomap_iter_advance(struct iomap_iter *iter, u64 count) 24 { 25 if (WARN_ON_ONCE(count > iomap_length(iter))) 26 return -EIO; 27 iter->pos += count; 28 iter->len -= count; 29 return 0; 30 } 31 32 static inline void iomap_iter_done(struct iomap_iter *iter) 33 { 34 WARN_ON_ONCE(iter->iomap.offset > iter->pos); 35 WARN_ON_ONCE(iter->iomap.length == 0); 36 WARN_ON_ONCE(iter->iomap.offset + iter->iomap.length <= iter->pos); 37 WARN_ON_ONCE(iter->iomap.flags & IOMAP_F_STALE); 38 39 iter->iter_start_pos = iter->pos; 40 41 trace_iomap_iter_dstmap(iter->inode, &iter->iomap); 42 if (iter->srcmap.type != IOMAP_HOLE) 43 trace_iomap_iter_srcmap(iter->inode, &iter->srcmap); 44 } 45 46 /** 47 * iomap_iter - iterate over a ranges in a file 48 * @iter: iteration structue 49 * @ops: iomap ops provided by the file system 50 * 51 * Iterate over filesystem-provided space mappings for the provided file range. 52 * 53 * This function handles cleanup of resources acquired for iteration when the 54 * filesystem indicates there are no more space mappings, which means that this 55 * function must be called in a loop that continues as long it returns a 56 * positive value. If 0 or a negative value is returned, the caller must not 57 * return to the loop body. Within a loop body, there are two ways to break out 58 * of the loop body: leave @iter.status unchanged, or set it to a negative 59 * errno. 60 */ 61 int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) 62 { 63 bool stale = iter->iomap.flags & IOMAP_F_STALE; 64 ssize_t advanced; 65 u64 olen; 66 int ret; 67 68 trace_iomap_iter(iter, ops, _RET_IP_); 69 70 if (!iter->iomap.length) 71 goto begin; 72 73 /* 74 * Calculate how far the iter was advanced and the original length bytes 75 * for ->iomap_end(). 76 */ 77 advanced = iter->pos - iter->iter_start_pos; 78 olen = iter->len + advanced; 79 80 if (ops->iomap_end) { 81 ret = ops->iomap_end(iter->inode, iter->iter_start_pos, 82 iomap_length_trim(iter, iter->iter_start_pos, 83 olen), 84 advanced, iter->flags, &iter->iomap); 85 if (ret < 0 && !advanced) 86 return ret; 87 } 88 89 /* detect old return semantics where this would advance */ 90 if (WARN_ON_ONCE(iter->status > 0)) 91 iter->status = -EIO; 92 93 /* 94 * Use iter->len to determine whether to continue onto the next mapping. 95 * Explicitly terminate on error status or if the current iter has not 96 * advanced at all (i.e. no work was done for some reason) unless the 97 * mapping has been marked stale and needs to be reprocessed. 98 */ 99 if (iter->status < 0) 100 ret = iter->status; 101 else if (iter->len == 0 || (!advanced && !stale)) 102 ret = 0; 103 else 104 ret = 1; 105 iomap_iter_reset_iomap(iter); 106 if (ret <= 0) 107 return ret; 108 109 begin: 110 ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, 111 &iter->iomap, &iter->srcmap); 112 if (ret < 0) 113 return ret; 114 iomap_iter_done(iter); 115 return 1; 116 } 117