Skip to content

Commit f4b896c

Browse files
Christoph HellwigDarrick J. Wong
authored andcommitted
iomap: add the new iomap_iter model
The iomap_iter struct provides a convenient way to package up and maintain all the arguments to the various mapping and operation functions. It is operated on using the iomap_iter() function that is called in loop until the whole range has been processed. Compared to the existing iomap_apply() function this avoid an indirect call for each iteration. For now iomap_iter() calls back into the existing ->iomap_begin and ->iomap_end methods, but in the future this could be further optimized to avoid indirect calls entirely. Based on an earlier patch from Matthew Wilcox <willy@infradead.org>. Signed-off-by: Christoph Hellwig <hch@lst.de> [djwong: add to apply.c to preserve git history of iomap loop control] Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 740499c commit f4b896c

3 files changed

Lines changed: 165 additions & 2 deletions

File tree

fs/iomap/apply.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/*
33
* Copyright (C) 2010 Red Hat, Inc.
4-
* Copyright (c) 2016-2018 Christoph Hellwig.
4+
* Copyright (c) 2016-2021 Christoph Hellwig.
55
*/
66
#include <linux/module.h>
77
#include <linux/compiler.h>
@@ -97,3 +97,75 @@ iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags,
9797

9898
return written ? written : ret;
9999
}
100+
101+
static inline int iomap_iter_advance(struct iomap_iter *iter)
102+
{
103+
/* handle the previous iteration (if any) */
104+
if (iter->iomap.length) {
105+
if (iter->processed <= 0)
106+
return iter->processed;
107+
if (WARN_ON_ONCE(iter->processed > iomap_length(iter)))
108+
return -EIO;
109+
iter->pos += iter->processed;
110+
iter->len -= iter->processed;
111+
if (!iter->len)
112+
return 0;
113+
}
114+
115+
/* clear the state for the next iteration */
116+
iter->processed = 0;
117+
memset(&iter->iomap, 0, sizeof(iter->iomap));
118+
memset(&iter->srcmap, 0, sizeof(iter->srcmap));
119+
return 1;
120+
}
121+
122+
static inline void iomap_iter_done(struct iomap_iter *iter)
123+
{
124+
WARN_ON_ONCE(iter->iomap.offset > iter->pos);
125+
WARN_ON_ONCE(iter->iomap.length == 0);
126+
WARN_ON_ONCE(iter->iomap.offset + iter->iomap.length <= iter->pos);
127+
128+
trace_iomap_iter_dstmap(iter->inode, &iter->iomap);
129+
if (iter->srcmap.type != IOMAP_HOLE)
130+
trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
131+
}
132+
133+
/**
134+
* iomap_iter - iterate over a ranges in a file
135+
* @iter: iteration structue
136+
* @ops: iomap ops provided by the file system
137+
*
138+
* Iterate over filesystem-provided space mappings for the provided file range.
139+
*
140+
* This function handles cleanup of resources acquired for iteration when the
141+
* filesystem indicates there are no more space mappings, which means that this
142+
* function must be called in a loop that continues as long it returns a
143+
* positive value. If 0 or a negative value is returned, the caller must not
144+
* return to the loop body. Within a loop body, there are two ways to break out
145+
* of the loop body: leave @iter.processed unchanged, or set it to a negative
146+
* errno.
147+
*/
148+
int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
149+
{
150+
int ret;
151+
152+
if (iter->iomap.length && ops->iomap_end) {
153+
ret = ops->iomap_end(iter->inode, iter->pos, iomap_length(iter),
154+
iter->processed > 0 ? iter->processed : 0,
155+
iter->flags, &iter->iomap);
156+
if (ret < 0 && !iter->processed)
157+
return ret;
158+
}
159+
160+
trace_iomap_iter(iter, ops, _RET_IP_);
161+
ret = iomap_iter_advance(iter);
162+
if (ret <= 0)
163+
return ret;
164+
165+
ret = ops->iomap_begin(iter->inode, iter->pos, iter->len, iter->flags,
166+
&iter->iomap, &iter->srcmap);
167+
if (ret < 0)
168+
return ret;
169+
iomap_iter_done(iter);
170+
return 1;
171+
}

