]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs: make tr_growdata a permanent transaction
authorBrian Foster <bfoster@redhat.com>
Tue, 25 Jun 2019 21:57:55 +0000 (14:57 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 26 Jun 2019 01:46:26 +0000 (18:46 -0700)
The growdata transaction is used by growfs operations to increase
the data size of the filesystem. Part of this sequence involves
extending the size of the last preexisting AG in the fs, if
necessary. This is implemented by freeing the newly available
physical range to the AG.

tr_growdata is not a permanent transaction, however, and block
allocation transactions must be permanent to handle deferred frees
of AGFL blocks. If the grow operation extends an existing AG that
requires AGFL fixing, assert failures occur due to a populated dfops
list on a non-permanent transaction and the AGFL free does not
occur. This is reproduced (rarely) by xfs/104.

Change tr_growdata to a permanent transaction with a default log
count. This increases initial transaction reservation size, but
growfs is an infrequent and non-performance critical operation and
so should have minimal impact. Also add an assert in the block
allocation path to make this transaction requirement explicit and
obvious to future callers.

Reported-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
[darrick: add a comment to the assert]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
libxfs/xfs_alloc.c
libxfs/xfs_trans_resv.c

index d440e4195cb254c3a8069893b9574a08ba4f09c5..e21c788531a0ed1264b5951d48aa43411fd1f618 100644 (file)
@@ -2239,6 +2239,9 @@ xfs_alloc_fix_freelist(
        xfs_extlen_t            need;   /* total blocks needed in freelist */
        int                     error = 0;
 
+       /* deferred ops (AGFL block frees) require permanent transactions */
+       ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
+
        if (!pag->pagf_init) {
                error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
                if (error)
index 4ecf7c2e8740811e2ba336837de58b03f4367c08..5bd258d93bdee5a40ab80624d163850fe20b2543 100644 (file)
@@ -875,9 +875,13 @@ xfs_trans_resv_calc(
        resp->tr_sb.tr_logres = xfs_calc_sb_reservation(mp);
        resp->tr_sb.tr_logcount = XFS_DEFAULT_LOG_COUNT;
 
+       /* growdata requires permanent res; it can free space to the last AG */
+       resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp);
+       resp->tr_growdata.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT;
+       resp->tr_growdata.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
        /* The following transaction are logged in logical format */
        resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp);
-       resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp);
        resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp);
        resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp);
        resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp);