mirror of
https://github.com/ostreedev/ostree.git
synced 2025-02-03 17:47:40 +03:00
core: Use linkat() rather than link() in threaded checkouts
This seems to work around a likely Linux kernel VFS bug, where I randomly see ENOENT on link() when we *definitely* called mkdir() at an earlier point in time.
This commit is contained in:
parent
d6956bfc19
commit
1642310486
@ -3196,6 +3196,7 @@ checkout_file_hardlink (OstreeRepo *self,
|
|||||||
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
OstreeRepoCheckoutOverwriteMode overwrite_mode,
|
||||||
GFile *source,
|
GFile *source,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
|
int dirfd,
|
||||||
gboolean *out_was_supported,
|
gboolean *out_was_supported,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error)
|
GError **error)
|
||||||
@ -3204,7 +3205,11 @@ checkout_file_hardlink (OstreeRepo *self,
|
|||||||
gboolean ret_was_supported = FALSE;
|
gboolean ret_was_supported = FALSE;
|
||||||
ot_lobj GFile *dir = NULL;
|
ot_lobj GFile *dir = NULL;
|
||||||
|
|
||||||
if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) != -1)
|
if (dirfd != -1 &&
|
||||||
|
linkat (-1, ot_gfile_get_path_cached (source),
|
||||||
|
dirfd, ot_gfile_get_basename_cached (destination), 0) != -1)
|
||||||
|
ret_was_supported = TRUE;
|
||||||
|
else if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) != -1)
|
||||||
ret_was_supported = TRUE;
|
ret_was_supported = TRUE;
|
||||||
else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
|
else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
|
||||||
{
|
{
|
||||||
@ -3318,6 +3323,7 @@ typedef struct {
|
|||||||
OstreeRepoCheckoutMode mode;
|
OstreeRepoCheckoutMode mode;
|
||||||
OstreeRepoCheckoutOverwriteMode overwrite_mode;
|
OstreeRepoCheckoutOverwriteMode overwrite_mode;
|
||||||
GFile *destination;
|
GFile *destination;
|
||||||
|
int dirfd;
|
||||||
OstreeRepoFile *source;
|
OstreeRepoFile *source;
|
||||||
GFileInfo *source_info;
|
GFileInfo *source_info;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
@ -3447,7 +3453,7 @@ checkout_file_thread (GSimpleAsyncResult *result,
|
|||||||
/* If we found one, try hardlinking */
|
/* If we found one, try hardlinking */
|
||||||
if (!checkout_file_hardlink (checkout_data->repo, checkout_data->mode,
|
if (!checkout_file_hardlink (checkout_data->repo, checkout_data->mode,
|
||||||
checkout_data->overwrite_mode, loose_path,
|
checkout_data->overwrite_mode, loose_path,
|
||||||
checkout_data->destination,
|
checkout_data->destination, checkout_data->dirfd,
|
||||||
&hardlink_supported, cancellable, error))
|
&hardlink_supported, cancellable, error))
|
||||||
{
|
{
|
||||||
g_prefix_error (error, "Hardlinking loose object %s to %s: ", checksum,
|
g_prefix_error (error, "Hardlinking loose object %s to %s: ", checksum,
|
||||||
@ -3487,6 +3493,7 @@ checkout_one_file_async (OstreeRepo *self,
|
|||||||
OstreeRepoFile *source,
|
OstreeRepoFile *source,
|
||||||
GFileInfo *source_info,
|
GFileInfo *source_info,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
|
int dirfd,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
@ -3498,6 +3505,7 @@ checkout_one_file_async (OstreeRepo *self,
|
|||||||
checkout_data->mode = mode;
|
checkout_data->mode = mode;
|
||||||
checkout_data->overwrite_mode = overwrite_mode;
|
checkout_data->overwrite_mode = overwrite_mode;
|
||||||
checkout_data->destination = g_object_ref (destination);
|
checkout_data->destination = g_object_ref (destination);
|
||||||
|
checkout_data->dirfd = dirfd;
|
||||||
checkout_data->source = g_object_ref (source);
|
checkout_data->source = g_object_ref (source);
|
||||||
checkout_data->source_info = g_object_ref (source_info);
|
checkout_data->source_info = g_object_ref (source_info);
|
||||||
checkout_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
checkout_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
||||||
@ -3542,6 +3550,8 @@ typedef struct {
|
|||||||
gboolean caught_error;
|
gboolean caught_error;
|
||||||
GError *error;
|
GError *error;
|
||||||
|
|
||||||
|
DIR *dir_handle;
|
||||||
|
|
||||||
guint pending_ops;
|
guint pending_ops;
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
GSimpleAsyncResult *result;
|
GSimpleAsyncResult *result;
|
||||||
@ -3557,6 +3567,8 @@ checkout_tree_async_data_free (gpointer data)
|
|||||||
g_clear_object (&checkout_data->source);
|
g_clear_object (&checkout_data->source);
|
||||||
g_clear_object (&checkout_data->source_info);
|
g_clear_object (&checkout_data->source_info);
|
||||||
g_clear_object (&checkout_data->cancellable);
|
g_clear_object (&checkout_data->cancellable);
|
||||||
|
if (checkout_data->dir_handle)
|
||||||
|
(void) closedir (checkout_data->dir_handle);
|
||||||
g_free (checkout_data);
|
g_free (checkout_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3667,8 +3679,8 @@ on_got_next_files (GObject *src,
|
|||||||
checkout_one_file_async (data->repo, data->mode,
|
checkout_one_file_async (data->repo, data->mode,
|
||||||
data->overwrite_mode,
|
data->overwrite_mode,
|
||||||
(OstreeRepoFile*)src_child, file_info,
|
(OstreeRepoFile*)src_child, file_info,
|
||||||
dest_path, data->cancellable,
|
dest_path, dirfd(data->dir_handle),
|
||||||
on_one_file_checked_out,
|
data->cancellable, on_one_file_checked_out,
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
data->pending_ops++;
|
data->pending_ops++;
|
||||||
@ -3726,6 +3738,13 @@ ostree_repo_checkout_tree_async (OstreeRepo *self,
|
|||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
checkout_data->dir_handle = opendir (ot_gfile_get_path_cached (checkout_data->destination));
|
||||||
|
if (!checkout_data->dir_handle)
|
||||||
|
{
|
||||||
|
ot_util_set_error_from_errno (error, errno);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
g_clear_pointer (&xattrs, (GDestroyNotify) g_variant_unref);
|
g_clear_pointer (&xattrs, (GDestroyNotify) g_variant_unref);
|
||||||
|
|
||||||
dir_enum = g_file_enumerate_children ((GFile*)checkout_data->source,
|
dir_enum = g_file_enumerate_children ((GFile*)checkout_data->source,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user