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