aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-01-09 10:38:45 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-12 05:39:41 -0500
commit3d6e3b12bb4eac5cadb4733530c1967fe9e3d6a9 (patch)
tree55166fd5eec2a1e205e7b182d96d1aa58ffaa348 /fs
parent4a323331d8c963aaba4f19f84f16c052bd7eb156 (diff)
xfs: clean up cow fork reservation and tag inodes correctly
commit 0260d8ff5f76617e3a55a1c471383ecb4404c3ad upstream. COW fork reservation is implemented via delayed allocation. The code is modeled after the traditional delalloc allocation code, but is slightly different in terms of how preallocation occurs. Rather than post-eof speculative preallocation, COW fork preallocation is implemented via a COW extent size hint that is designed to minimize fragmentation as a reflinked file is split over time. xfs_reflink_reserve_cow() still uses logic that is oriented towards dealing with post-eof speculative preallocation, however, and is stale or not necessarily correct. First, the EOF alignment to the COW extent size hint is implemented in xfs_bmapi_reserve_delalloc() (which does so correctly by aligning the start and end offsets) and so is not necessary in xfs_reflink_reserve_cow(). The backoff and retry logic on ENOSPC is also ineffective for the same reason, as xfs_bmapi_reserve_delalloc() will simply perform the same allocation request on the retry. Finally, since the COW extent size hint aligns the start and end offset of the range to allocate, the end_fsb != orig_end_fsb logic is not sufficient. Indeed, if a write request happens to end on an aligned offset, it is possible that we do not tag the inode for COW preallocation even though xfs_bmapi_reserve_delalloc() may have preallocated at the start offset. Kill the unnecessary, duplicate code in xfs_reflink_reserve_cow(). Remove the inode tag logic as well since xfs_bmapi_reserve_delalloc() has been updated to tag the inode correctly. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_reflink.c29
1 files changed, 3 insertions, 26 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 7a30bff82dcf..4d3f74e3c5e1 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -245,11 +245,9 @@ xfs_reflink_reserve_cow(
245{ 245{
246 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); 246 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
247 struct xfs_bmbt_irec got; 247 struct xfs_bmbt_irec got;
248 xfs_fileoff_t end_fsb, orig_end_fsb;
249 int error = 0; 248 int error = 0;
250 bool eof = false, trimmed; 249 bool eof = false, trimmed;
251 xfs_extnum_t idx; 250 xfs_extnum_t idx;
252 xfs_extlen_t align;
253 251
254 /* 252 /*
255 * Search the COW fork extent list first. This serves two purposes: 253 * Search the COW fork extent list first. This serves two purposes:
@@ -287,33 +285,12 @@ xfs_reflink_reserve_cow(
287 if (error) 285 if (error)
288 return error; 286 return error;
289 287
290 end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount;
291
292 align = xfs_eof_alignment(ip, xfs_get_cowextsz_hint(ip));
293 if (align)
294 end_fsb = roundup_64(end_fsb, align);
295
296retry:
297 error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff, 288 error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
298 end_fsb - imap->br_startoff, 0, &got, &idx, eof); 289 imap->br_blockcount, 0, &got, &idx, eof);
299 switch (error) { 290 if (error == -ENOSPC || error == -EDQUOT)
300 case 0:
301 break;
302 case -ENOSPC:
303 case -EDQUOT:
304 /* retry without any preallocation */
305 trace_xfs_reflink_cow_enospc(ip, imap); 291 trace_xfs_reflink_cow_enospc(ip, imap);
306 if (end_fsb != orig_end_fsb) { 292 if (error)
307 end_fsb = orig_end_fsb;
308 goto retry;
309 }
310 /*FALLTHRU*/
311 default:
312 return error; 293 return error;
313 }
314
315 if (end_fsb != orig_end_fsb)
316 xfs_inode_set_cowblocks_tag(ip);
317 294
318 trace_xfs_reflink_cow_alloc(ip, &got); 295 trace_xfs_reflink_cow_alloc(ip, &got);
319 return 0; 296 return 0;