@@ -780,7 +780,14 @@ static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset,
if (status)
return status;
- zero_user(page, offset, bytes);
+ /*
+ * zero-around is conditional on whether the page we found already
+ * contains data or not. If it's up to date, it contains data and we
+ * should not zero it. We still need to mark it dirty to get that data
+ * written, however.
+ */
+ if (!(iomap->flags & IOMAP_F_ZERO_AROUND) || !PageUptodate(page))
+ zero_user(page, offset, bytes);
mark_page_accessed(page);
return iomap_write_end(inode, pos, bytes, bytes, page, iomap);
@@ -877,11 +884,41 @@ iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
{
bool *did_zero = data;
loff_t written = 0;
+ loff_t old_count = 0;
int status;
/* already zeroed? we're done. */
- if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN)
- return count;
+ if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN) {
+
+ if (!iomap_need_zero_around(iomap))
+ return count;
+
+ /*
+ * Because we landed in a hole, we only need to zero to the end
+ * of this block. We'll do that by the loop below, but we need
+ * to trim count here so the zero-around only acts on this
+ * block, too.
+ *
+ * The magic "pos + 1" is needed because we want the offset of
+ * the next block after pos. If pos is already aligned to the
+ * block size, the round_up() returns the same value, not that
+ * of the next highest multiple. Hence we have to add 1 to pos
+ * to get round_up() to behave as we want.
+ */
+ old_count = count;
+ if (pos + count > round_up(pos + 1, i_blocksize(inode)))
+ count = round_up(pos + 1, i_blocksize(inode)) - pos;
+
+ status = iomap_zero_around(inode, pos, count, iomap);
+ if (status)
+ return status;
+
+ /*
+ * now clear the zero-around flag so that the range requested
+ * in this block will be unconditionally zeroed.
+ */
+ iomap->flags &= ~IOMAP_F_ZERO_AROUND;
+ }
do {
unsigned offset, bytes;
@@ -903,7 +940,7 @@ iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count,
*did_zero = true;
} while (count > 0);
- return written;
+ return old_count ? old_count : written;
}
int