fsck: Mark commits with missing or deleted object partial

This means we can later use various operations to heal the repository
because ostree does not assume all objects are there.

This the begining of a fix for https://github.com/ostreedev/ostree/pull/345

Closes: #1533
Approved by: cgwalters
This commit is contained in:
Alexander Larsson 2018-04-06 15:39:43 +02:00 committed by Atomic Bot
parent f258e9e5ff
commit 474556b955
3 changed files with 89 additions and 8 deletions

View File

@ -53,6 +53,8 @@ static gboolean
fsck_one_object (OstreeRepo *repo,
const char *checksum,
OstreeObjectType objtype,
GHashTable *object_parents,
GVariant *key,
gboolean *out_found_corruption,
GCancellable *cancellable,
GError **error)
@ -60,12 +62,14 @@ fsck_one_object (OstreeRepo *repo,
g_autoptr(GError) temp_error = NULL;
if (!ostree_repo_fsck_object (repo, objtype, checksum, cancellable, &temp_error))
{
gboolean object_missing = FALSE;
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_printerr ("Object missing: %s.%s\n", checksum,
ostree_object_type_to_string (objtype));
*out_found_corruption = TRUE;
object_missing = TRUE;
}
else
{
@ -73,7 +77,7 @@ fsck_one_object (OstreeRepo *repo,
{
g_printerr ("%s\n", temp_error->message);
(void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL);
*out_found_corruption = TRUE;
object_missing = TRUE;
}
else
{
@ -81,6 +85,26 @@ fsck_one_object (OstreeRepo *repo,
return FALSE;
}
}
if (object_missing)
{
*out_found_corruption = TRUE;
if (object_parents != NULL && objtype != OSTREE_OBJECT_TYPE_COMMIT)
{
g_auto(GStrv) parent_commits = ostree_repo_traverse_parents_get_commits (object_parents, key);
int i;
/* The commit was missing or deleted, mark the commit partial */
for (i = 0; parent_commits[i] != NULL; i++)
{
const char *parent_commit = parent_commits[i];
g_printerr ("Marking commit %s as partial\n", parent_commit);
if (!ostree_repo_mark_commit_partial (repo, parent_commit, TRUE, error))
return FALSE;
}
}
}
}
return TRUE;
@ -94,6 +118,7 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
GError **error)
{
g_autoptr(GHashTable) reachable_objects = ostree_repo_traverse_new_reachable ();
g_autoptr(GHashTable) object_parents = ostree_repo_traverse_new_parents ();
GHashTableIter hash_iter;
gpointer key, value;
@ -108,7 +133,7 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT);
if (!ostree_repo_traverse_commit_union (repo, checksum, 0, reachable_objects,
if (!ostree_repo_traverse_commit_union_with_parents (repo, checksum, 0, reachable_objects, object_parents,
cancellable, error))
return FALSE;
}
@ -127,8 +152,9 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
if (!fsck_one_object (repo, checksum, objtype, out_found_corruption,
cancellable, error))
if (!fsck_one_object (repo, checksum, objtype,
object_parents, serialized_key,
out_found_corruption, cancellable, error))
return FALSE;
i++;
@ -150,7 +176,7 @@ fsck_commit_for_ref (OstreeRepo *repo,
GError **error)
{
if (!fsck_one_object (repo, checksum, OSTREE_OBJECT_TYPE_COMMIT,
found_corruption,
NULL, NULL, found_corruption,
cancellable, error))
return FALSE;

View File

@ -30,6 +30,20 @@ ostree --repo=bare-repo init --mode=bare-user
ostree --repo=bare-repo remote add origin --set=gpg-verify=false $(cat ${test_tmpdir}/httpd-address)
log_timestamps ostree --repo=bare-repo pull --disable-static-deltas origin ${host_nonremoteref}
echo "ok pull"
# fsck marks commits partial
# https://github.com/ostreedev/ostree/pull/1533
for d in $(find bare-repo/objects/ -maxdepth 1 -type d); do
(find ${d} -name '*.file' || true) | head -20 | xargs rm -vf
done
if ostree --repo=bare-repo fsck; then
fatal "fsck unexpectedly succeeded"
fi
ostree --repo=bare-repo pull origin ${host_nonremoteref}
# Don't need a full fsck here
ostree --repo=bare-repo ls origin:${host_nonremoteref} >/dev/null
rm bare-repo repo -rf
# Try copying the host's repo across a mountpoint for direct
@ -44,6 +58,7 @@ log_timestamps ostree --repo=repo fsck
cd ..
umount mnt
# Cleanup
kill -TERM $(cat ${test_tmpdir}/httpd-pid)
echo "ok"
date

View File

@ -21,7 +21,7 @@
set -euo pipefail
echo "1..6"
echo "1..8"
. $(dirname $0)/libtest.sh
@ -89,3 +89,43 @@ if ${CMD_PREFIX} ostree --repo=ostree-path-traverse/repo checkout pathtraverse-t
fi
assert_file_has_content_literal err.txt 'Invalid / in filename ../afile'
echo "ok path traverse checkout"
cd ${test_tmpdir}
rm repo files -rf
setup_test_repository "bare"
rev=$($OSTREE rev-parse test2)
filechecksum=$(ostree_file_path_to_checksum repo test2 /firstfile)
rm repo/$(ostree_checksum_to_relative_object_path repo $filechecksum)
assert_not_has_file repo/state/${rev}.commitpartial
if $OSTREE fsck -q 2>err.txt; then
assert_not_reached "fsck unexpectedly succeeded"
fi
assert_file_has_content_literal err.txt "Object missing:"
assert_file_has_content_literal err.txt "Marking commit $rev as partial"
assert_has_file repo/state/${rev}.commitpartial
echo "ok missing file"
cd ${test_tmpdir}
rm repo files -rf
setup_test_repository "bare"
rev=$($OSTREE rev-parse test2)
filechecksum=$(ostree_file_path_to_checksum repo test2 /firstfile)
echo corrupted >> repo/$(ostree_checksum_to_relative_object_path repo $filechecksum)
assert_not_has_file repo/state/${rev}.commitpartial
if $OSTREE fsck -q --delete 2>err.txt; then
assert_not_reached "fsck unexpectedly succeeded"
fi
assert_file_has_content_literal err.txt "Corrupted file object;"
assert_file_has_content_literal err.txt "Marking commit $rev as partial"
assert_has_file repo/state/${rev}.commitpartial
echo "ok corrupt file"