From 49fc819889fb6151c8fa7ee2684dad50d6726838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz> Date: Tue, 8 Apr 2014 14:46:54 +0200 Subject: [PATCH] ddns: excluded ddns/zone discard, release the zone after the ddns lock --- src/knot/nameserver/update.c | 30 ++++++++++++++++++------------ src/knot/server/zone-load.c | 2 -- src/knot/zone/zonedb.c | 6 +++++- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index ac3b18c13..afa4e8199 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -142,6 +142,12 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata) return NS_PROC_FAIL; } + /* Check if the zone is not discarded. */ + if (zone->flags & ZONE_DISCARDED) { + pthread_mutex_unlock(&zone->ddns_lock); + return NS_PROC_FAIL; + } + struct timeval t_start = {0}, t_end = {0}; gettimeofday(&t_start, NULL); UPDATE_LOG(LOG_INFO, "Started (serial %u).", knot_zone_serial(qdata->zone->contents)); @@ -149,10 +155,22 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata) /* Reserve space for TSIG. */ knot_pkt_reserve(pkt, tsig_wire_maxsize(qdata->sign.tsig_key)); + /* Retain zone for the whole processing so it doesn't disappear + * for example during reload. + * @note This is going to be fixed when this is made a zone event. */ + zone_retain(zone); + /* Process UPDATE. */ + rcu_read_unlock(); int ret = update_process(pkt, qdata); + rcu_read_lock(); + /* Since we unlocked RCU read lock, it is possible that the + * zone was modified/removed in the background. Therefore, + * we must NOT touch the zone after we release it here. */ pthread_mutex_unlock(&zone->ddns_lock); + zone_release(zone); + qdata->zone = NULL; /* Evaluate */ switch(ret) { @@ -335,7 +353,6 @@ static int zones_process_update_auth(struct query_data *qdata) } // Apply changeset to zone created by DDNS processing - if (zone_config->dnssec_enable) { /*! * Check if the UPDATE changed DNSKEYs. If yes, resign the whole @@ -436,10 +453,7 @@ static int zones_process_update_auth(struct query_data *qdata) } // Switch zone contents. - zone_retain(zone); /* Retain pointer for safe RCU unlock. */ - rcu_read_unlock(); /* Unlock for switch. */ ret = xfrin_switch_zone(zone, new_contents, XFR_TYPE_UPDATE); - rcu_read_lock(); /* Relock */ if (ret != KNOT_EOK) { log_zone_error("%s: Failed to replace current zone (%s)\n", msg, knot_strerror(ret)); @@ -449,8 +463,6 @@ static int zones_process_update_auth(struct query_data *qdata) /* Free changesets, but not the data. */ zones_free_merged_changesets(chgsets, sec_chs); - zone_release(zone); - qdata->zone = NULL; return KNOT_ERROR; } @@ -479,12 +491,6 @@ static int zones_process_update_auth(struct query_data *qdata) zones_schedule_zonefile_sync(zone, 0); } - /* Since we unlocked RCU read lock, it is possible that the - * zone was modified/removed in the background. Therefore, - * we must NOT touch the zone after we release it here. */ - zone_release(zone); - qdata->zone = NULL; - return ret; } diff --git a/src/knot/server/zone-load.c b/src/knot/server/zone-load.c index 919d20071..226df6502 100644 --- a/src/knot/server/zone-load.c +++ b/src/knot/server/zone-load.c @@ -519,8 +519,6 @@ static int remove_old_zonedb(const knot_zonedb_t *db_new, knot_zonedb_t *db_old) knot_zonedb_iter_next(&it); } - synchronize_rcu(); - /* Delete all deprecated zones and delete the old database. */ knot_zonedb_deep_free(&db_old); diff --git a/src/knot/zone/zonedb.c b/src/knot/zone/zonedb.c index e152a6e0d..4915969bb 100644 --- a/src/knot/zone/zonedb.c +++ b/src/knot/zone/zonedb.c @@ -40,8 +40,12 @@ /*! \brief Discard zone in zone database. */ static void discard_zone(zone_t *zone) { - synchronize_rcu(); + /* @note Exclude DDNS. */ + pthread_mutex_lock(&zone->ddns_lock); zone->flags |= ZONE_DISCARDED; + pthread_mutex_unlock(&zone->ddns_lock); + /* Wait for current operations. */ + synchronize_rcu(); zone_release(zone); } -- GitLab