]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Netindex: consistency checks and deletion of whole hash
authorMaria Matejka <mq@ucw.cz>
Thu, 30 May 2024 20:59:08 +0000 (22:59 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 4 Jun 2024 08:11:36 +0000 (10:11 +0200)
lib/netindex.c
lib/netindex.h
lib/netindex_private.h
nest/rt-table.c

index c5f422e8f9bd33d498f4f003d9982d42b4c62dd7..296319691ee8dc1bf2a3f490276dc4c397c5926a 100644 (file)
@@ -33,11 +33,32 @@ net_lock_revive_unlock(struct netindex_hash_private *hp, struct netindex *i)
   return i;
 }
 
+void
+netindex_hash_consistency_check(struct netindex_hash_private *nh)
+{
+  for (uint t = 0; t < NET_MAX; t++)
+  {
+    if (!nh->net[t].hash.data)
+      continue;
+
+    uint count = 0;
+    HASH_WALK(nh->net[t].hash, next, i)
+    {
+      ASSERT_DIE(count < nh->net[t].hash.count);
+      ASSERT_DIE(nh->net[t].block[i->index] == i);
+      count++;
+    }
+    HASH_WALK_END;
+
+    ASSERT_DIE(count == nh->net[t].hash.count);
+  }
+}
+
 /*
  * Index initialization
  */
 netindex_hash *
-netindex_hash_new(pool *sp)
+netindex_hash_new(pool *sp, event_list *cleanup_target)
 {
   DOMAIN(attrs) dom = DOMAIN_NEW(attrs);
   LOCK_DOMAIN(attrs, dom);
@@ -48,7 +69,7 @@ netindex_hash_new(pool *sp)
   nh->lock = dom;
   nh->pool = p;
 
-  nh->cleanup_list = &global_event_list;
+  nh->cleanup_list = cleanup_target;
   nh->cleanup_event = (event) { .hook = netindex_hash_cleanup, nh };
 
   UNLOCK_DOMAIN(attrs, dom);
@@ -58,29 +79,71 @@ netindex_hash_new(pool *sp)
 static void
 netindex_hash_cleanup(void *_nh)
 {
-  NH_LOCK((netindex_hash *) _nh, nh);
+  struct netindex_hash_private *nh = _nh;
+
+  DOMAIN(attrs) dom = nh->lock;
+  LOCK_DOMAIN(attrs, dom);
+
+  EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
+
+  uint kept = 0;
 
   for (uint t = 0; t < NET_MAX; t++)
-  {
-    if (!nh->net[t].hash.data)
-      continue;
+    for (uint i = 0; i < nh->net[t].block_size; i++)
+    {
+      struct netindex *ni = nh->net[t].block[i];
+      if (!ni)
+       continue;
 
-    HASH_WALK_FILTER(nh->net[t].hash, next, i, ii)
-      if (lfuc_finished(&i->uc))
+      ASSERT_DIE(i == ni->index);
+
+      if (lfuc_finished(&ni->uc))
       {
-       HASH_DO_REMOVE(nh->net[t].hash, NETINDEX, ii);
-       hmap_clear(&nh->net[t].id_map, i->index);
-       nh->net[t].block[i->index] = NULL;
+       HASH_REMOVE2(nh->net[t].hash, NETINDEX, nh->pool, ni);
+       hmap_clear(&nh->net[t].id_map, ni->index);
+       nh->net[t].block[i] = NULL;
 
        if (nh->net[t].slab)
-         sl_free(i);
+         sl_free(ni);
        else
-         mb_free(i);
+         mb_free(ni);
       }
-    HASH_WALK_DELSAFE_END;
+      else
+       kept++;
+    }
+
+  EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
+
+  if (kept || !nh->deleted_event)
+  {
+    UNLOCK_DOMAIN(attrs, dom);
+    return;
   }
-}
 
+  ev_postpone(&nh->cleanup_event);
+
+  event *e = nh->deleted_event;
+  event_list *t = nh->deleted_target;
+
+  /* Check cleanliness */
+  for (uint t = 0; t < NET_MAX; t++)
+    if (nh->net[t].hash.data)
+    {
+      HASH_WALK(nh->net[t].hash, next, i)
+       bug("Stray netindex in deleted hash");
+      HASH_WALK_END;
+    }
+
+  /* Pool free is enough to drop everything */
+  rp_free(nh->pool);
+
+  /* And only the lock remains */
+  UNLOCK_DOMAIN(attrs, dom);
+  DOMAIN_FREE(attrs, dom);
+
+  /* Notify the requestor */
+  ev_send(t, e);
+}
 
 static void
 netindex_hash_init(struct netindex_hash_private *hp, u8 type)
@@ -94,6 +157,19 @@ netindex_hash_init(struct netindex_hash_private *hp, u8 type)
   hmap_init(&hp->net[type].id_map, hp->pool, 128);
 };
 
