diff options
author | Tom Gundersen <teg@jklm.no> | 2015-06-24 18:41:46 +0200 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2015-07-14 12:03:04 +0200 |
commit | 91b14d6ff362b938a72db17b095ee9903d07381b (patch) | |
tree | ac16392fcde03fa1732b80e82c5ad2359f22d1d6 /src/resolve | |
parent | a0166609f782da91710dea9183d1bf138538db37 (diff) |
resolved: reference count the dns servers
We want to reference the servers from their active transactions, so make sure
they stay around as long as the transaction does.
Diffstat (limited to 'src/resolve')
-rw-r--r-- | src/resolve/resolved-dns-server.c | 44 | ||||
-rw-r--r-- | src/resolve/resolved-dns-server.h | 5 | ||||
-rw-r--r-- | src/resolve/resolved-link.c | 23 | ||||
-rw-r--r-- | src/resolve/resolved-manager.c | 32 |
4 files changed, 73 insertions, 31 deletions
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 9a62a63258..92e48ae442 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -41,6 +41,7 @@ int dns_server_new( if (!s) return -ENOMEM; + s->n_ref = 1; s->type = type; s->family = family; s->address = *in_addr; @@ -74,33 +75,46 @@ int dns_server_new( return 0; } -DnsServer* dns_server_free(DnsServer *s) { +DnsServer* dns_server_ref(DnsServer *s) { if (!s) return NULL; - if (s->link) { - if (s->type == DNS_SERVER_LINK) - LIST_REMOVE(servers, s->link->dns_servers, s); + assert(s->n_ref > 0); - if (s->link->current_dns_server == s) - link_set_dns_server(s->link, NULL); - } + s->n_ref ++; - if (s->manager) { - if (s->type == DNS_SERVER_SYSTEM) - LIST_REMOVE(servers, s->manager->dns_servers, s); - else if (s->type == DNS_SERVER_FALLBACK) - LIST_REMOVE(servers, s->manager->fallback_dns_servers, s); + return s; +} + +static DnsServer* dns_server_free(DnsServer *s) { + if (!s) + return NULL; - if (s->manager->current_dns_server == s) - manager_set_dns_server(s->manager, NULL); - } + if (s->link && s->link->current_dns_server == s) + link_set_dns_server(s->link, NULL); + + if (s->manager && s->manager->current_dns_server == s) + manager_set_dns_server(s->manager, NULL); free(s); return NULL; } +DnsServer* dns_server_unref(DnsServer *s) { + if (!s) + return NULL; + + assert(s->n_ref > 0); + + if (s->n_ref == 1) + dns_server_free(s); + else + s->n_ref --; + + return NULL; +} + static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { const DnsServer *s = p; uint64_t u; diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 70ff35b08f..03013beb82 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -37,6 +37,8 @@ typedef enum DnsServerType { struct DnsServer { Manager *manager; + unsigned n_ref; + DnsServerType type; Link *link; @@ -57,6 +59,7 @@ int dns_server_new( int family, const union in_addr_union *address); -DnsServer* dns_server_free(DnsServer *s); +DnsServer* dns_server_ref(DnsServer *s); +DnsServer* dns_server_unref(DnsServer *s); extern const struct hash_ops dns_server_hash_ops; diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index ff8dc3a5bc..d66b3a88fc 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -58,7 +58,6 @@ int link_new(Manager *m, Link **ret, int ifindex) { } Link *link_free(Link *l) { - if (!l) return NULL; @@ -68,8 +67,12 @@ Link *link_free(Link *l) { if (l->manager) hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex)); - while (l->dns_servers) - dns_server_free(l->dns_servers); + while (l->dns_servers) { + DnsServer *s = l->dns_servers; + + LIST_REMOVE(servers, l->dns_servers, s); + dns_server_unref(s); + } dns_scope_free(l->unicast_scope); dns_scope_free(l->llmnr_ipv4_scope); @@ -182,14 +185,20 @@ static int link_update_dns_servers(Link *l) { } LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers) - if (s->marked) - dns_server_free(s); + if (s->marked) { + LIST_REMOVE(servers, l->dns_servers, s); + dns_server_unref(s); + } return 0; clear: - while (l->dns_servers) - dns_server_free(l->dns_servers); + while (l->dns_servers) { + s = l->dns_servers; + + LIST_REMOVE(servers, l->dns_servers, s); + dns_server_unref(s); + } return r; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 6785a2e3c7..e050092a12 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -603,8 +603,10 @@ int manager_read_resolv_conf(Manager *m) { } LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers) - if (s->marked) - dns_server_free(s); + if (s->marked) { + LIST_REMOVE(servers, m->dns_servers, s); + dns_server_unref(s); + } /* Whenever /etc/resolv.conf changes, start using the first * DNS server of it. This is useful to deal with broken @@ -619,8 +621,12 @@ int manager_read_resolv_conf(Manager *m) { return 0; clear: - while (m->dns_servers) - dns_server_free(m->dns_servers); + while (m->dns_servers) { + s = m->dns_servers; + + LIST_REMOVE(servers, m->dns_servers, s); + dns_server_unref(s); + } return r; } @@ -1381,15 +1387,25 @@ void manager_verify_all(Manager *m) { } void manager_flush_dns_servers(Manager *m, DnsServerType t) { + DnsServer *s; + assert(m); if (t == DNS_SERVER_SYSTEM) - while (m->dns_servers) - dns_server_free(m->dns_servers); + while (m->dns_servers) { + s = m->dns_servers; + + LIST_REMOVE(servers, m->dns_servers, s); + dns_server_unref(s); + } if (t == DNS_SERVER_FALLBACK) - while (m->fallback_dns_servers) - dns_server_free(m->fallback_dns_servers); + while (m->fallback_dns_servers) { + s = m->fallback_dns_servers; + + LIST_REMOVE(servers, m->fallback_dns_servers, s); + dns_server_unref(s); + } } static const char* const support_table[_SUPPORT_MAX] = { |