From abff8b8cfac00203062362ad506ffdb14f1da6ef Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 26 Jun 2018 14:39:16 +0100 Subject: [PATCH] lib/repo-commit: Abort a transaction if preparing it fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Closes: #1647 Approved by: cgwalters --- src/libostree/ostree-repo-commit.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index a3a6df44..54bd8b66 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -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);