diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 0708be776740..c479ec73dedd 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -1352,18 +1352,14 @@ static inline int iomap_zero_iter_flush_and_stale(struct iomap_iter *i)
 
 static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero)
 {
-	loff_t pos = iter->pos;
-	loff_t length = iomap_length(iter);
-	loff_t written = 0;
-
 	do {
 		struct folio *folio;
 		int status;
 		size_t offset;
-		size_t bytes = min_t(u64, SIZE_MAX, length);
+		size_t bytes = min_t(u64, SIZE_MAX, iter->iter_len);
 		bool ret;
 
-		status = iomap_write_begin(iter, pos, bytes, &folio);
+		status = iomap_write_begin(iter, iter->pos, bytes, &folio);
 		if (status)
 			return status;
 		if (iter->iomap.flags & IOMAP_F_STALE)
@@ -1371,26 +1367,24 @@ static loff_t iomap_zero_iter(struct iomap_iter *iter, bool *did_zero)
 
 		/* warn about zeroing folios beyond eof that won't write back */
 		WARN_ON_ONCE(folio_pos(folio) > iter->inode->i_size);
-		offset = offset_in_folio(folio, pos);
+		offset = offset_in_folio(folio, iter->pos);
 		if (bytes > folio_size(folio) - offset)
 			bytes = folio_size(folio) - offset;
 
 		folio_zero_range(folio, offset, bytes);
 		folio_mark_accessed(folio);
 
-		ret = iomap_write_end(iter, pos, bytes, bytes, folio);
-		__iomap_put_folio(iter, pos, bytes, folio);
+		ret = iomap_write_end(iter, iter->pos, bytes, bytes, folio);
+		__iomap_put_folio(iter, iter->pos, bytes, folio);
 		if (WARN_ON_ONCE(!ret))
 			return -EIO;
 
-		pos += bytes;
-		length -= bytes;
-		written += bytes;
-	} while (length > 0);
+		iomap_iter_advance(iter, bytes);
+	} while (iter->iter_len > 0);
 
 	if (did_zero)
 		*did_zero = true;
-	return written;
+	return 0;
 }
 
 int
diff --git a/fs/iomap/iter.c b/fs/iomap/iter.c
index 3790918646af..962f4b35d856 100644
--- a/fs/iomap/iter.c
+++ b/fs/iomap/iter.c
@@ -7,6 +7,14 @@
 #include <linux/iomap.h>
 #include "trace.h"
 
+/* clear out iomaps from the fs */
+static inline void iomap_iter_reset_iomap(struct iomap_iter *iter)
+{
+	iter->processed = iter->iter_len = 0;
+	memset(&iter->iomap, 0, sizeof(iter->iomap));
+	memset(&iter->srcmap, 0, sizeof(iter->srcmap));
+}
+
 /*
  * Advance to the next range we need to map.
  *
@@ -19,30 +27,40 @@
  * (processed = 0) meaning we are done and (processed = 0 && stale) meaning we
  * need to remap the entire remaining range.
  */
-static inline int iomap_iter_advance(struct iomap_iter *iter)
+int iomap_iter_advance(struct iomap_iter *iter, s64 count)
 {
 	bool stale = iter->iomap.flags & IOMAP_F_STALE;
 	int ret = 1;
 
 	/* handle the previous iteration (if any) */
 	if (iter->iomap.length) {
-		if (iter->processed < 0)
-			return iter->processed;
-		if (WARN_ON_ONCE(iter->processed > iomap_length(iter)))
+		if (count < 0)
+			return count;
+		if (WARN_ON_ONCE(count > iter->iter_len))
 			return -EIO;
-		iter->pos += iter->processed;
-		iter->len -= iter->processed;
-		if (!iter->len || (!iter->processed && !stale))
+		iter->pos += count;
+		iter->len -= count;
+		if (!iter->len || (!count && !stale))
 			ret = 0;
+		iter->iter_len -= count;
+		/*
+		 * XXX: Stale the mapping on consuming iter_len to prevent
+		 * interference from subsequent 0 byte (i.e. return success
+		 * advance). Perhaps use a separate flag here for "incremental"
+		 * iterators..?
+		 */
+		if (!iter->iter_len)
+			iter->iomap.flags |= IOMAP_F_STALE;
 	}
 
-	/* clear the per iteration state */
-	iter->processed = 0;
-	memset(&iter->iomap, 0, sizeof(iter->iomap));
-	memset(&iter->srcmap, 0, sizeof(iter->srcmap));
 	return ret;
 }
 
+static inline int iomap_iter_advance_processed(struct iomap_iter *iter)
+{
+	return iomap_iter_advance(iter, iter->processed);
+}
+
 static inline void iomap_iter_done(struct iomap_iter *iter)
 {
 	WARN_ON_ONCE(iter->iomap.offset > iter->pos);
@@ -53,6 +71,8 @@ static inline void iomap_iter_done(struct iomap_iter *iter)
 	trace_iomap_iter_dstmap(iter->inode, &iter->iomap);
 	if (iter->srcmap.type != IOMAP_HOLE)
 		trace_iomap_iter_srcmap(iter->inode, &iter->srcmap);
+
+	iter->iter_len = iomap_length(iter);
 }
 
 /**
@@ -83,7 +103,8 @@ int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops)
 	}
 
 	trace_iomap_iter(iter, ops, _RET_IP_);
-	ret = iomap_iter_advance(iter);
+	ret = iomap_iter_advance_processed(iter);
+	iomap_iter_reset_iomap(iter);
 	if (ret <= 0)
 		return ret;
 
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 27048ec10e1c..6fb7adc1f2c6 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -217,6 +217,7 @@ struct iomap_iter {
 	struct inode *inode;
 	loff_t pos;
 	u64 len;
+	u64 iter_len;
 	s64 processed;
 	unsigned flags;
 	struct iomap iomap;
@@ -225,6 +226,7 @@ struct iomap_iter {
 };
 
 int iomap_iter(struct iomap_iter *iter, const struct iomap_ops *ops);
+int iomap_iter_advance(struct iomap_iter *iter, s64 count);
 
 /**
  * iomap_length - length of the current iomap iteration
