summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-queue.c
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2024-01-16 05:50:23 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2024-01-16 15:25:32 +0100
commite30dc59c2e2b87f5bbfaffd2e98de5caf3b18c28 (patch)
tree277bbfa6ad3f30593c8f5e02d134a748f2f3d63e /src/network/networkd-queue.c
parentMerge pull request #30953 from yuwata/network-nexthop-silently-removed-by-kernel (diff)
downloadsystemd-e30dc59c2e2b87f5bbfaffd2e98de5caf3b18c28.tar.xz
systemd-e30dc59c2e2b87f5bbfaffd2e98de5caf3b18c28.zip
network/queue: increase the reference counter of the request before processing it
To prevent the request freed in req->process(). This also makes a request that is not requested by a link detached on failure. Otherwise, the request may periodically processed and failed forever.
Diffstat (limited to '')
-rw-r--r--src/network/networkd-queue.c42
1 files changed, 20 insertions, 22 deletions
diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c
index 0b89ec9736..d1e9fec57a 100644
--- a/src/network/networkd-queue.c
+++ b/src/network/networkd-queue.c
@@ -231,42 +231,40 @@ int manager_process_requests(Manager *manager) {
manager->request_queued = false;
ORDERED_SET_FOREACH(req, manager->request_queue) {
- _cleanup_(link_unrefp) Link *link = link_ref(req->link);
-
- assert(req->process);
-
if (req->waiting_reply)
- continue; /* Waiting for netlink reply. */
+ continue; /* Already processed, and waiting for netlink reply. */
/* Typically, requests send netlink message asynchronously. If there are many requests
* queued, then this event may make reply callback queue in sd-netlink full. */
if (netlink_get_reply_callback_count(manager->rtnl) >= REPLY_CALLBACK_COUNT_THRESHOLD ||
netlink_get_reply_callback_count(manager->genl) >= REPLY_CALLBACK_COUNT_THRESHOLD ||
fw_ctx_get_reply_callback_count(manager->fw_ctx) >= REPLY_CALLBACK_COUNT_THRESHOLD)
- return 0;
+ break;
- r = req->process(req, link, req->userdata);
- if (r == 0) { /* The request is not ready. */
- if (manager->request_queued)
- break; /* a new request is queued during processing the request. */
- continue;
- }
+ /* Avoid the request and link freed by req->process() and request_detach(). */
+ _unused_ _cleanup_(request_unrefp) Request *req_unref = request_ref(req);
+ _cleanup_(link_unrefp) Link *link = link_ref(req->link);
- /* If the request sends netlink message, e.g. for Address or so, the Request object is
- * referenced by the netlink slot, and will be detached later by its destroy callback.
- * Otherwise, e.g. for DHCP client or so, detach the request from queue now. */
- if (!req->waiting_reply)
+ assert(req->process);
+ r = req->process(req, link, req->userdata);
+ if (r < 0) {
request_detach(manager, req);
- if (r < 0 && link) {
- link_enter_failed(link);
- /* link_enter_failed() may remove multiple requests,
- * hence we need to exit from the loop. */
- break;
+ if (link) {
+ link_enter_failed(link);
+ /* link_enter_failed() may detach multiple requests from the queue.
+ * Hence, we need to exit from the loop. */
+ break;
+ }
}
+ if (r > 0 && !req->waiting_reply)
+ /* If the request sends netlink message, e.g. for Address or so, the Request object is
+ * referenced by the netlink slot, and will be detached later by its destroy callback.
+ * Otherwise, e.g. for DHCP client or so, detach the request from queue now. */
+ request_detach(manager, req);
if (manager->request_queued)
- break;
+ break; /* New request is queued. Exit from the loop. */
}
return 0;