slab: Update the ctor/dtor interface
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Nov 2016 21:44:17 +0000 (16:44 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 29 Nov 2016 16:27:40 +0000 (11:27 -0500)
The priv (private) field is to support parameterized callbacks.  For
instance, you might have separate kmem_caches for different parts of a
driver.

The old 'size' field was useless, since the caller should know the size of
the object (if that's even useful).

ctor can fail, and it will respect the mem flags.  I have a couple ctors in
mind that could block, so they'll need to check MEM_WAIT/MEM_ATOMIC.

I moved the dtor out of free_to_slab since the ctor needs to call free
if it failed.  I also considered adding a batch dtor interface so we can
free a chunk of objects at once, which could amortize the overhead of
freeing.  For example, if there was an expensive operation that had to
be done after freeing any object (such as a TLB shootdown), then a batch
dtor would make sense.  It turns out that I don't need this for now, so
I opted to keep the vmem paper's API.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
15 files changed:
kern/include/slab.h
kern/src/arena.c
kern/src/blockdev.c
kern/src/ext2fs.c
kern/src/frontend.c
kern/src/hashtable.c
kern/src/kfs.c
kern/src/kmalloc.c
kern/src/kthread.c
kern/src/mm.c
kern/src/process.c
kern/src/radix.c
kern/src/slab.c
kern/src/trap.c
kern/src/vfs.c

index 705befe..4d90556 100644 (file)
@@ -112,8 +112,9 @@ struct kmem_cache {
        struct kmem_slab_list full_slab_list;
        struct kmem_slab_list partial_slab_list;
        struct kmem_slab_list empty_slab_list;
-       void (*ctor)(void *, size_t);
-       void (*dtor)(void *, size_t);
+       int (*ctor)(void *obj, void *priv, int flags);
+       void (*dtor)(void *obj, void *priv);
+       void *priv;
        unsigned long nr_cur_alloc;
        struct hash_helper hh;
        struct kmem_bufctl_list *alloc_hash;
@@ -128,8 +129,9 @@ extern struct kmem_cache_tailq all_kmem_caches;
 struct kmem_cache *kmem_cache_create(const char *name, size_t obj_size,
                                      int align, int flags,
                                      struct arena *source,
-                                     void (*ctor)(void *, size_t),
-                                     void (*dtor)(void *, size_t));
+                                     int (*ctor)(void *, void *, int),
+                                     void (*dtor)(void *, void *),
+                                     void *priv);
 void kmem_cache_destroy(struct kmem_cache *cp);
 /* Front end: clients of caches use these */
 void *kmem_cache_alloc(struct kmem_cache *cp, int flags);
@@ -142,5 +144,5 @@ unsigned int kmc_nr_pcpu_caches(void);
 void __kmem_cache_create(struct kmem_cache *kc, const char *name,
                          size_t obj_size, int align, int flags,
                          struct arena *source,
-                         void (*ctor)(void *, size_t),
-                         void (*dtor)(void *, size_t));
+                         int (*ctor)(void *, void *, int),
+                         void (*dtor)(void *, void *), void *priv);
index 1a9df25..26a5991 100644 (file)
@@ -125,7 +125,7 @@ static void setup_qcaches(struct arena *arena, size_t quantum,
                qc_size = (i + 1) * quantum;
                snprintf(kc_name, KMC_NAME_SZ, "%s_%d", arena->name, qc_size);
                __kmem_cache_create(&arena->qcaches[i], kc_name, qc_size, quantum,
-                                   KMC_NOTOUCH | KMC_QCACHE, arena, NULL, NULL);
+                                   KMC_NOTOUCH | KMC_QCACHE, arena, NULL, NULL, NULL);
        }
 }
 