+void
+netindex_hash_delete(netindex_hash *h, event *e, event_list *t)
+{
+  NH_LOCK(h, hp);
+
+  EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
+
+  hp->deleted_event = e;
+  hp->deleted_target = t;
+
+  ev_send(hp->cleanup_list, &hp->cleanup_event);
+}
+
 /*
  * Private index manipulation
  */
@@ -115,6 +191,8 @@ net_find_index_fragile(struct netindex_hash_private *hp, const net_addr *n)
   if (!hp->net[n->type].block)
     return NULL;
 
+  EXPENSIVE_CHECK(netindex_hash_consistency_check(nh));
+
   u32 h = net_hash(n);
   return HASH_FIND(hp->net[n->type].hash, NETINDEX, h, n);
 }
@@ -128,6 +206,8 @@ net_find_index_locked(struct netindex_hash_private *hp, const net_addr *n)
 static struct netindex *
 net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n)
 {
+  ASSERT_DIE(!hp->deleted_event);
+
   if (!hp->net[n->type].block)
     netindex_hash_init(hp, n->type);
 
@@ -151,8 +231,11 @@ net_new_index_locked(struct netindex_hash_private *hp, const net_addr *n)
     struct netindex **nb = mb_alloc(hp->pool, bs * 2 * sizeof *nb);
     memcpy(nb, hp->net[n->type].block, bs * sizeof *nb);
     memset(&nb[bs], 0, bs * sizeof *nb);
-    hp->net[n->type].block_size *= 2;
+
+    mb_free(hp->net[n->type].block);
     hp->net[n->type].block = nb;
+
+    hp->net[n->type].block_size *= 2;
   }
 
   hp->net[n->type].block[i] = ni;
index 18c24a079c2dd0c456d013dc1036f9da192c28d0..b2553212abdc75136c6a5d76d000cbee0dfa1eb6 100644 (file)
@@ -27,8 +27,9 @@ struct netindex {
 /* Index hash: data structure completely opaque, use handlers */
 typedef union netindex_hash netindex_hash;
 
-/* Initialization */
-netindex_hash *netindex_hash_new(pool *);
+/* Initialization and teardown */
+netindex_hash *netindex_hash_new(pool *, event_list *);
+void netindex_hash_delete(netindex_hash *, event *, event_list *);
 
 /* Find/get/resolve index; pointer valid until end of task */ 
 struct netindex *net_find_index(netindex_hash *, const net_addr *);
index 712a6aac915d4e3187734c8bf241f6362f0f2ad1..8e72a5c87de9d38bff16469b64018c6177137400 100644 (file)
@@ -27,6 +27,8 @@ struct netindex_hash_private {
     struct netindex **block;
     struct hmap id_map;
   } net[NET_MAX];
+  event *deleted_event;
+  event_list *deleted_target;
 };
 
 typedef union netindex_hash {
index eb365c7c13ee1c0f09bad3a8e18841e15b8e2e60..9a10ab3abb33f289ed8b756df28552ff5b530032 100644 (file)
@@ -2899,7 +2899,7 @@ rt_init(void)
   ev_init_list(&rt_cork.queue, &main_birdloop, "Route cork release");
   rt_cork.run = (event) { .hook = rt_cork_release_hook };
   idm_init(&rtable_idm, rt_table_pool, 256);
-  rt_global_netindex_hash = netindex_hash_new(rt_table_pool);
+  rt_global_netindex_hash = netindex_hash_new(rt_table_pool, &global_event_list);
 }
 
 static _Bool