1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * Copyright (C) 2010 Red Hat, Inc. 3 * Copyright (C) 2010 Red Hat, Inc. 4 * Copyright (c) 2016-2021 Christoph Hellwig. 4 * Copyright (c) 2016-2021 Christoph Hellwig. 5 */ 5 */ 6 #include <linux/fs.h> 6 #include <linux/fs.h> 7 #include <linux/iomap.h> 7 #include <linux/iomap.h> 8 #include "trace.h" 8 #include "trace.h" 9 9 10 /* 10 /* 11 * Advance to the next range we need to map. 11 * Advance to the next range we need to map. 12 * 12 * 13 * If the iomap is marked IOMAP_F_STALE, it me 13 * If the iomap is marked IOMAP_F_STALE, it means the existing map was not fully 14 * processed - it was aborted because the exte 14 * processed - it was aborted because the extent the iomap spanned may have been 15 * changed during the operation. In this case, 15 * changed during the operation. In this case, the iteration behaviour is to 16 * remap the unprocessed range of the iter, an 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 17 * even when we've made no progress (i.e. iter->processed = 0). Hence the 18 * "finished iterating" case needs to distingu 18 * "finished iterating" case needs to distinguish between 19 * (processed = 0) meaning we are done and (pr 19 * (processed = 0) meaning we are done and (processed = 0 && stale) meaning we 20 * need to remap the entire remaining range. 20 * need to remap the entire remaining range. 21 */ 21 */ 22 static inline int iomap_iter_advance(struct io 22 static inline int iomap_iter_advance(struct iomap_iter *iter) 23 { 23 { 24 bool stale = iter->iomap.flags & IOMAP 24 bool stale = iter->iomap.flags & IOMAP_F_STALE; 25 25 26 /* handle the previous iteration (if a 26 /* handle the previous iteration (if any) */ 27 if (iter->iomap.length) { 27 if (iter->iomap.length) { 28 if (iter->processed < 0) 28 if (iter->processed < 0) 29 return iter->processed 29 return iter->processed; 30 if (!iter->processed && !stale 30 if (!iter->processed && !stale) 31 return 0; 31 return 0; 32 if (WARN_ON_ONCE(iter->process 32 if (WARN_ON_ONCE(iter->processed > iomap_length(iter))) 33 return -EIO; 33 return -EIO; 34 iter->pos += iter->processed; 34 iter->pos += iter->processed; 35 iter->len -= iter->processed; 35 iter->len -= iter->processed; 36 if (!iter->len) 36 if (!iter->len) 37 return 0; 37 return 0; 38 } 38 } 39 39 40 /* clear the state for the next iterat 40 /* clear the state for the next iteration */ 41 iter->processed = 0; 41 iter->processed = 0; 42 memset(&iter->iomap, 0, sizeof(iter->i 42 memset(&iter->iomap, 0, sizeof(iter->iomap)); 43 memset(&iter->srcmap, 0, sizeof(iter-> 43 memset(&iter->srcmap, 0, sizeof(iter->srcmap)); 44 return 1; 44 return 1; 45 } 45 } 46 46 47 static inline void iomap_iter_done(struct ioma 47 static inline void iomap_iter_done(struct iomap_iter *iter) 48 { 48 { 49 WARN_ON_ONCE(iter->iomap.offset > iter 49 WARN_ON_ONCE(iter->iomap.offset > iter->pos); 50 WARN_ON_ONCE(iter->iomap.length == 0); 50 WARN_ON_ONCE(iter->iomap.length == 0); 51 WARN_ON_ONCE(iter->iomap.offset + iter 51 WARN_ON_ONCE(iter->iomap.offset + iter->iomap.length <= iter->pos); 52 WARN_ON_ONCE(iter->iomap.flags & IOMAP 52 WARN_ON_ONCE(iter->iomap.flags & IOMAP_F_STALE); 53 53 54 trace_iomap_iter_dstmap(iter->inode, & 54 trace_iomap_iter_dstmap(iter->inode, &iter->iomap); 55 if (iter->srcmap.type != IOMAP_HOLE) 55 if (iter->srcmap.type != IOMAP_HOLE) 56 trace_iomap_iter_srcmap(iter-> 56 trace_iomap_iter_srcmap(iter->inode, &iter->srcmap); 57 } 57 } 58 58 59 /** 59 /** 60 * iomap_iter - iterate over a ranges in a fil 60 * iomap_iter - iterate over a ranges in a file 61 * @iter: iteration structue 61 * @iter: iteration structue 62 * @ops: iomap ops provided by the file system 62 * @ops: iomap ops provided by the file system 63 * 63 * 64 * Iterate over filesystem-provided space mapp 64 * Iterate over filesystem-provided space mappings for the provided file range. 65 * 65 * 66 * This function handles cleanup of resources 66 * This function handles cleanup of resources acquired for iteration when the 67 * filesystem indicates there are no more spac 67 * filesystem indicates there are no more space mappings, which means that this 68 * function must be called in a loop that cont 68 * function must be called in a loop that continues as long it returns a 69 * positive value. If 0 or a negative value i 69 * positive value. If 0 or a negative value is returned, the caller must not 70 * return to the loop body. Within a loop bod 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 un 71 * of the loop body: leave @iter.processed unchanged, or set it to a negative 72 * errno. 72 * errno. 73 */ 73 */ 74 int iomap_iter(struct iomap_iter *iter, const 74 int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) 75 { 75 { 76 int ret; 76 int ret; 77 77 78 if (iter->iomap.length && ops->iomap_e 78 if (iter->iomap.length && ops->iomap_end) { 79 ret = ops->iomap_end(iter->ino 79 ret = ops->iomap_end(iter->inode, iter->pos, iomap_length(iter), 80 iter->processe 80 iter->processed > 0 ? iter->processed : 0, 81 iter->flags, & 81 iter->flags, &iter->iomap); 82 if (ret < 0 && !iter->processe 82 if (ret < 0 && !iter->processed) 83 return ret; 83 return ret; 84 } 84 } 85 85 86 trace_iomap_iter(iter, ops, _RET_IP_); 86 trace_iomap_iter(iter, ops, _RET_IP_); 87 ret = iomap_iter_advance(iter); 87 ret = iomap_iter_advance(iter); 88 if (ret <= 0) 88 if (ret <= 0) 89 return ret; 89 return ret; 90 90 91 ret = ops->iomap_begin(iter->inode, it 91 ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, 92 &iter->iomap, & 92 &iter->iomap, &iter->srcmap); 93 if (ret < 0) 93 if (ret < 0) 94 return ret; 94 return ret; 95 iomap_iter_done(iter); 95 iomap_iter_done(iter); 96 return 1; 96 return 1; 97 } 97 } 98 98
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.