diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 9dbc0891c5..714baa8572 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -285,6 +285,8 @@ struct wait_data { blkid_partition blkidp; sd_device *found; uint64_t uevent_seqnum_not_before; + usec_t timestamp_not_before; + DissectImageFlags flags; }; static inline void wait_data_done(struct wait_data *d) { @@ -329,6 +331,49 @@ finish: return sd_event_exit(sd_device_monitor_get_event(monitor), r); } +static int timeout_handler(sd_event_source *s, uint64_t usec, void *userdata) { + struct wait_data *w = userdata; + int r; + + assert(w); + + /* Why partition not appeared within the timeout? We may lost some uevent, as some properties + * were not ready when we received uevent... Not sure, but anyway, let's try to find the + * partition again before give up. */ + + r = find_partition(w->parent_device, w->blkidp, w->timestamp_not_before, w->flags, &w->found); + if (r == -ENXIO) + return log_debug_errno(SYNTHETIC_ERRNO(ETIMEDOUT), + "Partition still not appeared after timeout reached."); + if (r < 0) + return log_debug_errno(r, "Failed to find partition: %m"); + + log_debug("Partition appeared after timeout reached."); + return sd_event_exit(sd_event_source_get_event(s), 0); +} + +static int retry_handler(sd_event_source *s, uint64_t usec, void *userdata) { + struct wait_data *w = userdata; + int r; + + assert(w); + + r = find_partition(w->parent_device, w->blkidp, w->timestamp_not_before, w->flags, &w->found); + if (r != -ENXIO) { + if (r < 0) + return log_debug_errno(r, "Failed to find partition: %m"); + + log_debug("Partition found by a periodic search."); + return sd_event_exit(sd_event_source_get_event(s), 0); + } + + r = sd_event_source_set_time_relative(s, 500 * USEC_PER_MSEC); + if (r < 0) + return r; + + return sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); +} + static int wait_for_partition_device( sd_device *parent, blkid_partition pp, @@ -338,7 +383,7 @@ static int wait_for_partition_device( DissectImageFlags flags, sd_device **ret) { - _cleanup_(sd_event_source_unrefp) sd_event_source *timeout_source = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *timeout_source = NULL, *retry_source = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; int r; @@ -379,6 +424,8 @@ static int wait_for_partition_device( .parent_device = parent, .blkidp = pp, .uevent_seqnum_not_before = uevent_seqnum_not_before, + .timestamp_not_before = timestamp_not_before, + .flags = flags, }; r = sd_device_monitor_start(monitor, device_monitor_handler, &w); @@ -394,11 +441,26 @@ static int wait_for_partition_device( r = sd_event_add_time( event, &timeout_source, CLOCK_MONOTONIC, deadline, 0, - NULL, INT_TO_PTR(-ETIMEDOUT)); + timeout_handler, &w); + if (r < 0) + return r; + + r = sd_event_source_set_exit_on_failure(timeout_source, true); if (r < 0) return r; } + r = sd_event_add_time_relative( + event, &retry_source, + CLOCK_MONOTONIC, 500 * USEC_PER_MSEC, 0, + retry_handler, &w); + if (r < 0) + return r; + + r = sd_event_source_set_exit_on_failure(retry_source, true); + if (r < 0) + return r; + r = sd_event_loop(event); if (r < 0) return r;