lib/repo-commit: Abort a transaction if preparing it fails

If ostree_repo_prepare_transaction() fails, we should reset the
repository’s state so that the failed call was essentially idempotent.
Do that by calling ostree_repo_abort_transaction() on the failure path.

Typically, the way for preparing a transaction to fail is for its
GCancellable to be triggered, rather than because any of the operations
involved in preparing a transaction are particularly failure prone.

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Closes: #1647
Approved by: cgwalters
This commit is contained in:
Philip Withnall 2018-06-26 14:39:16 +01:00 committed by Atomic Bot
parent be018ed70c
commit abff8b8cfa

View File

@ -1614,9 +1614,15 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(_OstreeRepoAutoTransaction) txn = NULL;
g_return_val_if_fail (self->in_transaction == FALSE, FALSE);
g_debug ("Preparing transaction in repository %p", self);
/* Set up to abort the transaction if we return early from this function. */
txn = self;
memset (&self->txn.stats, 0, sizeof (OstreeRepoTransactionStats));
self->txn_locked = _ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED,
@ -1631,6 +1637,7 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
struct statvfs stvfsbuf;
if (TEMP_FAILURE_RETRY (fstatvfs (self->repo_dir_fd, &stvfsbuf)) < 0)
return glnx_throw_errno_prefix (error, "fstatvfs");
g_mutex_lock (&self->txn_lock);
self->txn.blocksize = stvfsbuf.f_bsize;
guint64 reserved_blocks = min_free_space_calculate_reserved_blocks (self, &stvfsbuf);
@ -1663,6 +1670,9 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
cancellable, error))
return FALSE;
/* Success: do not abort the transaction when returning. */
txn = NULL;
if (out_transaction_resume)
*out_transaction_resume = ret_transaction_resume;
return TRUE;
@ -2150,6 +2160,8 @@ ostree_repo_commit_transaction (OstreeRepo *self,
{
g_return_val_if_fail (self->in_transaction == TRUE, FALSE);
g_debug ("Committing transaction in repository %p", self);
if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_PRE_COMMIT) > 0)
return glnx_throw (error, "OSTREE_REPO_TEST_ERROR_PRE_COMMIT specified");
@ -2234,6 +2246,8 @@ ostree_repo_abort_transaction (OstreeRepo *self,
if (!self->in_transaction)
return TRUE;
g_debug ("Aborting transaction in repository %p", self);
if (self->loose_object_devino_hash)
g_hash_table_remove_all (self->loose_object_devino_hash);