fs/iomap/trace.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
/*
3-
* Copyright (c) 2009-2019 Christoph Hellwig
3+
* Copyright (c) 2009-2021 Christoph Hellwig
44
*
55
* NOTE: none of these tracepoints shall be considered a stable kernel ABI
66
* as they can change at any time.
@@ -140,6 +140,8 @@ DEFINE_EVENT(iomap_class, name, \
140140
TP_ARGS(inode, iomap))
141141
DEFINE_IOMAP_EVENT(iomap_apply_dstmap);
142142
DEFINE_IOMAP_EVENT(iomap_apply_srcmap);
143+
DEFINE_IOMAP_EVENT(iomap_iter_dstmap);
144+
DEFINE_IOMAP_EVENT(iomap_iter_srcmap);
143145

144146
TRACE_EVENT(iomap_apply,
145147
TP_PROTO(struct inode *inode, loff_t pos, loff_t length,
@@ -179,6 +181,39 @@ TRACE_EVENT(iomap_apply,
179181
__entry->actor)
180182
);
181183

184+
TRACE_EVENT(iomap_iter,
185+
TP_PROTO(struct iomap_iter *iter, const void *ops,
186+
unsigned long caller),
187+
TP_ARGS(iter, ops, caller),
188+
TP_STRUCT__entry(
189+
__field(dev_t, dev)
190+
__field(u64, ino)
191+
__field(loff_t, pos)
192+
__field(loff_t, length)
193+
__field(unsigned int, flags)
194+
__field(const void *, ops)
195+
__field(unsigned long, caller)
196+
),
197+
TP_fast_assign(
198+
__entry->dev = iter->inode->i_sb->s_dev;
199+
__entry->ino = iter->inode->i_ino;
200+
__entry->pos = iter->pos;
201+
__entry->length = iomap_length(iter);
202+
__entry->flags = iter->flags;
203+
__entry->ops = ops;
204+
__entry->caller = caller;
205+
),
206+
TP_printk("dev %d:%d ino 0x%llx pos %lld length %lld flags %s (0x%x) ops %ps caller %pS",
207+
MAJOR(__entry->dev), MINOR(__entry->dev),
208+
__entry->ino,
209+
__entry->pos,
210+
__entry->length,
211+
__print_flags(__entry->flags, "|", IOMAP_FLAGS_STRINGS),
212+
__entry->flags,
213+
__entry->ops,
214+
(void *)__entry->caller)
215+
);
216+
182217
#endif /* _IOMAP_TRACE_H */
183218

184219
#undef TRACE_INCLUDE_PATH

include/linux/iomap.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,62 @@ struct iomap_ops {
161161
ssize_t written, unsigned flags, struct iomap *iomap);
162162
};
163163

164+
/**
165+
* struct iomap_iter - Iterate through a range of a file
166+
* @inode: Set at the start of the iteration and should not change.
167+
* @pos: The current file position we are operating on. It is updated by
168+
* calls to iomap_iter(). Treat as read-only in the body.
169+
* @len: The remaining length of the file segment we're operating on.
170+
* It is updated at the same time as @pos.
171+
* @processed: The number of bytes processed by the body in the most recent
172+
* iteration, or a negative errno. 0 causes the iteration to stop.
173+
* @flags: Zero or more of the iomap_begin flags above.
174+
* @iomap: Map describing the I/O iteration
175+
* @srcmap: Source map for COW operations
176+
*/
177+
struct iomap_iter {
178+
struct inode *inode;
179+
loff_t pos;
180+
u64 len;
181+
s64 processed;
182+
unsigned flags;
183+
struct iomap iomap;
184+
struct iomap srcmap;
185+
};
186+
187+
int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops);
188+
189+
/**
190+
* iomap_length - length of the current iomap iteration
191+
* @iter: iteration structure
192+
*
193+
* Returns the length that the operation applies to for the current iteration.
194+
*/
195+
static inline u64 iomap_length(const struct iomap_iter *iter)
196+
{
197+
u64 end = iter->iomap.offset + iter->iomap.length;
198+
199+
if (iter->srcmap.type != IOMAP_HOLE)
200+
end = min(end, iter->srcmap.offset + iter->srcmap.length);
201+
return min(iter->len, end - iter->pos);
202+
}
203+
204+
/**
205+
* iomap_iter_srcmap - return the source map for the current iomap iteration
206+
* @i: iteration structure
207+
*
208+
* Write operations on file systems with reflink support might require a
209+
* source and a destination map. This function retourns the source map
210+
* for a given operation, which may or may no be identical to the destination
211+
* map in &i->iomap.
212+
*/
213+
static inline struct iomap *iomap_iter_srcmap(struct iomap_iter *i)
214+
{
215+
if (i->srcmap.type != IOMAP_HOLE)
216+
return &i->srcmap;
217+
return &i->iomap;
218+
}
219+
164220
/*
165221
* Main iomap iterator function.
166222
*/

0 commit comments

Comments
 (0)