index 73c7c60..434051b 100644 (file)
@@ -23,11 +23,11 @@ void block_init(void)
        breq_kcache = kmem_cache_create("block_reqs",
                                        sizeof(struct block_request),
                                        __alignof__(struct block_request), 0,
-                                       NULL, 0, 0);
+                                       NULL, 0, 0, NULL);
        bh_kcache = kmem_cache_create("buffer_heads",
                                      sizeof(struct buffer_head),
                                      __alignof__(struct buffer_head), 0,
-                                     NULL, 0, 0);
+                                     NULL, 0, 0, NULL);
 
        #ifdef CONFIG_EXT2FS
        /* Now probe for and init the block device for the ext2 ram disk */
index 75790a2..97c8f38 100644 (file)
@@ -101,7 +101,7 @@ void ext2_init(void)
        ext2_i_kcache = kmem_cache_create("ext2_i_info",
                                          sizeof(struct ext2_i_info),
                                          __alignof__(struct ext2_i_info), 0,
-                                         NULL, 0, 0);
+                                         NULL, 0, 0, NULL);
 }
 
 /* Block management */
index 5beb3df..43554ce 100644 (file)
@@ -36,7 +36,7 @@ void file_init()
 {
        struct_file_cache = kmem_cache_create("struct_file",
                                              sizeof(struct file), 8, 0,
-                                             NULL, 0, 0);
+                                             NULL, 0, 0, NULL);
 }
 
 /* will zero anything in the page after the EOF */
index 9d150ab..eff77cb 100644 (file)
@@ -42,7 +42,7 @@ void hashtable_init(void)
        hentry_cache = kmem_cache_create("hash_entry",
                                         sizeof(struct hash_entry),
                                         __alignof__(struct hash_entry), 0,
-                                        NULL, 0, 0);
+                                        NULL, 0, 0, NULL);
 }
 
 /* Common hash/equals functions.  Don't call these directly. */
index eb6459a..ecf71b5 100644 (file)
@@ -50,7 +50,7 @@ static void kfs_init(void)
        kfs_i_kcache = kmem_cache_create("kfs_ino_info",
                                         sizeof(struct kfs_i_info),
                                         __alignof__(struct kfs_i_info), 0,
-                                        NULL, 0, 0);
+                                        NULL, 0, 0, NULL);
 }
 
 /* Creates the SB (normally would read in from disc and create).  Passes its
index f29b0bb..a5b51cf 100644 (file)
@@ -37,7 +37,7 @@ void kmalloc_init(void)
        for (int i = 0; i < NUM_KMALLOC_CACHES; i++) {
                snprintf(kc_name, KMC_NAME_SZ, "kmalloc_%d", ksize);
                kmalloc_caches[i] = kmem_cache_create(kc_name, ksize, KMALLOC_ALIGNMENT,
-                                                     0, NULL, 0, 0);
+                                                     0, NULL, 0, 0, NULL);
                ksize <<= 1;
        }
 }
index 816157e..dcd56b9 100644 (file)
@@ -47,7 +47,7 @@ void kthread_init(void)
 {
        kthread_kcache = kmem_cache_create("kthread", sizeof(struct kthread),
                                           __alignof__(struct kthread), 0,
-                                          NULL, 0, 0);
+                                          NULL, 0, 0, NULL);
 }
 
 /* Used by early init routines (smp_boot, etc) */
index 45f4839..db355ea 100644 (file)
@@ -46,7 +46,7 @@ void vmr_init(void)
        vmr_kcache = kmem_cache_create("vm_regions",
                                       sizeof(struct vm_region),
                                       __alignof__(struct dentry), 0, NULL,
-                                      0, 0);
+                                      0, 0, NULL);
 }
 
 /* For now, the caller will set the prot, flags, file, and offset.  In the
index 6e5cd17..d54001f 100644 (file)
@@ -247,7 +247,7 @@ void proc_init(void)
        proc_cache = kmem_cache_create("proc", sizeof(struct proc),
                                       MAX(ARCH_CL_SIZE,
                                       __alignof__(struct proc)), 0, NULL, 0,
-                                      0);
+                                      0, NULL);
        /* Init PID mask and hash.  pid 0 is reserved. */
        SET_BITMASK_BIT(pid_bmask, 0);
        spinlock_init(&pid_hash_lock);
