static int manager_post_handler(sd_event_source *s, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
+ (void) manager_process_remove_requests(manager);
(void) manager_process_requests(manager);
(void) manager_clean_all(manager);
return 0;
(void) link_stop_engines(link, true);
m->request_queue = ordered_set_free(m->request_queue);
+ m->remove_request_queue = ordered_set_free(m->remove_request_queue);
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->new_wlan_ifindices = set_free(m->new_wlan_ifindices);
assert(manager);
+ /* Process only when no remove request is queued. */
+ if (!ordered_set_isempty(manager->remove_request_queue))
+ return 0;
+
manager->request_queued = false;
ORDERED_SET_FOREACH(req, manager->request_queue) {
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(request_type, RequestType);
+
+static RemoveRequest* remove_request_free(RemoveRequest *req) {
+ if (!req)
+ return NULL;
+
+ if (req->manager)
+ ordered_set_remove(req->manager->remove_request_queue, req);
+
+ if (req->unref_func)
+ req->unref_func(req->userdata);
+
+ link_unref(req->link);
+ sd_netlink_unref(req->netlink);
+ sd_netlink_message_unref(req->message);
+
+ return mfree(req);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(RemoveRequest*, remove_request_free);
+DEFINE_TRIVIAL_DESTRUCTOR(remove_request_destroy_callback, RemoveRequest, remove_request_free);
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ remove_request_hash_ops,
+ void,
+ trivial_hash_func,
+ trivial_compare_func,
+ remove_request_free);
+
+int remove_request_add(
+ Manager *manager,
+ Link *link,
+ void *userdata,
+ mfree_func_t unref_func,
+ sd_netlink *netlink,
+ sd_netlink_message *message,
+ remove_request_netlink_handler_t netlink_handler) {
+
+ _cleanup_(remove_request_freep) RemoveRequest *req = NULL;
+ int r;
+
+ assert(manager);
+ assert(userdata);
+ assert(netlink);
+ assert(message);
+
+ req = new(RemoveRequest, 1);
+ if (!req)
+ return -ENOMEM;
+
+ *req = (RemoveRequest) {
+ .link = link_ref(link), /* link may be NULL, but link_ref() handles it gracefully. */
+ .userdata = userdata,
+ .netlink = sd_netlink_ref(netlink),
+ .message = sd_netlink_message_ref(message),
+ .netlink_handler = netlink_handler,
+ };
+
+ r = ordered_set_ensure_put(&manager->remove_request_queue, &remove_request_hash_ops, req);
+ if (r < 0)
+ return r;
+ assert(r > 0);
+
+ req->manager = manager;
+ req->unref_func = unref_func;
+
+ TAKE_PTR(req);
+ return 0;
+}
+
+int manager_process_remove_requests(Manager *manager) {
+ RemoveRequest *req;
+ int r;
+
+ assert(manager);
+
+ while ((req = ordered_set_first(manager->remove_request_queue))) {
+
+ /* Do not make the reply callback queue in sd-netlink full. */
+ if (netlink_get_reply_callback_count(req->netlink) >= REPLY_CALLBACK_COUNT_THRESHOLD)
+ return 0;
+
+ r = netlink_call_async(
+ req->netlink, NULL, req->message,
+ req->netlink_handler,
+ remove_request_destroy_callback,
+ req);
+ if (r < 0) {
+ _cleanup_(link_unrefp) Link *link = link_ref(req->link);
+
+ log_link_warning_errno(link, r, "Failed to call netlink message: %m");
+
+ /* First free the request. */
+ remove_request_free(req);
+
+ /* Then, make the link enter the failed state. */
+ if (link)
+ link_enter_failed(link);
+
+ } else {
+ /* On success, netlink needs to be unref()ed. Otherwise, the netlink and remove
+ * request may not freed on shutting down. */
+ req->netlink = sd_netlink_unref(req->netlink);
+ ordered_set_remove(manager->remove_request_queue, req);
+ }
+ }
+
+ return 0;
+}
int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req);
const char* request_type_to_string(RequestType t) _const_;
+
+typedef struct RemoveRequest RemoveRequest;
+typedef int (*remove_request_netlink_handler_t)(sd_netlink *nl, sd_netlink_message *m, RemoveRequest *req);
+
+struct RemoveRequest {
+ Manager *manager;
+ Link *link;
+ void *userdata; /* e.g. Address */
+ mfree_func_t unref_func; /* e.g. address_unref() */
+ sd_netlink *netlink;
+ sd_netlink_message *message;
+ remove_request_netlink_handler_t netlink_handler;
+};
+
+int remove_request_add(
+ Manager *manager,
+ Link *link,
+ void *userdata, /* This is unref()ed when the call failed. */
+ mfree_func_t unref_func,
+ sd_netlink *netlink,
+ sd_netlink_message *message,
+ remove_request_netlink_handler_t netlink_handler);
+
+#define _remove_request_add(manager, link, data, name, nl, m, handler) \
+ ({ \
+ typeof(*data) *_data = (data); \
+ int _r; \
+ \
+ _r = remove_request_add(manager, link, _data, \
+ (mfree_func_t) name##_unref, \
+ nl, m, handler); \
+ if (_r >= 0) \
+ name##_ref(_data); \
+ _r; \
+ })
+
+
+#define link_remove_request_add(link, data, name, nl, m, handler) \
+ ({ \
+ Link *_link = (link); \
+ \
+ _remove_request_add(_link->manager, _link, data, name, \
+ nl, m, handler); \
+ })
+
+#define manager_remove_request_add(manager, data, name, nl, m, handler) \
+ _remove_request_add(manager, NULL, data, name, nl, m, handler)
+
+int manager_process_remove_requests(Manager *manager);