]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: use reference counting for DnsQueryCandidate objects 18407/head
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 29 Jan 2021 15:21:08 +0000 (16:21 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 29 Jan 2021 16:14:15 +0000 (17:14 +0100)
Follow-up for 4ea8b443de. The logic that manages DnsQueryCandidate is rather
complicated: a calls to dns_query_complete() that wants to destroy a
DnsQueryCandidate can be nested inside a deep chain of calls. Using reference
counts seems like the simplest approach.

DnsSearchDomain already uses reference counting.

This patch effectively brings dns_query_candidate_go() to the state before
4ea8b443de, but wraps the iteration over DnsQueryCandidate.transactions in
dns_query_candidate_ref+dns_query_candidate_unref.

src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-query.h
src/resolve/resolved-dns-scope.c

index d10a2db9c298407174c5e042cde9022188eadb15..8ee4fd8309348647d86d0c68204686e42d7daf51 100644 (file)
@@ -26,6 +26,7 @@ static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScop
                 return -ENOMEM;
 
         *c = (DnsQueryCandidate) {
+                .n_ref = 1,
                 .query = q,
                 .scope = s,
         };
@@ -49,7 +50,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
         }
 }
 
-DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
+static DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
         if (!c)
                 return NULL;
 
@@ -67,6 +68,8 @@ DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {
         return mfree(c);
 }
 
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(DnsQueryCandidate, dns_query_candidate, dns_query_candidate_free);
+
 static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) {
         DnsSearchDomain *next;
 
@@ -129,14 +132,15 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource
 }
 
 static int dns_query_candidate_go(DnsQueryCandidate *c) {
+        _cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *keep_c = NULL;
         DnsTransaction *t;
         int r;
         unsigned n = 0;
-        bool notify = false;
 
         assert(c);
 
-        c->query->block_ready++;
+        /* Let's keep a reference to the query while we're operating */
+        keep_c = dns_query_candidate_ref(c);
 
         /* Start the transactions that are not started yet */
         SET_FOREACH(t, c->transactions) {
@@ -144,21 +148,14 @@ static int dns_query_candidate_go(DnsQueryCandidate *c) {
                         continue;
 
                 r = dns_transaction_go(t);
-                if (r < 0) {
-                        c->query->block_ready--;
+                if (r < 0)
                         return r;
-                }
-                if (r == 0)
-                        /* A transaction is complete. */
-                        notify = true;
 
                 n++;
         }
 
-        c->query->block_ready--;
-
         /* If there was nothing to start, then let's proceed immediately */
-        if (n == 0 || notify)
+        if (n == 0)
                 dns_query_candidate_notify(c);
 
         return 0;
@@ -306,11 +303,11 @@ static void dns_query_stop(DnsQuery *q) {
                 dns_query_candidate_stop(c);
 }
 
-static void dns_query_free_candidates(DnsQuery *q) {
+static void dns_query_unref_candidates(DnsQuery *q) {
         assert(q);
 
         while (q->candidates)
-                dns_query_candidate_free(q->candidates);
+                dns_query_candidate_unref(q->candidates);
 }
 
 static void dns_query_reset_answer(DnsQuery *q) {
@@ -339,7 +336,7 @@ DnsQuery *dns_query_free(DnsQuery *q) {
                 LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q);
         }
 
-        dns_query_free_candidates(q);
+        dns_query_unref_candidates(q);
 
         dns_question_unref(q->question_idna);
         dns_question_unref(q->question_utf8);
@@ -514,7 +511,7 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) {
 }
 
 static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {
-        _cleanup_(dns_query_candidate_freep) DnsQueryCandidate *c = NULL;
+        _cleanup_(dns_query_candidate_unrefp) DnsQueryCandidate *c = NULL;
         int r;
 
         assert(q);
@@ -935,7 +932,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
         dns_question_unref(q->question_utf8);
         q->question_utf8 = TAKE_PTR(nq_utf8);
 
-        dns_query_free_candidates(q);
+        dns_query_unref_candidates(q);
         dns_query_reset_answer(q);
 
         q->state = DNS_TRANSACTION_NULL;
index 6aadf28a154444a972dd450aaae9d43e669e55eb..133076dbf071199b91c74023fa71aaa4afb397de 100644 (file)
@@ -16,12 +16,14 @@ typedef struct DnsStubListenerExtra DnsStubListenerExtra;
 #include "resolved-dns-transaction.h"
 
 struct DnsQueryCandidate {
+        unsigned n_ref;
+        int error_code;
+
         DnsQuery *query;
         DnsScope *scope;
 
         DnsSearchDomain *search_domain;
 
-        int error_code;
         Set *transactions;
 
         LIST_FIELDS(DnsQueryCandidate, candidates_by_query);
@@ -101,8 +103,9 @@ enum {
         DNS_QUERY_RESTARTED,
 };
 
-DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_free);
+DnsQueryCandidate* dns_query_candidate_ref(DnsQueryCandidate*);
+DnsQueryCandidate* dns_query_candidate_unref(DnsQueryCandidate*);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_unref);
 
 void dns_query_candidate_notify(DnsQueryCandidate *c);
 
index 298ce21ae3f6638aeaeae1339470c8b1d7d48647..d77e81ae3986d8f92adae43cdd8465dfea1c1696 100644 (file)
@@ -105,7 +105,7 @@ DnsScope* dns_scope_free(DnsScope *s) {
         dns_scope_abort_transactions(s);
 
         while (s->query_candidates)
-                dns_query_candidate_free(s->query_candidates);
+                dns_query_candidate_unref(s->query_candidates);
 
         hashmap_free(s->transactions_by_key);