Blockdata fixes and tuning.
diff --git a/src/blockdata.c b/src/blockdata.c
index 1da78b7..16a1d94 100644
--- a/src/blockdata.c
+++ b/src/blockdata.c
@@ -18,13 +18,29 @@
 
 #ifdef HAVE_DNSSEC
 
-static struct blockdata *keyblock_free = NULL;
-static unsigned int blockdata_count = 0, blockdata_hwm = 0;
+static struct blockdata *keyblock_free;
+static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
+
+/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
+void blockdata_init(void)
+{
+  int i;
+
+  blockdata_alloced = (daemon->cachesize * 100) / sizeof(struct blockdata);
+   
+  keyblock_free = safe_malloc(blockdata_alloced * sizeof(struct blockdata));
+  keyblock_free[blockdata_alloced-1].next = NULL;
+  for (i = 0; i < blockdata_alloced - 1; i++)
+    keyblock_free[i].next = &keyblock_free[i+1];
+  
+  blockdata_count = 0;
+  blockdata_hwm = 0;
+}
 
 void blockdata_report(void)
 {
-  my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u"), 
-	    blockdata_count * sizeof(struct blockdata),  blockdata_hwm * sizeof(struct blockdata));
+  my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"), 
+	    blockdata_count * sizeof(struct blockdata),  blockdata_hwm * sizeof(struct blockdata),  blockdata_alloced * sizeof(struct blockdata));
 } 
 
 struct blockdata *blockdata_alloc(char *data, size_t len)
@@ -44,8 +60,8 @@
       else if ((block = whine_malloc(sizeof(struct blockdata))))
 	{
 	  blockdata_count++;
-	  if (blockdata_hwm < blockdata_count)
-	    blockdata_hwm = blockdata_count;
+	  if (blockdata_alloced < blockdata_count)
+	    blockdata_alloced = blockdata_count;
 	}
 	  
       if (!block)
@@ -54,6 +70,9 @@
 	  blockdata_free(ret);
 	  return NULL;
 	}
+       
+      if (blockdata_hwm < blockdata_count)
+	blockdata_hwm = blockdata_count; 
       
       blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
       memcpy(block->key, data, blen);
@@ -70,7 +89,7 @@
 void blockdata_free(struct blockdata *blocks)
 {
   struct blockdata *tmp;
-
+  
   if (blocks)
     {
       for (tmp = blocks; tmp->next; tmp = tmp->next)
diff --git a/src/cache.c b/src/cache.c
index 51764eb..3fe137d 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -170,7 +170,22 @@
   crecp->hash_next = *up;
   *up = crecp;
 }
- 
+
+#ifdef HAVE_DNSSEC
+static void cache_blockdata_free(struct crec *crecp)
+{
+  if (crecp->flags & F_DNSKEY)
+    {
+      if (crecp->flags & F_DS)
+	blockdata_free(crecp->addr.sig.keydata);
+      else
+	blockdata_free(crecp->addr.key.keydata);
+    }
+  else if (crecp->flags & F_DS)
+    blockdata_free(crecp->addr.ds.keydata);
+}
+#endif
+
 static void cache_free(struct crec *crecp)
 {
   crecp->flags &= ~F_FORWARD;
@@ -197,8 +212,7 @@
     }
 
 #ifdef HAVE_DNSSEC
-  if (crecp->flags & (F_DNSKEY | F_DS))
-    blockdata_free(crecp->addr.key.keydata);
+  cache_blockdata_free(crecp);
 #endif
 }    
 
@@ -957,8 +971,7 @@
     for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
       {
 #ifdef HAVE_DNSSEC
-	if (cache->flags & (F_DNSKEY | F_DS))
-	  blockdata_free(cache->addr.key.keydata);
+	cache_blockdata_free(cache);
 #endif
 	tmp = cache->hash_next;
 	if (cache->flags & (F_HOSTS | F_CONFIG))
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 03f9449..6c19c05 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -304,7 +304,12 @@
 #endif
   
   if (daemon->port != 0)
-    cache_init();
+    {
+      cache_init();
+#ifdef HAVE_DNSSEC
+      blockdata_init();
+#endif
+    }
     
   if (option_bool(OPT_DBUS))
 #ifdef HAVE_DBUS
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f8cc969..5317ea3 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1011,6 +1011,7 @@
 
 /* blockdata.c */
 #ifdef HAVE_DNSSEC
+void blockdata_init(void);
 void blockdata_report(void);
 struct blockdata *blockdata_alloc(char *data, size_t len);
 void *blockdata_retrieve(struct blockdata *block, size_t len, void *data);