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 | |
| 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.
| -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] = { | 
