objcache: Fix free(NULL) and realloc()
authorJack Miller <jack@codezen.org>
Sat, 18 Feb 2017 02:24:19 +0000 (20:24 -0600)
committerJack Miller <jack@codezen.org>
Fri, 12 Apr 2019 17:04:51 +0000 (12:04 -0500)
mm/objcache.c

index 9c99d1c..1d9ca32 100644 (file)
@@ -269,17 +269,25 @@ static int __oc_alloc_empty(u64 * page)
 
 void objcache_free(struct objcache *objcache, void *obj)
 {
-    void *base = OBJBASE(obj);
-    u64 *block_map = OBJCACHE_BLOCK_BMAP(base);
-    u64 *mark_map = OBJCACHE_MARK_BMAP(base);
-    u64 *meta_map = OBJCACHE_META_BMAP(base);
+    void *base;
+    u64 *block_map, *mark_map, *meta_map;
+    int idx, longidx;
+    u64 bit, meta_bit, meta_mask;
 
-    int idx = OBJIDX(obj);
-    int longidx = idx / 64;
-    u64 bit = FIRST_BIT >> (idx % 64);
+    if (!obj)
+        return;
+
+    base = OBJBASE(obj);
+    block_map = OBJCACHE_BLOCK_BMAP(base);
+    mark_map = OBJCACHE_MARK_BMAP(base);
+    meta_map = OBJCACHE_META_BMAP(base);
+
+    idx = OBJIDX(obj);
+    longidx = idx / 64;
+    bit = FIRST_BIT >> (idx % 64);
 
-    u64 meta_bit = (FIRST_BIT >> longidx);
-    u64 meta_mask = meta_bit - 1;
+    meta_bit = (FIRST_BIT >> longidx);
+    meta_mask = meta_bit - 1;
 
     assert(obj == OBJCACHE_CELL(base, idx));
     assert(block_map[longidx] & bit);
@@ -305,6 +313,49 @@ void objcache_free(struct objcache *objcache, void *obj)
     }
 }
 
+void *objcache_realloc(struct objcache *objcache, void *obj, u32 size)
+{
+    void *base = OBJBASE(obj);
+    u64 *block_map = OBJCACHE_BLOCK_BMAP(base);
+    u64 *mark_map = OBJCACHE_MARK_BMAP(base);
+
+    int idx = OBJIDX(obj);
+    int longidx = idx / 64;
+    u64 bit = FIRST_BIT >> (idx % 64);
+
+    int cur_cells = 0;
+    void *ret;
+
+    if (obj) {
+        assert(obj == OBJCACHE_CELL(base, idx));
+        assert(block_map[longidx] & bit);
+
+        /* Figure out how big the current allocation is */
+        do {
+            cur_cells++;
+
+            idx++;
+            if (idx >= FREE_CELLS)
+                break;
+            longidx = idx / 64;
+            bit = FIRST_BIT >> (idx % 64);
+
+        } while ((!(block_map[longidx] & bit))&&
+                (!(mark_map[longidx] & bit)));
+    }
+
+    ret = objcache_get(objcache, size);
+    
+    if (!ret)
+        return NULL;
+
+    memcpy(ret, obj, cur_cells * OC_CELL_SIZE);
+
+    objcache_free(objcache, obj);
+
+    return ret;
+}
+
 void objcache_destroy(struct objcache *objcache)
 {
     u64 *cur = objcache->data;