if (error)
return error;
+restart:
error = xfs_ilock_for_iomap(ip, flags, &lockmode);
if (error)
return error;
if (eof)
imap.br_startoff = end_fsb; /* fake hole until the end */
- /* We never need to allocate blocks for zeroing or unsharing a hole. */
- if ((flags & (IOMAP_UNSHARE | IOMAP_ZERO)) &&
- imap.br_startoff > offset_fsb) {
+ /* We never need to allocate blocks for unsharing a hole. */
+ if ((flags & IOMAP_UNSHARE) && imap.br_startoff > offset_fsb) {
+ xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
+ goto out_unlock;
+ }
+
+ /*
+ * We may need to zero over a hole in the data fork if it's fronted by
+ * COW blocks and dirty pagecache. To make sure zeroing occurs, force
+ * writeback to remap pending blocks and restart the lookup.
+ */
+ if ((flags & IOMAP_ZERO) && imap.br_startoff > offset_fsb) {
+ if (filemap_range_needs_writeback(inode->i_mapping, offset,
+ offset + count - 1)) {
+ xfs_iunlock(ip, lockmode);
+ error = filemap_write_and_wait_range(inode->i_mapping,
+ offset, offset + count - 1);
+ if (error)
+ return error;
+ goto restart;
+ }
xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
goto out_unlock;
}