Index: linux-2.6.18-rc4/mm/allocator.c =================================================================== --- linux-2.6.18-rc4.orig/mm/allocator.c 2006-08-14 21:06:41.102078360 -0700 +++ linux-2.6.18-rc4/mm/allocator.c 2006-08-15 14:09:23.772537089 -0700 @@ -23,7 +23,7 @@ static void null_destructor(struct page_ /* * The page allocator that can allocate all of memory */ -static struct page *gen_alloc(struct page_allocator *a, int order, +static struct page *gen_alloc(const struct page_allocator *a, int order, gfp_t flags, int node) { if (order) @@ -35,21 +35,22 @@ static struct page *gen_alloc(struct pag return alloc_pages(flags, order); } -static void gen_free(struct page_allocator *a, struct page *page, int order) +static void gen_free(const struct page_allocator *a, struct page *page, int order) { __free_pages(page, order); } -struct page_allocator page_allocator = { +const struct page_allocator page_allocator = { .allocate = gen_alloc, .free = gen_free, - .destructor = null_destructor + .destructor = null_destructor, + .name = "page_allocator" }; /* * Allocate vmalloc memory */ -static struct page *vmalloc_alloc(struct page_allocator *a, int order, +static struct page *vmalloc_alloc(const struct page_allocator *a, int order, gfp_t flags, int node) { void *addr; @@ -67,15 +68,16 @@ static struct page *vmalloc_alloc(struct return virt_to_page(addr); } -static void vmalloc_free(struct page_allocator *a, struct page *page, int order) +static void vmalloc_free(const struct page_allocator *a, struct page *page, int order) { vfree(page_address(page)); } -struct page_allocator vmalloc_allocator = { +const struct page_allocator vmalloc_allocator = { .allocate = vmalloc_alloc, .free = vmalloc_free, - .destructor = null_destructor + .destructor = null_destructor, + .name = "vmalloc_allocator" }; /* @@ -85,7 +87,7 @@ void derived_destructor(struct page_allo { struct derived_page_allocator *d = (void *)a; - d->base->destructor(d->base); + d->base->destructor((struct page_allocator *)d->base); kfree(a); } @@ -94,14 +96,14 @@ void derived_destructor(struct page_allo * is duplicated except for the destructor. The caller needs to do * modifications to some of the methods in the copy. */ -struct derived_page_allocator *derive_page_allocator(struct page_allocator *base) +struct derived_page_allocator *derive_page_allocator(const struct page_allocator *base) { struct derived_page_allocator *d = kmalloc(sizeof(struct derived_page_allocator), GFP_KERNEL); - d->a.private = base->private; d->a.allocate = base->allocate; d->a.free = base->free; + d->a.name = "derived"; d->a.destructor = derived_destructor; d->base = base; return d; @@ -132,7 +134,7 @@ static void page_free_rcu(struct rcu_hea /* * Use page struct as intermediate rcu storage. */ -static void rcu_free(struct page_allocator *a, struct page *page, int order) +static void rcu_free(const struct page_allocator *a, struct page *page, int order) { struct rcu_head *head = (void *)&page->lru; struct derived_page_allocator *d = (void *)a; @@ -142,18 +144,19 @@ static void rcu_free(struct page_allocat call_rcu(head, page_free_rcu); } -struct page_allocator *rcuify_allocator(struct page_allocator *base) +struct page_allocator *rcuify_page_allocator(const struct page_allocator *base) { struct derived_page_allocator *d = derive_page_allocator(base); d->a.free = rcu_free; + d->a.name = "rcu"; return &d->a; }; /* * Restrict memory allocations to DMA */ -static struct page *dma_alloc(struct page_allocator *a, int order, +static struct page *dma_alloc(const struct page_allocator *a, int order, gfp_t flags, int node) { struct derived_page_allocator *d = (void *)a; @@ -161,11 +164,12 @@ static struct page *dma_alloc(struct pag return d->base->allocate(d->base, order, flags | __GFP_DMA, node); } -struct page_allocator *dmaify_allocator(struct page_allocator *base) +struct page_allocator *dmaify_page_allocator(const struct page_allocator *base) { struct derived_page_allocator *d = derive_page_allocator(base); d->a.allocate = dma_alloc; + d->a.name = "dma"; return &d->a; } @@ -175,14 +179,14 @@ struct page_allocator *dmaify_allocator( */ struct deconstructor { struct page_allocator a; - struct page_allocator *base; + const struct page_allocator *base; unsigned int size; void *private; void (*ctor)(void *, void *, unsigned long); void (*dtor)(void *, void *, unsigned long); }; -static struct page *ctor_alloc(struct page_allocator *a, +static struct page *ctor_alloc(const struct page_allocator *a, int order, gfp_t flags, int node) { struct deconstructor *d = (void *)a; @@ -200,7 +204,7 @@ static struct page *ctor_alloc(struct pa return page; } -static void dtor_free(struct page_allocator *a, +static void dtor_free(const struct page_allocator *a, struct page *page, int order) { struct deconstructor *d = (void *)a; @@ -216,7 +220,7 @@ static void dtor_free(struct page_alloca d->base->free(d->base, page, order); } -struct page_allocator *deconstructify_allocator(struct page_allocator *base, +struct page_allocator *ctor_and_dtor_for_page_allocator(const struct page_allocator *base, size_t size, void *private, void (*ctor)(void *, void *, unsigned long), void (*dtor)(void *, void *, unsigned long)) @@ -224,10 +228,10 @@ struct page_allocator *deconstructify_al struct deconstructor *d = kmalloc(sizeof(struct deconstructor), GFP_KERNEL); - d->a.private = base->private; - d->a.allocate = ctor_alloc; - d->a.free = dtor_free; + d->a.allocate = ctor ? ctor_alloc : base->allocate; + d->a.free = dtor ? dtor_free : base->free; d->a.destructor = derived_destructor; + d->a.name = "ctor_dtor"; d->base = base; d->ctor = ctor; d->dtor = dtor; @@ -236,41 +240,163 @@ struct page_allocator *deconstructify_al return &d->a; } -#ifdef CONFIG_NUMA + /* - * Numacontrol for allocators + * Slab allocators */ -struct numactl { - struct page_allocator a; - struct page_allocator *base; - int node; - gfp_t flags; + +/* Tools to make your own */ +void null_slab_allocator_destructor(struct slab_allocator *a) +{ +} + +void derived_slab_destructor(struct slab_allocator *a) { + struct derived_slab_allocator *d = (void *)a; + + d->base->destructor((struct slab_allocator *)d->base); + kfree(d); +} + +struct derived_slab_allocator *derive_slab_allocator( + const struct slab_allocator *base) { + struct derived_slab_allocator *d = + kmalloc(sizeof(struct derived_slab_allocator), GFP_KERNEL); + + memcpy(&d->a, base, sizeof(struct slab_allocator)); + d->base = base; + d->a.name = "derived"; + d->a.destructor = derived_slab_destructor; + return d; +} + +/* Generate a new slab allocators based on old ones */ + +/* + * First a generic method to rcuify any slab. We add the rcuhead + * to the end of the object and use that on free. + */ + +struct rcuified_slab { + struct slab_allocator *a; + const struct slab_allocator *base; + unsigned int rcu_offset; }; -static struct page *numactl_alloc(struct page_allocator *a, - int order, gfp_t flags, int node) +/* + * Information that is added to the end of the slab + */ +struct slabr { + struct rcu_head r; + struct slab_cache *s; +}; + +struct slab_cache *rcuify_slab_create(const struct slab_allocator *sa, + const struct page_allocator *pa, int node, + const char *name, int size, int align, int order, + int objsize, int inuse, int offset) { - struct numactl *d = (void *)a; + struct rcuified_slab *d = (void *)sa; + + inuse = d->rcu_offset = ALIGN(inuse, sizeof(void *)); + inuse += sizeof(struct slabr) + sizeof(void *); + while (inuse > size) + size += align; - if (d->node >= 0) - node = d->node; + return d->base->create(d->base, pa, node, name, size, align, + order, objsize, inuse, offset); +} + +void rcu_slab_free(struct rcu_head *rcu) +{ + struct slabr *r = (void *) rcu; + struct slab_cache *s = r->s; + struct rcuified_slab *d = (void *)s->slab_alloc; + void *object = (void *)object - d->rcu_offset; - return d->base->allocate(d->base, order, flags | d->flags, node); + d->base->free(s, object); } +void rcuify_slab_free(struct slab_cache *s, const void *object) +{ + struct rcuified_slab *r = (struct rcuified_slab *)(s->slab_alloc); + + call_rcu((struct rcu_head *)(object + r->rcu_offset), rcu_slab_free); +} -struct page_allocator *numactl_allocator(struct page_allocator *base, - int node, gfp_t flags) +struct slab_allocator *rcuify_slab_allocator(const struct slab_allocator *base) { - struct numactl *d = - kmalloc(sizeof(struct numactl), GFP_KERNEL); + struct derived_slab_allocator *d = derive_slab_allocator(base); - d->a.private = base->private; - d->a.allocate = numactl_alloc; - d->a.destructor = derived_destructor; - d->base = base; - d->node = node; - d->flags = flags; + d->a.create = rcuify_slab_create; + d->a.free = rcuify_slab_free; + d->a.name = "rcu"; return &d->a; } + + +/* + * dmaification of slab allocation. This is done by dmaifying the + * underlying page allocator. + */ + +struct slab_cache *dmaify_slab_create(const struct slab_allocator *s, + const struct page_allocator *a, int node, const char *name, + int size, int align, int order, int objsize, int inuse, + int offset) +{ + struct derived_slab_allocator *d = (void *)s; + + return d->base->create(s, dmaify_page_allocator(a), node, name, + size, align, order, objsize, inuse, offset); +} + +struct slab_allocator *dmaify_slab_allocator(const struct slab_allocator *base) +{ + struct derived_slab_allocator *d = derive_slab_allocator(base); + + d->a.create = dmaify_slab_create; + d->a.name = "dma"; + return &d->a; +} + +#if 0 +/* + * Generic Redzoning support works by adding a word at the end + * of an object and filling up to the beginning of the next + * object (depending on the gap between objects). + * + * The fillings are different on free and allocate so that + * we can check on each if the object or the guard area was + * corrupted. + */ +struct slab_allocator *redzone_slab_allocator(struct slab_allocator *base) +{ + struct derived_slab_allocat *d = derive_slab_allcator(base); + + d->create = redzone_create; + d->alloc = redzone_alloc; + d->free = redzone_free; + return &d->aL; +} + +/* + * Object tracking adds two words to the end of the slab that track + * the latest allocator and the last freeer of the object. + */ +struct slab_allocator *track_slab_allocator(struct slab_allocator *base) +{ + return NULL; +} + +/* + * Write to the syslog whenever something happens on a slab. + * + * CAUTION: Do not try this on busy system slabs. + */ +struct slab_allocator *trace_slab_allocator(struct slab_allocator *base) +{ + return NULL; +} #endif + + Index: linux-2.6.18-rc4/include/linux/allocator.h =================================================================== --- linux-2.6.18-rc4.orig/include/linux/allocator.h 2006-08-14 21:06:41.101101857 -0700 +++ linux-2.6.18-rc4/include/linux/allocator.h 2006-08-15 13:47:22.741805560 -0700 @@ -22,16 +22,16 @@ */ struct page_allocator { - struct page *(*allocate)(struct page_allocator *, int order, + struct page *(*allocate)(const struct page_allocator *, int order, gfp_t mask, int node); - void (*free)(struct page_allocator *, struct page *, int order); + void (*free)(const struct page_allocator *, struct page *, int order); void (*destructor) (struct page_allocator *); - void *private; + const char *name; }; /* Some known page allocators */ -extern struct page_allocator page_allocator; -extern struct page_allocator vmalloc_allocator; +extern const struct page_allocator page_allocator; +extern const struct page_allocator vmalloc_allocator; /* * Generators for new allocators based on known allocators @@ -45,13 +45,13 @@ extern struct page_allocator vmalloc_all * struct page so this fully transparent and does not require any * allocation and freeing of memory. */ -struct page_allocator *rcuify_allocator(struct page_allocator *base); +struct page_allocator *rcuify_page_allocator(const struct page_allocator *base); /* * Make an allocation via a specific allocator always return * DMA memory. */ -struct page_allocator *dmaify_allocator(struct page_allocator *base); +struct page_allocator *dmaify_page_allocator(const struct page_allocator *base); /* * This provides a constructor and a destructor call for each object @@ -63,8 +63,8 @@ struct page_allocator *dmaify_allocator( * and destructors. These run after a page was allocated and before * a page is freed. */ -struct page_allocator *deconstructify_allocator(struct page_allocator *, - unsigned long size, void *private, +struct page_allocator *ctor_and_dtor_for_page_allocator( + const struct page_allocator *, unsigned long size, void *private, void (*ctor)(void *, void *, unsigned long), void (*dtor)(void *, void *, unsigned long)); @@ -76,19 +76,152 @@ struct page_allocator *deconstructify_al * F.e. one can set GFP_THISNODE to force an allocation on a particular node * or on a local node. */ -struct page_allocator *numactl_allocator(struct page_allocator *, int node, +struct page_allocator *numactl_allocator(const struct page_allocator *, int node, gfp_t flags); #endif /* Tools to make your own */ struct derived_page_allocator { struct page_allocator a; - struct page_allocator *base; + const struct page_allocator *base; }; void derived_destructor(struct page_allocator *a); struct derived_page_allocator *derive_page_allocator( - struct page_allocator *base); + const struct page_allocator *base); + +/* + * Slab allocators + */ + + +/* + * A slab cache structure is generated by a slab allocator when the create method + * is invoked. + */ +struct slab_cache { + const struct slab_allocator *slab_alloc; + const struct page_allocator *page_alloc; + const char *name; /* Name (only for display!) */ + int size; /* The size of a chunk on a slab */ + int align; /* Alignment requirements */ + int objsize; /* The size of an object that is in a chunk */ + int inuse; /* Used portion of the chunk */ + int offset; /* Offset to the freelist pointer */ + unsigned int order; /* Size of the slab page */ +}; + +struct slab_allocator { + /* + * Create an actually usable slab cache from a slab allocator + */ + struct slab_cache *(*create)(const struct slab_allocator *, + const struct page_allocator *a, const char *name, int size, int align, + int order, int objsize, int inuse, int offset); + + /* Allocation functions */ + void *(*alloc)(struct slab_cache *, gfp_t); + void *(*alloc_node)(struct slab_cache *, gfp_t, int); + void (*free)(struct slab_cache *, const void *); + + /* Object checks */ + int (*valid_pointer)(struct slab_cache *, const void *object); + unsigned long (*object_size)(struct slab_cache *, const void *); + + /* + * Determine slab statistics in units of slabs. Returns the + * number of total pages used by the slab cache. + * active are the pages under allocation or empty + * partial are the number of partial slabs. + */ + unsigned long (*objects)(struct slab_cache *, unsigned long *active, + unsigned long *partial); + + /* + * shrink defragments a slab cache by moving objects from sparsely + * populated slabs to others. slab shrink will terminate when there + * is only one fragmented slab left. + * + * The move_object function must be supplied otherwise shrink can only + * free pages that are competely empty. + * + * move_object gets a slab_cache pointer and an object pointer. The + * function must reallocate another object and move the contents + * from this object into the new object. Then the function should + * return 1 for success. If it return 0 then the object is pinned. + * the slab that the object resides on will not be freed. + */ + int (*shrink)(struct slab_cache *, + int (*move_object)(struct slab_cache *, void *)); + + /* + * The NUMA slab provides an array of slab caches. This is a means + * to get to the slab cache on a particular node. But beware! + * The resulting slab_cache belongs to another allocator. + */ + struct slab_cache *(*node)(struct slab_cache *, int node); + + /* + * Establish a new reference so that destroy does not + * unecessarilyl destroy the slab_cache + */ + struct slab_cache * (*dup)(struct slab_cache *); + int (*destroy)(struct slab_cache *); + void (*destructor)(struct slab_allocator *); + void *name; +}; + +/* Standard slab allocators */ +extern const struct slab_allocator slab_allocator; /* The original one */ +extern const struct slab_allocator slob_allocator; +extern const struct slab_allocator slabifier_allocator; + +/* Use page allocator for slab (allocation size in pages) */ +extern struct slab_allocator page_slab_allocator; + +/* Access kmalloc's fixed slabs without creating new ones. */ +extern struct slab_allocator kmalloc_slab_allocator; + +#ifdef CONFIG_NUMA +extern const struct slab_allocator numa_slab_allocator; +#endif + +/* Generate new slab allocators based on old ones */ +struct slab_allocator *rcuify_slab(struct slab_allocator *base); +struct slab_allocator *dmaify_slab(struct slab_allocator *base); +struct slab_allocator *redzone_slab(struct slab_allocator *base); +struct slab_allocator *track_slab(struct slab_allocator *base); +struct slab_allocator *trace_slab(struct slab_allocator *base); + +/* Tools to make your own slab allocators */ +static inline void slab_allocator_fill(struct slab_cache *sc, + const struct slab_allocator *slab_alloc, const struct page_allocator *page_alloc, + const char *name, int size, int align, + int order, int objsize, int inuse, int offset) +{ + sc->slab_alloc = slab_alloc; + sc->page_alloc = page_alloc; + sc->name = name; + sc->size = size; + sc->align = align; + sc->order = order; + sc->objsize = objsize; + sc->inuse = inuse; + sc->offset = offset; +} + +/* Indestructible static allocators use this. */ +void null_slab_allocator_destructor(struct slab_allocator *); + +struct derived_slab_allocator { + struct slab_allocator a; + const struct slab_allocator *base; +}; + +void derived_slab_destructor(struct slab_allocator *a); + +struct derived_slab_allocator *derive_slab_allocator( + const struct slab_allocator *base); #endif /* _LINUX_ALLOCATOR_H */