Make TX abort after assign safer

It is not right, but there are few examples when TX is aborted
after being assigned in case of error.  To handle it better on
production systems add extra cleanup steps.

While here, replace couple dmu_tx_abort() in simple cases.

Reviewed-by: Rob Norris <robn@despairlabs.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Igor Kozhukhov <igor@dilos.org>
Signed-off-by:	Alexander Motin <mav@FreeBSD.org>
Sponsored by:	iXsystems, Inc.
Closes #17438
This commit is contained in:
Alexander Motin 2025-06-10 12:30:06 -04:00 committed by GitHub
parent bcd0430236
commit ba227e2cc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 3 deletions

View File

@ -1392,6 +1392,7 @@ dmu_tx_destroy(dmu_tx_t *tx)
void
dmu_tx_commit(dmu_tx_t *tx)
{
/* This function should only be used on assigned transactions. */
ASSERT(tx->tx_txg != 0);
/*
@ -1430,7 +1431,12 @@ dmu_tx_commit(dmu_tx_t *tx)
void
dmu_tx_abort(dmu_tx_t *tx)
{
ASSERT(tx->tx_txg == 0);
/* This function should not be used on assigned transactions. */
ASSERT0(tx->tx_txg);
/* Should not be needed, but better be safe than sorry. */
if (tx->tx_tempreserve_cookie)
dsl_dir_tempreserve_clear(tx->tx_tempreserve_cookie, tx);
/*
* Call any registered callbacks with an error code.
@ -1438,6 +1444,9 @@ dmu_tx_abort(dmu_tx_t *tx)
if (!list_is_empty(&tx->tx_callbacks))
dmu_tx_do_callbacks(&tx->tx_callbacks, SET_ERROR(ECANCELED));
/* Should not be needed, but better be safe than sorry. */
dmu_tx_unassign(tx);
dmu_tx_destroy(tx);
}

View File

@ -1188,7 +1188,7 @@ zfs_rewrite(znode_t *zp, uint64_t off, uint64_t len, uint64_t flags,
error = dmu_buf_hold_array_by_dnode(dn, off, n, TRUE, FTAG,
&numbufs, &dbp, DMU_READ_PREFETCH | DMU_UNCACHEDIO);
if (error) {
dmu_tx_abort(tx);
dmu_tx_commit(tx);
break;
}
for (int i = 0; i < numbufs; i++) {
@ -1860,7 +1860,7 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
*/
if (inblksz != outzp->z_blksz) {
error = SET_ERROR(EINVAL);
dmu_tx_abort(tx);
dmu_tx_commit(tx);
break;
}