Skip to content

Commit

Permalink
transactions: move all tmpobject-%s files under a per-boot subdir
Browse files Browse the repository at this point in the history
This prevents to use files after a kernel crash or power failure and
that can be not completely synced to disk.

Signed-off-by: Giuseppe Scrivano <[email protected]>
  • Loading branch information
giuseppe committed Jan 28, 2015
1 parent 35821c9 commit bc29e71
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 42 deletions.
170 changes: 132 additions & 38 deletions src/libostree/ostree-repo-commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,41 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
return TRUE;
}

void
static gboolean
ostree_repo_get_tmpobject_bootid (char **out,
GCancellable *cancellable,
GError **error)
{
gs_unref_object GFile *file = g_file_new_for_path ("/proc/sys/kernel/random/boot_id");
if (! g_file_load_contents (file,
cancellable,
out,
NULL,
NULL,
error))
return FALSE;

g_strdelimit (*out, "\n", '\0');
return TRUE;
}

gboolean
_ostree_repo_get_tmpobject_path (char *output,
const char *checksum,
OstreeObjectType objtype)
OstreeObjectType objtype,
GCancellable *cancellable,
GError **error)
{
gs_free char *boot_id = NULL;
if (! ostree_repo_get_tmpobject_bootid (&boot_id, cancellable, error))
return FALSE;

g_sprintf (output,
"tmpobject-%s.%s",
"%s/tmpobject-%s.%s",
boot_id,
checksum,
ostree_object_type_to_string (objtype));
return TRUE;
}

static GVariant *
Expand Down Expand Up @@ -289,7 +315,9 @@ commit_loose_object_trusted (OstreeRepo *self,
if (self->in_transaction)
{
char tmpbuf[_OSTREE_LOOSE_PATH_MAX];
_ostree_repo_get_tmpobject_path (tmpbuf, checksum, objtype);
if (! _ostree_repo_get_tmpobject_path (tmpbuf, checksum, objtype,
cancellable, error))
goto out;
tmp_dest = g_strdup (tmpbuf);
dir = self->tmp_dir_fd;
dest = tmp_dest;
Expand Down Expand Up @@ -944,6 +972,7 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
gboolean ret = FALSE;
gboolean ret_transaction_resume = FALSE;
gs_free char *transaction_str = NULL;
gs_free char *boot_id = NULL;

g_return_val_if_fail (self->in_transaction == FALSE, FALSE);

Expand All @@ -963,6 +992,20 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
if (!ot_gfile_ensure_unlinked (self->transaction_lock_path, cancellable, error))
goto out;
}

if (! ostree_repo_get_tmpobject_bootid (&boot_id, cancellable, error))
goto out;

if (mkdirat (self->tmp_dir_fd, boot_id, 0777) == -1)
{
int errsv = errno;
if (G_UNLIKELY (errsv != EEXIST))
{
gs_set_error_from_errno (error, errsv);
goto out;
}
}

transaction_str = g_strdup_printf ("pid=%llu", (unsigned long long) getpid ());
if (!g_file_make_symbolic_link (self->transaction_lock_path, transaction_str,
cancellable, error))
Expand All @@ -976,30 +1019,37 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
}

