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