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 void iomap_iter_reset_iomap(struct iomap_iter *iter) |
11 | { |
12 | iter->status = 0; |
13 | memset(&iter->iomap, 0, sizeof(iter->iomap)); |
14 | memset(&iter->srcmap, 0, sizeof(iter->srcmap)); |
15 | } |
16 | |
17 | /* |
18 | * Advance the current iterator position and output the length remaining for the |
19 | * current mapping. |
20 | */ |
21 | int iomap_iter_advance(struct iomap_iter *iter, u64 *count) |
22 | { |
23 | if (WARN_ON_ONCE(*count > iomap_length(iter))) |
24 | return -EIO; |
25 | iter->pos += *count; |
26 | iter->len -= *count; |
27 | *count = iomap_length(iter); |
28 | return 0; |
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 | WARN_ON_ONCE(iter->iomap.flags & IOMAP_F_STALE); |
37 | |
38 | iter->iter_start_pos = iter->pos; |
39 | |
40 | trace_iomap_iter_dstmap(inode: iter->inode, iomap: &iter->iomap); |
41 | if (iter->srcmap.type != IOMAP_HOLE) |
42 | trace_iomap_iter_srcmap(inode: iter->inode, iomap: &iter->srcmap); |
43 | } |
44 | |
45 | /** |
46 | * iomap_iter - iterate over a ranges in a file |
47 | * @iter: iteration structue |
48 | * @ops: iomap ops provided by the file system |
49 | * |
50 | * Iterate over filesystem-provided space mappings for the provided file range. |
51 | * |
52 | * This function handles cleanup of resources acquired for iteration when the |
53 | * filesystem indicates there are no more space mappings, which means that this |
54 | * function must be called in a loop that continues as long it returns a |
55 | * positive value. If 0 or a negative value is returned, the caller must not |
56 | * return to the loop body. Within a loop body, there are two ways to break out |
57 | * of the loop body: leave @iter.status unchanged, or set it to a negative |
58 | * errno. |
59 | */ |
60 | int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops) |
61 | { |
62 | bool stale = iter->iomap.flags & IOMAP_F_STALE; |
63 | ssize_t advanced; |
64 | u64 olen; |
65 | int ret; |
66 | |
67 | trace_iomap_iter(iter, ops, _RET_IP_); |
68 | |
69 | if (!iter->iomap.length) |
70 | goto begin; |
71 | |
72 | /* |
73 | * Calculate how far the iter was advanced and the original length bytes |
74 | * for ->iomap_end(). |
75 | */ |
76 | advanced = iter->pos - iter->iter_start_pos; |
77 | olen = iter->len + advanced; |
78 | |
79 | if (ops->iomap_end) { |
80 | ret = ops->iomap_end(iter->inode, iter->iter_start_pos, |
81 | iomap_length_trim(iter, pos: iter->iter_start_pos, |
82 | len: olen), |
83 | advanced, iter->flags, &iter->iomap); |
84 | if (ret < 0 && !advanced) |
85 | return ret; |
86 | } |
87 | |
88 | /* detect old return semantics where this would advance */ |
89 | if (WARN_ON_ONCE(iter->status > 0)) |
90 | iter->status = -EIO; |
91 | |
92 | /* |
93 | * Use iter->len to determine whether to continue onto the next mapping. |
94 | * Explicitly terminate on error status or if the current iter has not |
95 | * advanced at all (i.e. no work was done for some reason) unless the |
96 | * mapping has been marked stale and needs to be reprocessed. |
97 | */ |
98 | if (iter->status < 0) |
99 | ret = iter->status; |
100 | else if (iter->len == 0 || (!advanced && !stale)) |
101 | ret = 0; |
102 | else |
103 | ret = 1; |
104 | iomap_iter_reset_iomap(iter); |
105 | if (ret <= 0) |
106 | return ret; |
107 | |
108 | begin: |
109 | ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags, |
110 | &iter->iomap, &iter->srcmap); |
111 | if (ret < 0) |
112 | return ret; |
113 | iomap_iter_done(iter); |
114 | return 1; |
115 | } |
116 | |