{
struct iomap_iter *iter = container_of(iomap, struct iomap_iter,
iomap);
+ struct address_space *mapping = inode->i_mapping;
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
xfs_fileoff_t end_fsb = xfs_iomap_end_fsb(mp, offset, count);
+ xfs_fileoff_t cow_fsb = NULLFILEOFF;
struct xfs_bmbt_irec imap, cmap;
struct xfs_iext_cursor icur, ccur;
xfs_fsblock_t prealloc_blocks = 0;
}
cow_eof = !xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb,
&ccur, &cmap);
+ if (!cow_eof)
+ cow_fsb = cmap.br_startoff;
}
/* We never need to allocate blocks for unsharing a hole. */
* 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)) {
+ loff_t start, end;
+
+ imap.br_blockcount = imap.br_startoff - offset_fsb;
+ imap.br_startoff = offset_fsb;
+ imap.br_startblock = HOLESTARTBLOCK;
+ imap.br_state = XFS_EXT_NORM;
+
+ if (cow_fsb == NULLFILEOFF)
+ goto found_imap;
+ if (cow_fsb > offset_fsb) {
+ xfs_trim_extent(&imap, offset_fsb,
+ cow_fsb - offset_fsb);
+ goto found_imap;
+ }
+
+ /* COW fork blocks overlap the hole */
+ xfs_trim_extent(&imap, offset_fsb,
+ cmap.br_startoff + cmap.br_blockcount - offset_fsb);
+ start = XFS_FSB_TO_B(mp, imap.br_startoff);
+ end = XFS_FSB_TO_B(mp,
+ imap.br_startoff + imap.br_blockcount) - 1;
+ if (filemap_range_needs_writeback(mapping, start, end)) {
xfs_iunlock(ip, lockmode);
- error = filemap_write_and_wait_range(inode->i_mapping,
- offset, offset + count - 1);
+ error = filemap_write_and_wait_range(mapping, start,
+ end);
if (error)
return error;
goto restart;
}
- xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
- goto out_unlock;
+
+ goto found_imap;
}
/*