diff mbox

[RFC,10/22] block/pcache: add check node leak

Message ID 20160825134421.20231-11-pbutsykin@virtuozzo.com (mailing list archive)
State New, archived
Headers show

Commit Message

Pavel Butsykin Aug. 25, 2016, 1:44 p.m. UTC
If the pcache  has a bug with node reference, then s->death_node_list can help
to know about it.

Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
---
 block/pcache.c | 45 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 39 insertions(+), 6 deletions(-)
diff mbox

Patch

diff --git a/block/pcache.c b/block/pcache.c
index 6114289..a8a57e3 100644
--- a/block/pcache.c
+++ b/block/pcache.c
@@ -87,6 +87,8 @@  typedef struct BDRVPCacheState {
 
 #ifdef PCACHE_DEBUG
     uint64_t shrink_cnt_node;
+    QTAILQ_HEAD(death_node_head, BlockNode) death_node_list;
+    CoMutex                                 death_node_lock;
 #endif
 } BDRVPCacheState;
 
@@ -152,7 +154,7 @@  enum {
 
 #define PCNODE(_n) ((PCNode *)(_n))
 
-static inline void pcache_node_unref(PCNode *node)
+static inline void pcache_node_unref(BDRVPCacheState *s, PCNode *node)
 {
     assert(node->status == NODE_SUCCESS_STATUS ||
            node->status == NODE_REMOVE_STATUS);
@@ -161,6 +163,12 @@  static inline void pcache_node_unref(PCNode *node)
         assert(node->status == NODE_REMOVE_STATUS);
 
         node->status = NODE_GHOST_STATUS;
+
+#ifdef PCACHE_DEBUG
+        qemu_co_mutex_lock(&s->death_node_lock);
+        QTAILQ_REMOVE(&s->death_node_list, &node->cm, entry);
+        qemu_co_mutex_unlock(&s->death_node_lock);
+#endif
         g_free(node->data);
         g_slice_free1(sizeof(*node), node);
     }
@@ -263,11 +271,17 @@  static void pcache_node_drop(BDRVPCacheState *s, PCNode *node)
     QTAILQ_REMOVE(&s->pcache.lru.list, &node->cm, entry);
     qemu_co_mutex_unlock(&s->pcache.lru.lock);
 
+#ifdef PCACHE_DEBUG
+    qemu_co_mutex_lock(&s->death_node_lock);
+    QTAILQ_INSERT_HEAD(&s->death_node_list, &node->cm, entry);
+    qemu_co_mutex_unlock(&s->death_node_lock);
+#endif
+
     qemu_co_mutex_lock(&s->pcache.tree.lock);
     rb_erase(&node->cm.rb_node, &s->pcache.tree.root);
     qemu_co_mutex_unlock(&s->pcache.tree.lock);
 
-    pcache_node_unref(node);
+    pcache_node_unref(s, node);
 }
 
 static void pcache_try_shrink(BDRVPCacheState *s)
@@ -367,7 +381,7 @@  static void pcache_pickup_parts_of_cache(PrefCacheAIOCB *acb, PCNode *node,
             up_size = lc_key.size;
 
             if (!pcache_node_find_and_create(acb, &lc_key, &new_node)) {
-                pcache_node_unref(node);
+                pcache_node_unref(acb->s, node);
                 node = new_node;
                 continue;
             }
@@ -377,7 +391,7 @@  static void pcache_pickup_parts_of_cache(PrefCacheAIOCB *acb, PCNode *node,
         /* XXX: node read */
         up_size = MIN(node->cm.sector_num + node->cm.nb_sectors - num, size);
 
-        pcache_node_unref(node);
+        pcache_node_unref(acb->s, node);
 
         size -= up_size;
         num += up_size;
@@ -416,7 +430,7 @@  static int32_t pcache_prefetch(PrefCacheAIOCB *acb)
                                                      acb->nb_sectors)
     {
         /* XXX: node read */
-        pcache_node_unref(node);
+        pcache_node_unref(acb->s, node);
         return PREFETCH_FULL_UP;
     }
     pcache_pickup_parts_of_cache(acb, node, key.num, key.size);
@@ -459,7 +473,7 @@  static void pcache_merge_requests(PrefCacheAIOCB *acb)
 
         /* XXX: pcache read */
 
-        pcache_node_unref(req->node);
+        pcache_node_unref(acb->s, req->node);
 
         g_slice_free1(sizeof(*req), req);
     }
@@ -544,6 +558,11 @@  static void pcache_state_init(QemuOpts *opts, BDRVPCacheState *s)
     s->pcache.curr_size = 0;
 
     s->cfg_cache_size = cache_size >> BDRV_SECTOR_BITS;
+
+#ifdef PCACHE_DEBUG
+    QTAILQ_INIT(&s->death_node_list);
+    qemu_co_mutex_init(&s->death_node_lock);
+#endif
 }
 
 static int pcache_file_open(BlockDriverState *bs, QDict *options, int flags,
@@ -597,6 +616,20 @@  static void pcache_close(BlockDriverState *bs)
         cnt++;
     }
     DPRINTF("used %d nodes\n", cnt);
+
+#ifdef PCACHE_DEBUG
+    if (!QTAILQ_EMPTY(&s->death_node_list)) {
+        cnt = 0;
+        DPRINTF("warning: death node list contains of node\n");
+        QTAILQ_FOREACH_SAFE(node, &s->death_node_list, entry, next) {
+            QTAILQ_REMOVE(&s->death_node_list, node, entry);
+            g_free(PCNODE(node)->data);
+            g_slice_free1(sizeof(*node), node);
+            cnt++;
+        }
+        DPRINTF("death nodes: %d", cnt);
+    }
+#endif
 }
 
 static void pcache_parse_filename(const char *filename, QDict *options,