1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup dnsdbzone Zone related functions
36  *  @ingroup dnsdb
37  *  @brief Functions used to manipulate a zone
38  *
39  *  Functions used to manipulate a zone
40  *
41  * @{
42  */
43 
44 #include "dnsdb/dnsdb-config.h"
45 #include "dnsdb/zdb-config-features.h"
46 #include <unistd.h>
47 #include <arpa/inet.h>
48 
49 #if DEBUG
50 #include <dnscore/format.h>
51 #endif
52 
53 #include <dnscore/mutex.h>
54 
55 #include <dnscore/dnscore.h>
56 
57 #include <dnscore/logger.h>
58 
59 #include "dnsdb/zdb.h"
60 
61 #include "dnsdb/zdb_zone.h"
62 #include "dnsdb/zdb-zone-garbage.h"
63 #include "dnsdb/zdb_zone_label.h"
64 #include "dnsdb/zdb_rr_label.h"
65 #include "dnsdb/zdb_record.h"
66 
67 #include "dnsdb/zdb_utils.h"
68 #include "dnsdb/zdb_error.h"
69 
70 #include "dnsdb/dnsrdata.h"
71 
72 #if ZDB_HAS_NSEC_SUPPORT
73 #include "dnsdb/nsec.h"
74 #endif
75 #if ZDB_HAS_NSEC3_SUPPORT
76 #include "dnsdb/nsec3.h"
77 #endif
78 
79 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
80 #include "dnsdb/zdb-zone-lock-monitor.h"
81 #endif
82 
83 #if DEBUG
84 #define ZONE_MUTEX_LOG 0        // set this to 0 to disable in DEBUG
85 #define DEBUG_ARC 0             // set this to 0 do disable in DEBUG
86 #else
87 #define ZONE_MUTEX_LOG 0        // never enable if not in DEBUG
88 #define DEBUG_ARC 0             // never enable if not in DEBUG
89 #endif
90 
91 extern logger_handle* g_database_logger;
92 #define MODULE_MSG_HANDLE g_database_logger
93 
94 #if DEBUG_ARC
95 
zdb_zone_change_rc(zdb_zone * zone,s32 n,const char * txt)96 static inline bool zdb_zone_change_rc(zdb_zone *zone, s32 n, const char * txt)
97 {
98     char prefix[64];
99     int old_rc = zone->rc;
100     int new_rc = old_rc + n;
101     log_debug7("%s: %p going from %i to %i", txt, zone, old_rc, new_rc);
102     snformat(prefix, sizeof(prefix), "%s: %p", txt, zone);
103     debug_log_stacktrace(g_database_logger, MSG_DEBUG7, prefix);
104 
105     if(new_rc < 0)
106     {
107         abort();
108     }
109 
110     zone->rc = new_rc;
111 
112     if(new_rc == 0)
113     {
114         log_debug7("%s: good for the garbage", txt);
115     }
116 
117     return new_rc == 0;
118 }
119 
120 #define ZONE_RC_INC(zone_) zdb_zone_change_rc(zone_,  1, "rc++")
121 #define ZONE_RC_DEC(zone_) zdb_zone_change_rc(zone_, -1, "rc--")
122 
123 #else
124 
125 #define ZONE_RC_INC(zone_) (++(zone_)->rc)
126 #define ZONE_RC_DEC(zone_) ((--(zone_)->rc) == 0)
127 
128 #endif
129 
130 /**
131  *
132  * Locks the database
133  * Gets the zone
134  * Starts locking the zone for the owner
135  * Increment the zone RC
136  * Unlocks the database
137  * Resume locking the zone for the owner
138  * returns the locked zone
139  *
140  * @param db
141  * @param exact_match_origin
142  * @param owner
143  * @return
144  */
145 
146 static inline zdb_zone *
zdb_acquire_zone_resume_lock_from_label(zdb * db,const zdb_zone_label * label,u8 owner,u8 db_locktype)147 zdb_acquire_zone_resume_lock_from_label(zdb *db, const zdb_zone_label *label, u8 owner, u8 db_locktype)
148 {
149     yassert(zdb_islocked(db));
150 
151     if(label != NULL && label->zone != NULL)
152     {
153         zdb_zone *zone = label->zone;
154         mutex_t *mutex = &zone->lock_mutex;
155         mutex_lock(mutex);
156         zdb_unlock(db, db_locktype);
157 
158         ZONE_RC_INC(zone);
159 
160 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
161         struct zdb_zone_lock_monitor *holder = zdb_zone_lock_monitor_new(zone, owner, 0);
162 #endif
163 
164         for(;;)
165         {
166             /*
167                 A simple way to ensure that a lock can be shared
168                 by similar entities or not.
169                 Sharable entities have their msb off.
170             */
171 
172             u8 co = zone->lock_owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
173 
174             if(co == GROUP_MUTEX_NOBODY || co == owner)
175             {
176                 yassert(!SIGNED_VAR_VALUE_IS_MAX(zone->lock_count));
177 
178                 zone->lock_owner = owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
179                 zone->lock_count++;
180 
181 #if ZDB_ZONE_LOCK_HAS_OWNER_ID // if the owner changes, update the owning thread
182                 if(zone->lock_last_owner_id == 0)
183                 {
184                     zone->lock_last_owner_id = thread_self();
185                 }
186 #endif
187                 break;
188             }
189 
190 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
191             zdb_zone_lock_monitor_waits(holder);
192 #endif
193 
194             cond_wait(&zone->lock_cond, mutex);
195 
196 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
197             zdb_zone_lock_monitor_resumes(holder);
198 #endif
199         }
200 
201 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
202         zdb_zone_lock_monitor_locks(holder);
203 #endif
204 
205         mutex_unlock(mutex);
206 
207         return zone;
208     }
209     else
210     {
211         zdb_unlock(db, db_locktype);
212 
213         return NULL;
214     }
215 }
216 
217 static inline zdb_zone *
zdb_acquire_zone_resume_trylock_from_label(zdb * db,const zdb_zone_label * label,u8 owner,u8 db_locktype)218 zdb_acquire_zone_resume_trylock_from_label(zdb *db, const zdb_zone_label *label, u8 owner, u8 db_locktype)
219 {
220     yassert(zdb_islocked(db));
221 
222     if(label != NULL && label->zone != NULL)
223     {
224         zdb_zone *zone = label->zone;
225 
226         mutex_t *mutex = &zone->lock_mutex;
227 
228         mutex_lock(mutex);
229 
230         zdb_unlock(db, db_locktype);
231 
232 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
233         struct zdb_zone_lock_monitor *holder = zdb_zone_lock_monitor_new(zone, owner, 0);
234 #endif
235 
236         /*
237             A simple way to ensure that a lock can be shared
238             by similar entities or not.
239             Sharable entities have their msb off.
240         */
241 
242         u8 co = zone->lock_owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
243 
244         if(co == GROUP_MUTEX_NOBODY || co == owner)
245         {
246             yassert(!SIGNED_VAR_VALUE_IS_MAX(zone->lock_count));
247 
248             zone->lock_owner = owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
249             zone->lock_count++;
250 
251 #if ZDB_ZONE_LOCK_HAS_OWNER_ID // if the owner changes, update the owning thread
252             if(zone->lock_last_owner_id == 0)
253             {
254                 zone->lock_last_owner_id = thread_self();
255             }
256 #endif
257 
258             ZONE_RC_INC(zone);
259 
260 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
261             zdb_zone_lock_monitor_locks(holder);
262 #endif
263 
264             mutex_unlock(mutex);
265 
266             return zone;
267         }
268         else
269         {
270 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
271             zdb_zone_lock_monitor_cancels(holder);
272 #endif
273             mutex_unlock(mutex);
274 
275             return NULL;
276         }
277     }
278     else
279     {
280         zdb_unlock(db, db_locktype);
281 
282         return NULL;
283     }
284 }
285 
286 /**
287  * Internal.
288  * Second part of a double lock.
289  * Works on a locked DB.
290  * On success returns the double-locked zone.
291  * On error, unlocks the DB and return NULL.
292  *
293  * @param db
294  * @param label
295  * @param owner
296  * @param nextowner
297  * @param db_locktype
298  * @return
299  */
300 
301 static inline zdb_zone *
zdb_acquire_zone_resume_double_lock_from_label(zdb * db,const zdb_zone_label * label,u8 owner,u8 nextowner,u8 db_locktype)302 zdb_acquire_zone_resume_double_lock_from_label(zdb *db, const zdb_zone_label *label, u8 owner, u8 nextowner, u8 db_locktype)
303 {
304     yassert((owner & 0x80) == 0); // the new standard use
305 
306     yassert(zdb_islocked(db));
307 
308     if(label != NULL && label->zone != NULL)
309     {
310         zdb_zone *zone = label->zone;
311 
312         mutex_t *mutex = &zone->lock_mutex;
313 
314         mutex_lock(mutex);
315 
316         zdb_unlock(db, db_locktype);
317 
318         ZONE_RC_INC(zone);
319 
320 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
321         struct zdb_zone_lock_monitor *holder = zdb_zone_lock_monitor_new(zone, owner, nextowner);
322 #endif
323 
324         for(;;)
325         {
326             /*
327                 A simple way to ensure that a lock can be shared
328                 by similar entities or not.
329                 Sharable entities have their msb off.
330             */
331 
332             u8 so = zone->lock_reserved_owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
333 
334             if(so == ZDB_ZONE_MUTEX_NOBODY || so == nextowner)
335             {
336                 u8 co = zone->lock_owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
337 
338                 if(co == ZDB_ZONE_MUTEX_NOBODY || co == owner)
339                 {
340                     yassert(!SIGNED_VAR_VALUE_IS_MAX(zone->lock_count));
341 
342                     zone->lock_owner = owner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
343                     zone->lock_count++;
344                     zone->lock_reserved_owner = nextowner & ZDB_ZONE_MUTEX_LOCKMASK_FLAG;
345 
346 #if ZDB_ZONE_LOCK_HAS_OWNER_ID
347                     if(zone->lock_last_owner_id == 0)
348                     {
349                         zone->lock_last_owner_id = thread_self();
350                     }
351 #endif
352 
353 #if ZONE_MUTEX_LOG
354                     log_debug7("acquired lock for zone %{dnsname}@%p for %x (#%i)", zone->origin, zone, owner, zone->lock_count);
355 #endif
356                     break;
357                 }
358             }
359 
360 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
361             zdb_zone_lock_monitor_waits(holder);
362 #endif
363             cond_wait(&zone->lock_cond, mutex);
364 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
365             zdb_zone_lock_monitor_resumes(holder);
366 #endif
367         }
368 
369 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
370         zdb_zone_lock_monitor_locks(holder);
371 #endif
372 
373         mutex_unlock(mutex);
374 
375         return zone;
376     }
377     else
378     {
379         zdb_unlock(db, db_locktype);
380 
381         return NULL;
382     }
383 }
384 
385 zdb_zone *
zdb_acquire_zone_read(zdb * db,const dnsname_vector * exact_match_origin)386 zdb_acquire_zone_read(zdb *db, const dnsname_vector *exact_match_origin)
387 {
388     zdb_lock(db, ZDB_MUTEX_READER);
389 
390     const zdb_zone_label *label = zdb_zone_label_find(db, exact_match_origin);
391 
392     if(label != NULL && label->zone != NULL)
393     {
394         zdb_zone *zone = label->zone;
395 
396         mutex_t *mutex = &zone->lock_mutex;
397 
398         mutex_lock(mutex);
399 
400         zdb_unlock(db, ZDB_MUTEX_READER);
401 
402         ZONE_RC_INC(zone);
403 
404         mutex_unlock(mutex);
405 
406         return zone;
407     }
408     else
409     {
410         zdb_unlock(db, ZDB_MUTEX_READER);
411 
412         return NULL;
413     }
414 }
415 
416 zdb_zone *
zdb_acquire_zone_read_from_fqdn(zdb * db,const u8 * fqdn)417 zdb_acquire_zone_read_from_fqdn(zdb *db, const u8 *fqdn)
418 {
419     zdb_lock(db, ZDB_MUTEX_READER);
420 
421     zdb_zone_label *label = zdb_zone_label_find_from_dnsname(db, fqdn);
422 
423     if(label != NULL && label->zone != NULL)
424     {
425         zdb_zone *zone = label->zone;
426 
427         mutex_t *mutex = &zone->lock_mutex;
428 
429         mutex_lock(mutex);
430 
431         zdb_unlock(db, ZDB_MUTEX_READER);
432 
433         ZONE_RC_INC(zone);
434 
435         mutex_unlock(mutex);
436 
437         return zone;
438     }
439     else
440     {
441         zdb_unlock(db, ZDB_MUTEX_READER);
442 
443         return NULL;
444     }
445 }
446 
447 zdb_zone *
zdb_acquire_zone_read_trylock(zdb * db,dnsname_vector * exact_match_origin,u8 owner)448 zdb_acquire_zone_read_trylock(zdb *db, dnsname_vector *exact_match_origin, u8 owner)
449 {
450     zdb_lock(db, ZDB_MUTEX_READER);
451     zdb_zone_label *label = zdb_zone_label_find(db, exact_match_origin);
452     if(label != NULL)
453     {
454         zdb_zone *zone = zdb_acquire_zone_resume_trylock_from_label(db, label, owner, ZDB_MUTEX_READER);
455         return zone;
456     }
457 
458     zdb_unlock(db, ZDB_MUTEX_READER);
459     return NULL;
460 }
461 
462 zdb_zone *
zdb_acquire_zone_read_trylock_from_name(zdb * db,const char * name,u8 owner)463 zdb_acquire_zone_read_trylock_from_name(zdb *db, const char *name, u8 owner)
464 {
465     zdb_lock(db, ZDB_MUTEX_READER);
466     zdb_zone_label *label = zdb_zone_label_find_from_name(db, name);
467     if(label != NULL)
468     {
469         zdb_zone *zone = zdb_acquire_zone_resume_trylock_from_label(db, label, owner, ZDB_MUTEX_READER);
470         return zone;
471     }
472 
473     zdb_unlock(db, ZDB_MUTEX_READER);
474     return NULL;
475 }
476 
477 zdb_zone *
zdb_acquire_zone_read_trylock_from_fqdn(zdb * db,const u8 * fqdn,u8 owner)478 zdb_acquire_zone_read_trylock_from_fqdn(zdb *db, const u8 *fqdn, u8 owner)
479 {
480     zdb_lock(db, ZDB_MUTEX_READER);
481     zdb_zone_label *label = zdb_zone_label_find_from_dnsname(db, fqdn);
482     if(label != NULL)
483     {
484         zdb_zone *zone = zdb_acquire_zone_resume_trylock_from_label(db, label, owner, ZDB_MUTEX_READER);
485         return zone;
486     }
487 
488     zdb_unlock(db, ZDB_MUTEX_READER);
489     return NULL;
490 }
491 
492 zdb_zone *
zdb_acquire_zone_read_lock(zdb * db,dnsname_vector * exact_match_origin,u8 owner)493 zdb_acquire_zone_read_lock(zdb *db, dnsname_vector *exact_match_origin, u8 owner)
494 {
495     zdb_lock(db, ZDB_MUTEX_READER);
496     zdb_zone_label *label = zdb_zone_label_find(db, exact_match_origin);
497     if(label != NULL)
498     {
499         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_READER);
500         return zone;
501     }
502 
503     zdb_unlock(db, ZDB_MUTEX_READER);
504     return NULL;
505 }
506 
507 zdb_zone *
zdb_acquire_zone_read_lock_from_name(zdb * db,const char * name,u8 owner)508 zdb_acquire_zone_read_lock_from_name(zdb *db, const char *name, u8 owner)
509 {
510     zdb_lock(db, ZDB_MUTEX_READER);
511     zdb_zone_label *label = zdb_zone_label_find_from_name(db, name);
512     if(label != NULL)
513     {
514         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_READER);
515         return zone;
516     }
517 
518     zdb_unlock(db, ZDB_MUTEX_READER);
519     return NULL;
520 }
521 
522 zdb_zone *
zdb_acquire_zone_read_lock_from_fqdn(zdb * db,const u8 * fqdn,u8 owner)523 zdb_acquire_zone_read_lock_from_fqdn(zdb *db, const u8 *fqdn, u8 owner)
524 {
525     zdb_lock(db, ZDB_MUTEX_READER);
526     zdb_zone_label *label = zdb_zone_label_find_from_dnsname(db, fqdn);
527     if(label != NULL)
528     {
529         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_READER);
530         return zone;
531     }
532 
533     zdb_unlock(db, ZDB_MUTEX_READER);
534     return NULL;
535 }
536 
537 zdb_zone *
zdb_acquire_zone_write_lock(zdb * db,dnsname_vector * exact_match_origin,u8 owner)538 zdb_acquire_zone_write_lock(zdb *db, dnsname_vector *exact_match_origin, u8 owner)
539 {
540     zdb_lock(db, ZDB_MUTEX_WRITER);
541     zdb_zone_label *label = zdb_zone_label_find(db, exact_match_origin);
542     if(label != NULL)
543     {
544         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_WRITER);
545         return zone;
546     }
547 
548     zdb_unlock(db, ZDB_MUTEX_WRITER);
549     return NULL;
550 }
551 
552 zdb_zone *
zdb_acquire_zone_write_lock_from_name(zdb * db,const char * name,u8 owner)553 zdb_acquire_zone_write_lock_from_name(zdb *db, const char *name, u8 owner)
554 {
555     zdb_lock(db, ZDB_MUTEX_WRITER);
556     zdb_zone_label *label = zdb_zone_label_find_from_name(db, name);
557     if(label != NULL)
558     {
559         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_WRITER);
560         return zone;
561     }
562 
563     zdb_unlock(db, ZDB_MUTEX_WRITER);
564     return NULL;
565 }
566 
567 zdb_zone *
zdb_acquire_zone_write_lock_from_fqdn(zdb * db,const u8 * fqdn,u8 owner)568 zdb_acquire_zone_write_lock_from_fqdn(zdb *db, const u8 *fqdn, u8 owner)
569 {
570     zdb_lock(db, ZDB_MUTEX_WRITER);
571     zdb_zone_label *label = zdb_zone_label_find_from_dnsname(db, fqdn);
572     if(label != NULL)
573     {
574         zdb_zone *zone = zdb_acquire_zone_resume_lock_from_label(db, label, owner, ZDB_MUTEX_WRITER);
575         return zone;
576     }
577 
578     zdb_unlock(db, ZDB_MUTEX_WRITER);
579     return NULL;
580 }
581 
582 zdb_zone *
zdb_acquire_zone_read_double_lock(zdb * db,dnsname_vector * exact_match_origin,u8 owner,u8 nextowner)583 zdb_acquire_zone_read_double_lock(zdb *db, dnsname_vector *exact_match_origin, u8 owner, u8 nextowner)
584 {
585     zdb_lock(db, ZDB_MUTEX_READER);
586     zdb_zone_label *label = zdb_zone_label_find(db, exact_match_origin);
587     if(label != NULL)
588     {
589         zdb_zone *zone = zdb_acquire_zone_resume_double_lock_from_label(db, label, owner, nextowner, ZDB_MUTEX_READER);
590         return zone;
591     }
592 
593     zdb_unlock(db, ZDB_MUTEX_READER);
594     return NULL;
595 }
596 
597 zdb_zone *
zdb_acquire_zone_read_double_lock_from_name(zdb * db,const char * name,u8 owner,u8 nextowner)598 zdb_acquire_zone_read_double_lock_from_name(zdb *db, const char *name, u8 owner, u8 nextowner)
599 {
600     zdb_lock(db, ZDB_MUTEX_READER);
601     zdb_zone_label *label = zdb_zone_label_find_from_name(db, name);
602     if(label != NULL)
603     {
604         zdb_zone *zone = zdb_acquire_zone_resume_double_lock_from_label(db, label, owner, nextowner, ZDB_MUTEX_READER);
605         return zone;
606     }
607 
608     zdb_unlock(db, ZDB_MUTEX_READER);
609     return NULL;
610 }
611 
612 zdb_zone *
zdb_acquire_zone_read_double_lock_from_fqdn(zdb * db,const u8 * fqdn,u8 owner,u8 nextowner)613 zdb_acquire_zone_read_double_lock_from_fqdn(zdb *db, const u8 *fqdn, u8 owner, u8 nextowner)
614 {
615     zdb_lock(db, ZDB_MUTEX_READER);
616     zdb_zone_label *label = zdb_zone_label_find_from_dnsname(db, fqdn);
617     if(fqdn != NULL)
618     {
619         zdb_zone *zone = zdb_acquire_zone_resume_double_lock_from_label(db, label, owner, nextowner, ZDB_MUTEX_READER);
620         return zone;
621     }
622 
623     zdb_unlock(db, ZDB_MUTEX_READER);
624     return NULL;
625 }
626 
627 void
zdb_zone_acquire(zdb_zone * zone)628 zdb_zone_acquire(zdb_zone *zone)
629 {
630     mutex_lock(&zone->lock_mutex);
631 
632     ZONE_RC_INC(zone);
633 
634     mutex_unlock(&zone->lock_mutex);
635 }
636 /**
637  *
638  * Dereference and unlocks the zone.
639  * If the RC reached 0, enqueues it for destruction
640  *
641  * @param zone
642  * @param owner
643  */
644 
645 void
zdb_zone_release(zdb_zone * zone)646 zdb_zone_release(zdb_zone *zone)
647 {
648     mutex_lock(&zone->lock_mutex);
649 
650     if(ZONE_RC_DEC(zone))
651     {
652         if(!zdb_zone_garbage_collect(zone)) // zone mutex locked, as MUST be
653         {
654             // zone was not collected: it was destroyed
655             return;
656         }
657     }
658 
659     mutex_unlock(&zone->lock_mutex);
660 }
661 
662 void
zdb_zone_release_unlock(zdb_zone * zone,u8 owner)663 zdb_zone_release_unlock(zdb_zone *zone, u8 owner)
664 {
665 #if ZONE_MUTEX_LOG
666     log_debug7("releasing lock for zone %{dnsname}@%p by %x (owned by %x)", zone->origin, zone, owner, zone->lock_owner);
667 #else
668     (void)owner;
669 #endif
670 
671     mutex_lock(&zone->lock_mutex);
672 
673 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
674     struct zdb_zone_lock_monitor *holder = zdb_zone_lock_monitor_get(zone);
675 #endif
676 
677 #if DEBUG
678     if((zone->lock_owner != (owner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG)) || (zone->lock_count == 0))
679     {
680         mutex_unlock(&zone->lock_mutex);
681         yassert(zone->lock_owner == (owner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG));
682         yassert(zone->lock_count != 0);
683         abort(); // unreachable
684     }
685 #endif
686 
687     zone->lock_count--;
688 
689 #if ZONE_MUTEX_LOG
690     log_debug7("released lock for zone %{dnsname}@%p by %x (#%i)", zone->origin, zone, owner, zone->lock_count);
691 #endif
692 
693 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
694     zdb_zone_lock_monitor_unlocks(holder);
695 #endif
696 
697 #if ZDB_ZONE_LOCK_HAS_OWNER_ID
698     if(zone->lock_last_owner_id == thread_self())
699     {
700         zone->lock_last_owner_id = 0;
701     }
702 #endif
703 
704     if(zone->lock_count == 0)
705     {
706         zone->lock_owner = ZDB_ZONE_MUTEX_NOBODY;
707         cond_notify(&zone->lock_cond);
708     }
709 
710     if(ZONE_RC_DEC(zone))
711     {
712         if(!zdb_zone_garbage_collect(zone)) // zone mutex locked, as MUST be
713         {
714             // zone was not collected: it was destroyed
715             return;
716         }
717     }
718 
719     cond_notify(&zone->lock_cond);
720     mutex_unlock(&zone->lock_mutex);
721 }
722 
723 void
zdb_zone_release_double_unlock(zdb_zone * zone,u8 owner,u8 nextowner)724 zdb_zone_release_double_unlock(zdb_zone *zone, u8 owner, u8 nextowner)
725 {
726     mutex_lock(&zone->lock_mutex);
727 
728 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
729     struct zdb_zone_lock_monitor *holder = zdb_zone_lock_monitor_get(zone);
730 #else
731     (void)owner;
732     (void)nextowner;
733 #endif
734 
735 #if DEBUG
736     if((zone->lock_owner != (owner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG)) || (zone->lock_count == 0))
737     {
738         yassert(zone->lock_owner == (owner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG));
739         yassert(zone->lock_count != 0);
740     }
741 
742     if(zone->lock_reserved_owner != (nextowner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG))
743     {
744         yassert(zone->lock_reserved_owner != (nextowner & ZDB_ZONE_MUTEX_UNLOCKMASK_FLAG));
745     }
746 #endif
747 
748     zone->lock_reserved_owner = ZDB_ZONE_MUTEX_NOBODY;
749 
750     --zone->lock_count;
751 
752 #if ZONE_MUTEX_LOG
753     log_debug7("released lock for zone %{dnsname}@%p by %x (#%i)", zone->origin, zone, owner, zone->lock_count);
754 #endif
755 
756 #if ZDB_HAS_LOCK_DEBUG_SUPPORT
757     zdb_zone_lock_monitor_unlocks(holder);
758 #endif
759 
760     yassert((zone->lock_owner & 0xc0) == 0);
761     // NO, because it does not always to a transfer lock yassert(zone->lock_count == 0);
762 
763     if(zone->lock_count == 0)
764     {
765         zone->lock_owner = ZDB_ZONE_MUTEX_NOBODY;
766     }
767 
768 #if ZDB_ZONE_LOCK_HAS_OWNER_ID
769     if(zone->lock_last_owner_id == thread_self())
770     {
771         zone->lock_last_owner_id = 0;
772     }
773 #endif
774 
775     if(ZONE_RC_DEC(zone))
776     {
777 #if !DEBUG_ARC
778 #if DEBUG
779         debug_log_stacktrace(MODULE_MSG_HANDLE, MSG_DEBUG6, "GC: ");
780 #endif
781 #endif
782         if(!zdb_zone_garbage_collect(zone)) // zone mutex locked, as MUST be
783         {
784             // zone was not collected: it was destroyed
785             return;
786         }
787     }
788 
789     cond_notify(&zone->lock_cond);
790     mutex_unlock(&zone->lock_mutex);
791 }
792 
793 /** @} */
794