From a3d2f4261ef9a953904e3e21abafba0dad7daa77 Mon Sep 17 00:00:00 2001
From: gaoyi <gaoyi15@huawei.com>
Date: Mon, 28 Sep 2020 22:36:37 +0800
Subject: [PATCH] Retry to handle the uevent when worker is terminated abnormal

When processing uevent events fails, retry it.
---
 src/udev/udevd.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 75e2086..023fe55 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -69,6 +69,7 @@
 #include "version.h"
 
 #define WORKER_NUM_MAX 2048U
+#define UEVENT_MAX_RETRY_TIMES 3
 #define EVENT_RETRY_INTERVAL_USEC (200 * USEC_PER_MSEC)
 #define EVENT_RETRY_TIMEOUT_USEC  (3 * USEC_PER_MINUTE)
 
@@ -123,6 +124,7 @@ typedef struct Event {
         Manager *manager;
         Worker *worker;
         EventState state;
+        int retry;
 
         sd_device *dev;
 
@@ -166,6 +168,32 @@ typedef enum EventResult {
         _EVENT_RESULT_INVALID = -EINVAL,
 } EventResult;
 
+static bool event_retry(Event *event) {
+        if (!event)
+                return false;
+
+        assert(event->manager);
+
+        if (--event->retry < 0) {
+                log_device_error(event->dev, "Retry failed.");
+                return false;
+        }
+
+        log_device_info(event->dev, "Retry %d times.", UEVENT_MAX_RETRY_TIMES - event->retry);
+
+        event->timeout_warning_event = sd_event_source_unref(event->timeout_warning_event);
+        event->timeout_event = sd_event_source_unref(event->timeout_event);
+
+        if (event->worker) {
+                event->worker->event = NULL;
+                event->worker = NULL;
+        }
+
+        event->state = EVENT_QUEUED;
+
+        return true;
+}
+
 static Event *event_free(Event *event) {
         if (!event)
                 return NULL;
@@ -1118,6 +1146,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
                 .seqnum = seqnum,
                 .action = action,
                 .state = EVENT_QUEUED,
+                .retry = UEVENT_MAX_RETRY_TIMES,
         };
 
         if (LIST_IS_EMPTY(manager->events)) {
@@ -1547,8 +1576,10 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
                         device_delete_db(worker->event->dev);
                         device_tag_index(worker->event->dev, NULL, false);
 
-                        /* Forward kernel event to libudev listeners */
-                        device_broadcast(manager->monitor, worker->event->dev);
+                        if (event_retry(worker->event) == false) {
+                                /* Forward kernel event to libudev listeners */
+                                device_broadcast(manager->monitor, worker->event->dev);
+                        }
                 }
 
                 worker_free(worker);
-- 
2.33.0

