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 489417732 : static inline int iomap_iter_advance(struct iomap_iter *iter) 23 : { 24 489417732 : bool stale = iter->iomap.flags & IOMAP_F_STALE; 25 : 26 : /* handle the previous iteration (if any) */ 27 489417732 : if (iter->iomap.length) { 28 262251495 : if (iter->processed < 0) 29 1245 : return iter->processed; 30 262250250 : if (!iter->processed && !stale) 31 : return 0; 32 262071533 : if (WARN_ON_ONCE(iter->processed > iomap_length(iter))) 33 : return -EIO; 34 262071533 : iter->pos += iter->processed; 35 262071533 : iter->len -= iter->processed; 36 262071533 : if (!iter->len) 37 : return 0; 38 : } 39 : 40 : /* clear the state for the next iteration */ 41 263943888 : iter->processed = 0; 42 263943888 : memset(&iter->iomap, 0, sizeof(iter->iomap)); 43 263943888 : memset(&iter->srcmap, 0, sizeof(iter->srcmap)); 44 263943888 : return 1; 45 : } 46 : 47 262248380 : static inline void iomap_iter_done(struct iomap_iter *iter) 48 : { 49 262248380 : WARN_ON_ONCE(iter->iomap.offset > iter->pos); 50 262248380 : WARN_ON_ONCE(iter->iomap.length == 0); 51 262248380 : WARN_ON_ONCE(iter->iomap.offset + iter->iomap.length <= iter->pos); 52 262248380 : WARN_ON_ONCE(iter->iomap.flags & IOMAP_F_STALE); 53 : 54 262248380 : trace_iomap_iter_dstmap(iter->inode, &iter->iomap); 55 262259943 : if (iter->srcmap.type != IOMAP_HOLE) 56 2431192 : trace_iomap_iter_srcmap(iter->inode, &iter->srcmap); 57 262259945 : } 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 489440732 : int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) 75 : { 76 489440732 : int ret; 77 : 78 489440732 : if (iter->iomap.length && ops->iomap_end) { 79 97752295 : ret = ops->iomap_end(iter->inode, iter->pos, iomap_length(iter), 80 97752295 : iter->processed > 0 ? iter->processed : 0, 81 : iter->flags, &iter->iomap); 82 97743516 : if (ret < 0 && !iter->processed) 83 : return ret; 84 : } 85 : 86 489431953 : trace_iomap_iter(iter, ops, _RET_IP_); 87 489239274 : ret = iomap_iter_advance(iter); 88 489442619 : if (ret <= 0) 89 : return ret; 90 : 91 263960042 : ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, 92 : &iter->iomap, &iter->srcmap); 93 263985031 : if (ret < 0) 94 : return ret; 95 262238457 : iomap_iter_done(iter); 96 262238457 : return 1; 97 : }