fix hotplug2 event processing deadlock
[openwrt.git] / package / hotplug2 / patches / 120-throttling.patch
1 --- a/hotplug2.c
2 +++ b/hotplug2.c
3 @@ -21,6 +21,7 @@
4  #include <sys/mman.h>
5  #include <linux/types.h>
6  #include <linux/netlink.h>
7 +#include <poll.h>
8  
9  #include "mem_utils.h"
10  #include "filemap_utils.h"
11 @@ -492,6 +493,11 @@
12         char *coldplug_command = NULL;
13         char *rules_file = HOTPLUG2_RULE_PATH;
14         sigset_t block_mask;
15 +       struct pollfd msg_poll;
16 +
17 +       struct hotplug2_event_t *backlog = NULL;
18 +       struct hotplug2_event_t *backlog_tail = NULL;
19 +       int n_backlog = 0;
20         
21         struct rules_t *rules = NULL;
22         struct filemap_t filemap;
23 @@ -602,6 +608,8 @@
24          * Open netlink socket to read the uevents
25          */
26         netlink_socket = init_netlink_socket(NETLINK_BIND);
27 +       msg_poll.fd = netlink_socket;
28 +       msg_poll.events = POLLIN;
29         
30         if (netlink_socket == -1) {
31                 ERROR("netlink init","Unable to open netlink socket.");
32 @@ -642,20 +650,45 @@
33          * Main loop reading uevents
34          */
35         while (!terminate) {
36 -               /*
37 -                * Read the uevent packet
38 -                */
39 -               size = recv(netlink_socket, &buffer, sizeof(buffer), 0);
40 -               recv_errno = errno;
41 +               if ((n_backlog > 0) && (child_c < max_child_c)) {
42 +                       /* dequeue backlog message */
43 +                       tmpevent = backlog;
44 +                       backlog = backlog->next;
45 +                       n_backlog--;
46 +                       if (backlog_tail == tmpevent)
47 +                               backlog_tail = NULL;
48 +               } else {
49 +                       /*
50 +                        * Read the uevent packet
51 +                        */
52 +                       if (n_backlog >= HOTPLUG2_MSG_BACKLOG) {
53 +                               usleep(HOTPLUG2_THROTTLE_INTERVAL * 1000);
54 +                               continue;
55 +                       }
56 +
57 +                       if ((n_backlog > 0) && (child_c >= max_child_c)) {
58 +                               int fds;
59 +                               msg_poll.revents = 0;
60 +                               fds = poll(&msg_poll, 1, HOTPLUG2_THROTTLE_INTERVAL);
61 +                               if (fds < 0) {
62 +                                       perror("POLL FAILED");
63 +                                       continue;
64 +                               }
65 +                               if (fds == 0)
66 +                                       continue;
67 +                       }
68 +                       size = recv(netlink_socket, &buffer, sizeof(buffer), 0);
69 +                       recv_errno = errno;
70         
71 -               /*
72 -                * Parse the event into an event structure
73 -                */
74 -               tmpevent = get_hotplug2_event(buffer, size);
75 +                       /*
76 +                        * Parse the event into an event structure
77 +                        */
78 +                       tmpevent = get_hotplug2_event(buffer, size);
79                 
80 -               if (tmpevent == NULL) {
81 -                       ERROR("reading events", "Malformed event read (missing action prefix).");
82 -                       continue;
83 +                       if (tmpevent == NULL) {
84 +                               ERROR("reading events", "Malformed event read (missing action prefix).");
85 +                               continue;
86 +                       }
87                 }
88                 
89                 /*
90 @@ -706,13 +739,16 @@
91                          * Unless, of course, we've specified otherwise and no rules that match
92                          * need throttling.
93                          */
94 -                       if (!flags & FLAG_NOTHROTTLE) {
95 -                               /*
96 -                                * Okay, throttle away!
97 -                                */
98 -                               while (child_c >= max_child_c) {
99 -                                       usleep(HOTPLUG2_THROTTLE_INTERVAL);
100 -                               }
101 +                       if (!(flags & FLAG_NOTHROTTLE) && (child_c >= max_child_c)) {
102 +                               /* log the packet and process it later */
103 +                               if (backlog_tail)
104 +                                       backlog_tail->next = tmpevent;
105 +                               else
106 +                                       backlog = tmpevent;
107 +                               tmpevent->next = NULL;
108 +                               backlog_tail = tmpevent;
109 +                               n_backlog++;
110 +                               continue;
111                         }
112                         
113                         sigemptyset(&block_mask);
114 --- a/hotplug2.h
115 +++ b/hotplug2.h
116 @@ -45,9 +45,9 @@
117  #define DBG(action, fmt, arg...)
118  #endif
119  
120 +#define HOTPLUG2_MSG_BACKLOG   64
121  #define UEVENT_BUFFER_SIZE             2048
122 -#define HOTPLUG2_POLL_INTERVAL         20000
123 -#define HOTPLUG2_THROTTLE_INTERVAL     10000
124 +#define HOTPLUG2_THROTTLE_INTERVAL     50
125  #define HOTPLUG2_RULE_PATH             "/etc/hotplug2.rules"
126  
127  #define ACTION_ADD                     0
128 @@ -76,6 +76,7 @@
129         int env_vars_c;
130         char *plain;
131         int plain_s;
132 +       struct hotplug2_event_t *next;
133  };
134  
135  struct options_t {