xfs: clean up cow fork reservation and tag inodes correctly
authorBrian Foster <bfoster@redhat.com>
Mon, 28 Nov 2016 03:57:42 +0000 (14:57 +1100)
committerDave Chinner <david@fromorbit.com>
Mon, 28 Nov 2016 03:57:42 +0000 (14:57 +1100)
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>
fs/xfs/xfs_reflink.c

index a5b027a43990e672fe466c884c0a5d4ef1c1f165..becf2465dd2312d01b6a01accdf8e5bd9b6de163 100644 (file)
@@ -245,11 +245,9 @@ xfs_reflink_reserve_cow(
 {
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
        struct xfs_bmbt_irec    got;
-       xfs_fileoff_t           end_fsb, orig_end_fsb;
        int                     error = 0;
        bool                    eof = false, trimmed;
        xfs_extnum_t            idx;
-       xfs_extlen_t            align;
 
        /*
         * Search the COW fork extent list first.  This serves two purposes:
@@ -287,33 +285,12 @@ xfs_reflink_reserve_cow(
        if (error)
                return error;
 
-       end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount;
-
-       align = xfs_eof_alignment(ip, xfs_get_cowextsz_hint(ip));
-       if (align)
-               end_fsb = roundup_64(end_fsb, align);
-
-retry:
        error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff,
-                       end_fsb - imap->br_startoff, 0, &got, &idx, eof);
-       switch (error) {
-       case 0:
-               break;
-       case -ENOSPC:
-       case -EDQUOT:
-               /* retry without any preallocation */
+                       imap->br_blockcount, 0, &got, &idx, eof);
+       if (error == -ENOSPC || error == -EDQUOT)
                trace_xfs_reflink_cow_enospc(ip, imap);
-               if (end_fsb != orig_end_fsb) {
-                       end_fsb = orig_end_fsb;
-                       goto retry;
-               }
-               /*FALLTHRU*/
-       default:
+       if (error)
                return error;
-       }
-
-       if (end_fsb != orig_end_fsb)
-               xfs_inode_set_cowblocks_tag(ip);
 
        trace_xfs_reflink_cow_alloc(ip, &got);
        return 0;