Christoph Hellwig | 73ce6ab | 2019-04-28 08:34:02 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Christoph Hellwig | ae259a9 | 2016-06-21 09:23:11 +1000 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) 2010 Red Hat, Inc. |
Christoph Hellwig | f4b896c | 2021-08-10 18:33:07 -0700 | [diff] [blame] | 4 | * Copyright (c) 2016-2021 Christoph Hellwig. |
Christoph Hellwig | ae259a9 | 2016-06-21 09:23:11 +1000 | [diff] [blame] | 5 | */ |
Christoph Hellwig | ae259a9 | 2016-06-21 09:23:11 +1000 | [diff] [blame] | 6 | #include <linux/fs.h> |
| 7 | #include <linux/iomap.h> |
Darrick J. Wong | 6334b91 | 2019-11-21 16:14:49 -0800 | [diff] [blame] | 8 | #include "trace.h" |
Ingo Molnar | f361bf4 | 2017-02-03 23:47:37 +0100 | [diff] [blame] | 9 | |
Christoph Hellwig | f4b896c | 2021-08-10 18:33:07 -0700 | [diff] [blame] | 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 | } |