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.
This commit is contained in:
parent
a0166609f7
commit
91b14d6ff3
|
@ -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;
|
||||
}
|
||||
|
||||
if (s->manager->current_dns_server == s)
|
||||
manager_set_dns_server(s->manager, NULL);
|
||||
}
|
||||
static DnsServer* dns_server_free(DnsServer *s) {
|
||||
if (!s)
|
||||
return 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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] = {
|
||||
|
|
Loading…
Reference in New Issue