diff options
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 158d1074e1a8..290cfef0d9dd 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -561,12 +561,41 @@ static const struct iomap_writeback_ops xfs_writeback_ops = { .discard_page = xfs_discard_page, }; +/* + * Extend the writeback range to allocation unit granularity and alignment. + * This is a requirement for blocksize > pagesize scenarios such as realtime + * copy on write, since we can only share full rt extents. + */ +static void +xfs_vm_writepage_extend( + struct xfs_inode *ip, + struct writeback_control *wbc) +{ + unsigned int bsize = xfs_inode_alloc_unitsize(ip); + long long int pages_to_write; + + wbc->range_start = rounddown_64(wbc->range_start, bsize); + if (wbc->range_end != LLONG_MAX) + wbc->range_end = roundup_64(wbc->range_end, bsize); + + if (wbc->nr_to_write == LONG_MAX) + return; + + pages_to_write = roundup_64(wbc->range_end - wbc->range_start, + PAGE_SIZE); + if (pages_to_write >= LONG_MAX) + pages_to_write = LONG_MAX; + if (wbc->nr_to_write < pages_to_write) + wbc->nr_to_write = pages_to_write; +} + STATIC int xfs_vm_writepages( - struct address_space *mapping, - struct writeback_control *wbc) + struct address_space *mapping, + struct writeback_control *wbc) { - struct xfs_writepage_ctx wpc = { }; + struct xfs_writepage_ctx wpc = { }; + struct xfs_inode *ip = XFS_I(mapping->host); /* * Writing back data in a transaction context can result in recursive @@ -575,7 +604,10 @@ xfs_vm_writepages( if (WARN_ON_ONCE(current->journal_info)) return 0; - xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); + if (xfs_reflink_need_unshare_around(ip)) + xfs_vm_writepage_extend(ip, wbc); + + xfs_iflags_clear(ip, XFS_ITRUNCATED); return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops); } |