index e26e7a8..e109cfa 100644 (file)
@@ -22,7 +22,7 @@ void radix_init(void)
        radix_kcache = kmem_cache_create("radix_nodes",
                                         sizeof(struct radix_node),
                                         __alignof__(struct radix_node), 0,
-                                        NULL, 0, 0);
+                                        NULL, 0, 0, NULL);
 }
 
 /* Initializes a tree dynamically */
index b26b7c5..a9eab4a 100644 (file)
@@ -70,7 +70,7 @@
  *   grab a pcc lock.
  *
  * TODO:
- * - Change the sigs of ctor/dtor, add reclaim function.
+ * - Add reclaim function.
  * - When resizing, do we want to go through the depot and consolidate
  *   magazines?  (probably not a big deal.  maybe we'd deal with it when we
  *   clean up our excess mags.)
@@ -230,8 +230,11 @@ static void __return_to_depot(struct kmem_cache *kc, struct kmem_magazine *mag)
  * layer. */
 static void drain_mag(struct kmem_cache *kc, struct kmem_magazine *mag)
 {
-       for (int i = 0; i < mag->nr_rounds; i++)
+       for (int i = 0; i < mag->nr_rounds; i++) {
+               if (kc->dtor)
+                       kc->dtor(mag->rounds[i], kc->priv);
                __kmem_free_to_slab(kc, mag->rounds[i]);
+       }
        mag->nr_rounds = 0;
 }
 
@@ -255,8 +258,8 @@ static struct kmem_pcpu_cache *build_pcpu_caches(void)
 void __kmem_cache_create(struct kmem_cache *kc, const char *name,
                          size_t obj_size, int align, int flags,
                          struct arena *source,
-                         void (*ctor)(void *, size_t),
-                         void (*dtor)(void *, size_t))
+                         int (*ctor)(void *, void *, int),
+                         void (*dtor)(void *, void *), void *priv)
 {
        assert(kc);
        assert(align);
@@ -279,6 +282,7 @@ void __kmem_cache_create(struct kmem_cache *kc, const char *name,
        TAILQ_INIT(&kc->empty_slab_list);
        kc->ctor = ctor;
        kc->dtor = dtor;
+       kc->priv = priv;
        kc->nr_cur_alloc = 0;
        kc->alloc_hash = kc->static_hash;
        hash_init_hh(&kc->hh);
@@ -300,11 +304,12 @@ void __kmem_cache_create(struct kmem_cache *kc, const char *name,
        qunlock(&arenas_and_slabs_lock);
 }
 
-static void __mag_ctor(void *obj, size_t _ign)
+static int __mag_ctor(void *obj, void *priv, int flags)
 {
        struct kmem_magazine *mag = (struct kmem_magazine*)obj;
 
        mag->nr_rounds = 0;
+       return 0;
 }
 
 void kmem_cache_init(void)
@@ -315,30 +320,33 @@ void kmem_cache_init(void)
        __kmem_cache_create(kmem_magazine_cache, "kmem_magazine",
                            sizeof(struct kmem_magazine),
                            __alignof__(struct kmem_magazine), 0, base_arena,
-                           __mag_ctor, NULL);
+                           __mag_ctor, NULL, NULL);
        __kmem_cache_create(kmem_cache_cache, "kmem_cache",
                            sizeof(struct kmem_cache),
                            __alignof__(struct kmem_cache), 0, base_arena,
-                           NULL, NULL);
+                           NULL, NULL, NULL);
        __kmem_cache_create(kmem_slab_cache, "kmem_slab",
                            sizeof(struct kmem_slab),
                            __alignof__(struct kmem_slab), 0, base_arena,
-                           NULL, NULL);
+                           NULL, NULL, NULL);
        __kmem_cache_create(kmem_bufctl_cache, "kmem_bufctl",
                            sizeof(struct kmem_bufctl),
                            __alignof__(struct kmem_bufctl), 0, base_arena,
-                           NULL, NULL);
+                           NULL, NULL, NULL);
 }
 
 /* Cache management */
 struct kmem_cache *kmem_cache_create(const char *name, size_t obj_size,
                                      int align, int flags,
                                      struct arena *source,
-                                     void (*ctor)(void *, size_t),
-                                     void (*dtor)(void *, size_t))
+                                     int (*ctor)(void *, void *, int),
+                                     void (*dtor)(void *, void *),
+                                     void *priv)
 {
        struct kmem_cache *kc = kmem_cache_alloc(kmem_cache_cache, 0);
-       __kmem_cache_create(kc, name, obj_size, align, flags, source, ctor, dtor);
+
+       __kmem_cache_create(kc, name, obj_size, align, flags, source, ctor, dtor,
+                           priv);
        return kc;
 }
 