static gboolean
cleanup_tmpdir (OstreeRepo *self,
gboolean move_tmpobject,
GCancellable *cancellable,
GError **error)
move_tmpobjects (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
gs_free char *boot_id = NULL;
gs_unref_object GFileEnumerator *enumerator = NULL;
guint64 curtime_secs;
gs_unref_object GFile *tmpobjectsdir = NULL;
int dir_fd = -1;

enumerator = g_file_enumerate_children (self->tmp_dir, "standard::name,time::modified",
if (! ostree_repo_get_tmpobject_bootid (&boot_id, cancellable, error))
goto out;

tmpobjectsdir = g_file_get_child (self->tmp_dir, boot_id);
if (! tmpobjectsdir)
goto out;

enumerator = g_file_enumerate_children (tmpobjectsdir, "standard::name,time::modified",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
error);
if (!enumerator)
goto out;

curtime_secs = g_get_real_time () / 1000000;
if (!gs_file_open_dir_fd (tmpobjectsdir, &dir_fd, cancellable, error))
goto out;

while (TRUE)
{
GFileInfo *file_info;
GFile *path;
guint64 mtime;
guint64 delta;
gs_free char *basename = NULL;

if (!gs_file_enumerator_iterate (enumerator, &file_info, &path,
Expand All @@ -1008,38 +1058,82 @@ cleanup_tmpdir (OstreeRepo *self,
if (file_info == NULL)
break;

if (move_tmpobject)
basename = g_file_get_basename (path);
if (strncmp (basename, "tmpobject-", 10) == 0)
{
basename = g_file_get_basename (path);
if (strncmp (basename, "tmpobject-", 10) == 0)
{
char loose_path[_OSTREE_LOOSE_PATH_MAX];
gs_free gchar *checksum = NULL;
OstreeObjectType type;
ostree_object_from_string (basename + 10,
&checksum,
&type);
char loose_path[_OSTREE_LOOSE_PATH_MAX];
gs_free gchar *checksum = NULL;
OstreeObjectType type;
ostree_object_from_string (basename + 10,
&checksum,
&type);

_ostree_loose_path (loose_path, checksum, type, self->mode);
_ostree_loose_path (loose_path, checksum, type, self->mode);

if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path,
cancellable, error))
goto out;
if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path,
cancellable, error))
goto out;

if (G_UNLIKELY (renameat (self->tmp_dir_fd, basename,
self->objects_dir_fd, loose_path) < 0))
if (G_UNLIKELY (renameat (dir_fd, basename,
self->objects_dir_fd, loose_path) < 0))
{
(void) unlinkat (self->tmp_dir_fd, basename, 0);
if (errno != EEXIST)
{
(void) unlinkat (self->tmp_dir_fd, basename, 0);
if (errno != EEXIST)
{
gs_set_error_from_errno (error, errno);
g_prefix_error (error, "Storing file '%s': ", loose_path);
goto out;
}
gs_set_error_from_errno (error, errno);
g_prefix_error (error, "Storing file '%s': ", loose_path);
goto out;
}
continue;
}
continue;
}
}

if (!gs_shutil_rm_rf (tmpobjectsdir, cancellable, error))
goto out;

ret = TRUE;
out:
if (dir_fd >= 0)
close (dir_fd);
return ret;
}

static gboolean
cleanup_tmpdir (OstreeRepo *self,
gboolean move_tmpobject,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
gs_unref_object GFileEnumerator *enumerator = NULL;
guint64 curtime_secs;

if (move_tmpobject)
if (! move_tmpobjects (self, cancellable, error))
goto out;

enumerator = g_file_enumerate_children (self->tmp_dir, "standard::name,time::modified",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!enumerator)
goto out;

curtime_secs = g_get_real_time () / 1000000;

while (TRUE)
{
GFileInfo *file_info;
GFile *path;
guint64 mtime;
guint64 delta;

if (!gs_file_enumerator_iterate (enumerator, &file_info, &path,
cancellable, error))
goto out;
if (file_info == NULL)
break;

mtime = g_file_info_get_attribute_uint64 (file_info, "time::modified");
if (mtime > curtime_secs)
Expand Down
6 changes: 4 additions & 2 deletions src/libostree/ostree-repo-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
const char *loose_path,
GCancellable *cancellable,
GError **error);
void
gboolean
_ostree_repo_get_tmpobject_path (char *output,
const char *checksum,
OstreeObjectType objtype);
OstreeObjectType objtype,
GCancellable *cancellable,
GError **error);

gboolean
_ostree_repo_find_object (OstreeRepo *self,
Expand Down
8 changes: 6 additions & 2 deletions src/libostree/ostree-repo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1717,7 +1717,9 @@ load_metadata_internal (OstreeRepo *self,

if (self->in_transaction && fd < 0)
{
_ostree_repo_get_tmpobject_path (loose_path_buf, sha256, objtype);
if (! _ostree_repo_get_tmpobject_path (loose_path_buf, sha256, objtype,
cancellable, error))
goto out;
if (!openat_allow_noent (self->tmp_dir_fd, loose_path_buf, &fd, cancellable, error))
goto out;
}
Expand Down Expand Up @@ -2129,7 +2131,9 @@ _ostree_repo_has_loose_object (OstreeRepo *self,

if (self->in_transaction)
{
_ostree_repo_get_tmpobject_path (loose_path_buf, checksum, objtype);
if (! _ostree_repo_get_tmpobject_path (loose_path_buf, checksum, objtype,
cancellable, error))
goto out;
do
res = fstatat (self->tmp_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW);
while (G_UNLIKELY (res == -1 && errno == EINTR));
Expand Down

0 comments on commit bc29e71

Please sign in to comment.