Line data Source code
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 : /* 11 : * Advance to the next range we need to map. 12 : * 13 : * If the iomap is marked IOMAP_F_STALE, it means the existing map was not fully 14 : * processed - it was aborted because the extent the iomap spanned may have been 15 : * changed during the operation. In this case, the iteration behaviour is to 16 : * remap the unprocessed range of the iter, and that means we may need to remap 17 : * even when we've made no progress (i.e. iter->processed = 0). Hence the 18 : * "finished iterating" case needs to distinguish between 19 : * (processed = 0) meaning we are done and (processed = 0 && stale) meaning we 20 : * need to remap the entire remaining range. 21 : */ 22 924810260 : static inline int iomap_iter_advance(struct iomap_iter *iter) 23 : { 24 924810260 : bool stale = iter->iomap.flags & IOMAP_F_STALE; 25 : 26 : /* handle the previous iteration (if any) */ 27 924810260 : if (iter->iomap.length) { 28 510375373 : if (iter->processed < 0) 29 1368 : return iter->processed; 30 510374005 : if (!iter->processed && !stale) 31 : return 0; 32 510186925 : if (WARN_ON_ONCE(iter->processed > iomap_length(iter))) 33 : return -EIO; 34 510186925 : iter->pos += iter->processed; 35 510186925 : iter->len -= iter->processed; 36 510186925 : if (!iter->len) 37 : return 0; 38 : } 39 : 40 : /* clear the state for the next iteration */ 41 511960076 : iter->processed = 0; 42 511960076 : memset(&iter->iomap, 0, sizeof(iter->iomap)); 43 511960076 : memset(&iter->srcmap, 0, sizeof(iter->srcmap)); 44 511960076 : return 1; 45 : } 46 : 47 510380359 : static inline void iomap_iter_done(struct iomap_iter *iter) 48 : { 49 510380359 : WARN_ON_ONCE(iter->iomap.offset > iter->pos); 50 510380359 : WARN_ON_ONCE(iter->iomap.length == 0); 51 510380359 : WARN_ON_ONCE(iter->iomap.offset + iter->iomap.length <= iter->pos); 52 510380359 : WARN_ON_ONCE(iter->iomap.flags & IOMAP_F_STALE); 53 : 54 510380359 : trace_iomap_iter_dstmap(iter->inode, &iter->iomap); 55 510379149 : if (iter->srcmap.type != IOMAP_HOLE) 56 2988108 : trace_iomap_iter_srcmap(iter->inode, &iter->srcmap); 57 510379125 : } 58 : 59 : /** 60 : * iomap_iter - iterate over a ranges in a file 61 : * @iter: iteration structue 62 : * @ops: iomap ops provided by the file system 63 : * 64 : * Iterate over filesystem-provided space mappings for the provided file range. 65 : * 66 : * This function handles cleanup of resources acquired for iteration when the 67 : * filesystem indicates there are no more space mappings, which means that this 68 : * function must be called in a loop that continues as long it returns a 69 : * positive value. If 0 or a negative value is returned, the caller must not 70 : * return to the loop body. Within a loop body, there are two ways to break out 71 : * of the loop body: leave @iter.processed unchanged, or set it to a negative 72 : * errno. 73 : */ 74 924829966 : int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) 75 : { 76 924829966 : int ret; 77 : 78 924829966 : if (iter->iomap.length && ops->iomap_end) { 79 117177728 : ret = ops->iomap_end(iter->inode, iter->pos, iomap_length(iter), 80 117177728 : iter->processed > 0 ? iter->processed : 0, 81 : iter->flags, &iter->iomap); 82 117169102 : if (ret < 0 && !iter->processed) 83 : return ret; 84 : } 85 : 86 924821340 : trace_iomap_iter(iter, ops, _RET_IP_); 87 924530382 : ret = iomap_iter_advance(iter); 88 924840395 : if (ret <= 0) 89 : return ret; 90 : 91 511990833 : ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, 92 : &iter->iomap, &iter->srcmap); 93 512077542 : if (ret < 0) 94 : return ret; 95 510364049 : iomap_iter_done(iter); 96 510364049 : return 1; 97 : }