@@ -535,8 +543,13 @@ static void *__kmem_alloc_from_slab(struct kmem_cache *cp, int flags)
        }
        cp->nr_cur_alloc++;
        spin_unlock_irqsave(&cp->cache_lock);
-       if (cp->ctor)
-               cp->ctor(retval, cp->obj_size);
+       if (cp->ctor) {
+               if (cp->ctor(retval, cp->priv, flags)) {
+                       warn("Ctor %p failed, probably a bug!");
+                       __kmem_free_to_slab(cp, retval);
+                       return NULL;
+               }
+       }
        return retval;
 }
 
@@ -577,15 +590,13 @@ try_alloc:
        return __kmem_alloc_from_slab(kc, flags);
 }
 
-/* Returns an object to the slab layer.  Note that objects in the slabs are
- * unconstructed. */
+/* Returns an object to the slab layer.  Caller must deconstruct the objects.
+ * Note that objects in the slabs are unconstructed. */
 static void __kmem_free_to_slab(struct kmem_cache *cp, void *buf)
 {
        struct kmem_slab *a_slab;
        struct kmem_bufctl *a_bufctl;
 
-       if (cp->dtor)
-               cp->dtor(buf, cp->obj_size);
        spin_lock_irqsave(&cp->cache_lock);
        if (!__use_bufctls(cp)) {
                // find its slab
@@ -665,6 +676,8 @@ try_free:
                lock_pcu_cache(pcc);
                goto try_free;
        }
+       if (kc->dtor)
+               kc->dtor(buf, kc->priv);
        __kmem_free_to_slab(kc, buf);
 }
 
index 41e1155..a9983e4 100644 (file)
@@ -110,8 +110,8 @@ struct kmem_cache *kernel_msg_cache;
 void kernel_msg_init(void)
 {
        kernel_msg_cache = kmem_cache_create("kernel_msgs",
-                                            sizeof(struct kernel_message),
-                                            ARCH_CL_SIZE, 0, NULL, 0, 0);
+                                            sizeof(struct kernel_message),
+                                            ARCH_CL_SIZE, 0, NULL, 0, 0, NULL);
 }
 
 uint32_t send_kernel_message(uint32_t dst, amr_t pc, long arg0, long arg1,
index 1f21e29..ccd364b 100644 (file)
@@ -89,13 +89,13 @@ void vfs_init(void)
 
        dentry_kcache = kmem_cache_create("dentry", sizeof(struct dentry),
                                          __alignof__(struct dentry), 0,
-                                         NULL, 0, 0);
+                                         NULL, 0, 0, NULL);
        inode_kcache = kmem_cache_create("inode", sizeof(struct inode),
                                         __alignof__(struct inode), 0, NULL,
-                                        0, 0);
+                                        0, 0, NULL);
        file_kcache = kmem_cache_create("file", sizeof(struct file),
                                        __alignof__(struct file), 0, NULL, 0,
-                                       0);
+                                       0, NULL);
        /* default NS never dies, +1 to exist */
        kref_init(&default_ns.kref, fake_release, 1);
        spinlock_init(&default_ns.lock);