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 int iomap_iter_advance(struct iomap_iter *iter) 11 { 12 /* handle the previous iteration (if any) */ 13 if (iter->iomap.length) { 14 if (iter->processed <= 0) 15 return iter->processed; 16 if (WARN_ON_ONCE(iter->processed > iomap_length(iter))) 17 return -EIO; 18 iter->pos += iter->processed; 19 iter->len -= iter->processed; 20 if (!iter->len) 21 return 0; 22 } 23 24 /* clear the state for the next iteration */ 25 iter->processed = 0; 26 memset(&iter->iomap, 0, sizeof(iter->iomap)); 27 memset(&iter->srcmap, 0, sizeof(iter->srcmap)); 28 return 1; 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 37 trace_iomap_iter_dstmap(iter->inode, &iter->iomap); 38 if (iter->srcmap.type != IOMAP_HOLE) 39 trace_iomap_iter_srcmap(iter->inode, &iter->srcmap); 40 } 41 42 /** 43 * iomap_iter - iterate over a ranges in a file 44 * @iter: iteration structue 45 * @ops: iomap ops provided by the file system 46 * 47 * Iterate over filesystem-provided space mappings for the provided file range. 48 * 49 * This function handles cleanup of resources acquired for iteration when the 50 * filesystem indicates there are no more space mappings, which means that this 51 * function must be called in a loop that continues as long it returns a 52 * positive value. If 0 or a negative value is returned, the caller must not 53 * return to the loop body. Within a loop body, there are two ways to break out 54 * of the loop body: leave @iter.processed unchanged, or set it to a negative 55 * errno. 56 */ 57 int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) 58 { 59 int ret; 60 61 if (iter->iomap.length && ops->iomap_end) { 62 ret = ops->iomap_end(iter->inode, iter->pos, iomap_length(iter), 63 iter->processed > 0 ? iter->processed : 0, 64 iter->flags, &iter->iomap); 65 if (ret < 0 && !iter->processed) 66 return ret; 67 } 68 69 trace_iomap_iter(iter, ops, _RET_IP_); 70 ret = iomap_iter_advance(iter); 71 if (ret <= 0) 72 return ret; 73 74 ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, 75 &iter->iomap, &iter->srcmap); 76 if (ret < 0) 77 return ret; 78 iomap_iter_done(iter); 79 return 1; 80 } 81