]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
xfs: fix double ijoin in xfs_reflink_cancel_cow_range
authorDave Chinner <dchinner@redhat.com>
Wed, 9 May 2018 14:49:09 +0000 (07:49 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Thu, 10 May 2018 15:56:46 +0000 (08:56 -0700)
xfs_reflink_cancel_cow_range joins an inode twice to the same
transaction.  This is not allowed, so fix it and document that the
callers of xfs_reflink_cancel_cow_blocks() must have already joined the
inode to the permanent transaction passed in.

Signed-Off-By: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
[darrick: edited the commit log to remove trace for nonexistent ASSERT]
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/xfs_reflink.c

index cdbd342a5249988aeecadcc695ac2f51c6a3c085..bce2b5351d64ea675ca5634e9c41cc7643e0c5a0 100644 (file)
@@ -552,6 +552,9 @@ xfs_reflink_trim_irec_to_next_cow(
  *
  * If cancel_real is true this function cancels all COW fork extents for the
  * inode; if cancel_real is false, real extents are not cleared.
+ *
+ * Caller must have already joined the inode to the current transaction. The
+ * inode will be joined to the transaction returned to the caller.
  */
 int
 xfs_reflink_cancel_cow_blocks(
@@ -592,7 +595,6 @@ xfs_reflink_cancel_cow_blocks(
                        if (error)
                                break;
                } else if (del.br_state == XFS_EXT_UNWRITTEN || cancel_real) {
-                       xfs_trans_ijoin(*tpp, ip, 0);
                        xfs_defer_init(&dfops, &firstfsb);
 
                        /* Free the CoW orphan record. */
@@ -1570,6 +1572,7 @@ xfs_reflink_clear_inode_flag(
         * We didn't find any shared blocks so turn off the reflink flag.
         * First, get rid of any leftover CoW mappings.
         */
+       xfs_trans_ijoin(*tpp, ip, 0);
        error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, NULLFILEOFF, true);
        if (error)
                return error;
@@ -1578,7 +1581,6 @@ xfs_reflink_clear_inode_flag(
        trace_xfs_reflink_unset_inode_flag(ip);
        ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
        xfs_inode_clear_cowblocks_tag(ip);
-       xfs_trans_ijoin(*tpp, ip, 0);
        xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
 
        return error;