diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-16 05:50:23 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-16 15:25:32 +0100 |
commit | e30dc59c2e2b87f5bbfaffd2e98de5caf3b18c28 (patch) | |
tree | 277bbfa6ad3f30593c8f5e02d134a748f2f3d63e /src/network/networkd-queue.c | |
parent | Merge pull request #30953 from yuwata/network-nexthop-silently-removed-by-kernel (diff) | |
download | systemd-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.c | 42 |
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; |