From b226d99b044222739dccfa9cf9f7a9d79576c407 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Thu, 8 May 2014 19:46:06 +0200 Subject: [PATCH] networkd: link - take refcounts on links We need to take a refcount on the link whenever we expect a callback. The exceptions are the ipv4ll/dhcp clients as their lifetimes are guaranteed to be shorter than that of the link. --- src/network/networkd-link.c | 97 +++++++++++++++++++++++++++++------ src/network/networkd-netdev.c | 8 ++- 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 525fe1442..e3fb09494 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -236,8 +236,10 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { link->route_messages --; - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) @@ -254,6 +256,8 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { link_enter_configured(link); } + link_unref(link); + return 1; } @@ -282,6 +286,7 @@ static int link_enter_set_routes(Link *link) { return r; } + link_ref(link); link->route_messages ++; } @@ -316,6 +321,7 @@ static int link_enter_set_routes(Link *link) { return r; } + link_ref(link); link->route_messages ++; } } @@ -361,6 +367,7 @@ static int link_enter_set_routes(Link *link) { return r; } + link_ref(link); link->route_messages ++; route->family = AF_INET; @@ -374,6 +381,7 @@ static int link_enter_set_routes(Link *link) { return r; } + link_ref(link); link->route_messages ++; } } @@ -393,8 +401,10 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) assert(link); assert(link->ifname); - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -ENOENT) @@ -404,6 +414,8 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) "ERRNO=%d", -r, NULL); + link_unref(link); + return 0; } @@ -419,8 +431,10 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { link->addr_messages --; - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) @@ -435,6 +449,8 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { link_enter_set_routes(link); } + link_unref(link); + return 1; } @@ -463,6 +479,7 @@ static int link_enter_set_addresses(Link *link) { return r; } + link_ref(link); link->addr_messages ++; } @@ -498,6 +515,7 @@ static int link_enter_set_addresses(Link *link) { return r; } + link_ref(link); link->addr_messages ++; } } @@ -544,6 +562,7 @@ static int link_enter_set_addresses(Link *link) { return r; } + link_ref(link); link->addr_messages ++; } @@ -558,8 +577,10 @@ static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd assert(link); assert(link->ifname); - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -ENOENT) @@ -569,6 +590,8 @@ static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd "ERRNO=%d", -r, NULL); + link_unref(link); + return 0; } @@ -580,8 +603,10 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat assert(link); assert(link->ifname); - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -ENOENT) @@ -591,34 +616,43 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat "ERRNO=%d", -r, NULL); + link_unref(link); + return 0; } static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + Link *link = userdata; int r; + assert(link); + r = sd_bus_message_get_errno(m); if (r < 0) log_warning("Could not set hostname: %s", strerror(-r)); + link_unref(link); + return 1; } -static int set_hostname(sd_bus *bus, const char *hostname) { +static int link_set_hostname(Link *link, const char *hostname) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; int r = 0; + assert(link); + assert(link->manager); assert(hostname); - log_debug("Setting transient hostname: '%s'", hostname); + log_debug_link(link, "Setting transient hostname: '%s'", hostname); - if (!bus) { /* TODO: replace by assert when we can rely on kdbus */ - log_info("Not connected to system bus, ignoring transient hostname."); + if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */ + log_info_link(link, "Not connected to system bus, ignoring transient hostname."); return 0; } r = sd_bus_message_new_method_call( - bus, + link->manager->bus, &m, "org.freedesktop.hostname1", "/org/freedesktop/hostname1", @@ -631,9 +665,11 @@ static int set_hostname(sd_bus *bus, const char *hostname) { if (r < 0) return r; - r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL); + r = sd_bus_call_async(link->manager->bus, m, set_hostname_handler, link, 0, NULL); if (r < 0) - log_error("Could not set transient hostname: %s", strerror(-r)); + log_error_link(link, "Could not set transient hostname: %s", strerror(-r)); + + link_ref(link); return r; } @@ -646,8 +682,10 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { assert(link); assert(link->ifname); - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0) @@ -657,6 +695,8 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { "ERRNO=%d", -r, NULL); + link_unref(link); + return 1; } @@ -690,6 +730,8 @@ static int link_set_mtu(Link *link, uint32_t mtu) { return r; } + link_unref(link); + return 0; } @@ -720,6 +762,7 @@ static int dhcp_lease_lost(Link *link) { route_gw->scope = RT_SCOPE_LINK; route_drop(route_gw, link, &route_drop_handler); + link_ref(link); } r = route_new_dynamic(&route); @@ -728,6 +771,7 @@ static int dhcp_lease_lost(Link *link) { route->in_addr.in = gateway; route_drop(route, link, &route_drop_handler); + link_ref(link); } } @@ -740,6 +784,7 @@ static int dhcp_lease_lost(Link *link) { address->prefixlen = prefixlen; address_drop(address, link, &address_drop_handler); + link_ref(link); } if (link->network->dhcp_mtu) { @@ -761,7 +806,7 @@ static int dhcp_lease_lost(Link *link) { r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); if (r >= 0 && hostname) { - r = set_hostname(link->manager->bus, ""); + r = link_set_hostname(link, ""); if (r < 0) log_error("Failed to reset transient hostname"); } @@ -868,7 +913,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { r = sd_dhcp_lease_get_hostname(lease, &hostname); if (r >= 0) { - r = set_hostname(link->manager->bus, hostname); + r = link_set_hostname(link, hostname); if (r < 0) log_error("Failed to set transient hostname " "to '%s'", hostname); @@ -988,6 +1033,7 @@ static int ipv4ll_address_update(Link *link, bool deprecate) { address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen); address_update(address, link, &address_update_handler); + link_ref(link); } return 0; @@ -1020,6 +1066,7 @@ static int ipv4ll_address_lost(Link *link) { address->scope = RT_SCOPE_LINK; address_drop(address, link, &address_drop_handler); + link_ref(link); r = route_new_dynamic(&route); if (r < 0) { @@ -1033,6 +1080,7 @@ static int ipv4ll_address_lost(Link *link) { route->metrics = 99; route_drop(route, link, &route_drop_handler); + link_ref(link); } return 0; @@ -1287,8 +1335,10 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { assert(link); - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0) { @@ -1301,6 +1351,8 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { NULL); } + link_unref(link); + return 1; } @@ -1334,6 +1386,8 @@ static int link_up(Link *link) { return r; } + link_ref(link); + return 0; } @@ -1368,8 +1422,10 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { link->enslaving --; - if (link->state == LINK_STATE_FAILED) + if (link->state == LINK_STATE_FAILED) { + link_unref(link); return 1; + } r = sd_rtnl_message_get_errno(m); if (r < 0) { @@ -1379,6 +1435,7 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { "ERRNO=%d", -r, NULL); link_enter_failed(link); + link_unref(link); return 1; } @@ -1387,6 +1444,8 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { if (link->enslaving == 0) link_enslaved(link); + link_unref(link); + return 1; } @@ -1426,6 +1485,7 @@ static int link_enter_enslave(Link *link) { return r; } + link_ref(link); link->enslaving ++; } @@ -1447,6 +1507,7 @@ static int link_enter_enslave(Link *link) { return r; } + link_ref(link); link->enslaving ++; } @@ -1465,6 +1526,7 @@ static int link_enter_enslave(Link *link) { return r; } + link_ref(link); link->enslaving ++; } @@ -1483,6 +1545,7 @@ static int link_enter_enslave(Link *link) { return r; } + link_ref(link); link->enslaving ++; } diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 961404295..5ee257f98 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -168,7 +168,7 @@ static int netdev_enter_ready(NetDev *netdev) { log_info_netdev(netdev, "netdev ready"); LIST_FOREACH(callbacks, callback, netdev->callbacks) { - /* enslave the links that were attempted to be enslaved befor the + /* enslave the links that were attempted to be enslaved before the * link was ready */ netdev_enslave_ready(netdev, callback->link, callback->callback); } @@ -308,11 +308,15 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c } int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { + int r; + if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) return netdev_create(netdev, link, callback); if (netdev->state == NETDEV_STATE_READY) { - netdev_enslave_ready(netdev, link, callback); + r = netdev_enslave_ready(netdev, link, callback); + if (r < 0) + return r; } else { /* the netdev is not yet read, save this request for when it is*/ netdev_enslave_callback *cb; -- 2.30.2