mm/sl[aou]b: Common alignment code
Extract the code to do object alignment from the allocators. Do the alignment calculations in slab_common so that the __kmem_cache_create functions of the allocators do not have to deal with alignment. Signed-off-by: Christoph Lameter <cl@linux.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
parent
2f9baa9fcf
commit
4590685546
20
mm/slab.c
20
mm/slab.c
|
@ -2337,22 +2337,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
|
||||||
size &= ~(BYTES_PER_WORD - 1);
|
size &= ~(BYTES_PER_WORD - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate the final buffer alignment: */
|
|
||||||
|
|
||||||
/* 1) arch recommendation: can be overridden for debug */
|
|
||||||
if (flags & SLAB_HWCACHE_ALIGN) {
|
|
||||||
/*
|
|
||||||
* Default alignment: as specified by the arch code. Except if
|
|
||||||
* an object is really small, then squeeze multiple objects into
|
|
||||||
* one cacheline.
|
|
||||||
*/
|
|
||||||
ralign = cache_line_size();
|
|
||||||
while (size <= ralign / 2)
|
|
||||||
ralign /= 2;
|
|
||||||
} else {
|
|
||||||
ralign = BYTES_PER_WORD;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Redzoning and user store require word alignment or possibly larger.
|
* Redzoning and user store require word alignment or possibly larger.
|
||||||
* Note this will be overridden by architecture or caller mandated
|
* Note this will be overridden by architecture or caller mandated
|
||||||
|
@ -2369,10 +2353,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
|
||||||
size &= ~(REDZONE_ALIGN - 1);
|
size &= ~(REDZONE_ALIGN - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2) arch mandated alignment */
|
|
||||||
if (ralign < ARCH_SLAB_MINALIGN) {
|
|
||||||
ralign = ARCH_SLAB_MINALIGN;
|
|
||||||
}
|
|
||||||
/* 3) caller mandated alignment */
|
/* 3) caller mandated alignment */
|
||||||
if (ralign < cachep->align) {
|
if (ralign < cachep->align) {
|
||||||
ralign = cachep->align;
|
ralign = cachep->align;
|
||||||
|
|
|
@ -32,6 +32,9 @@ extern struct list_head slab_caches;
|
||||||
/* The slab cache that manages slab cache information */
|
/* The slab cache that manages slab cache information */
|
||||||
extern struct kmem_cache *kmem_cache;
|
extern struct kmem_cache *kmem_cache;
|
||||||
|
|
||||||
|
unsigned long calculate_alignment(unsigned long flags,
|
||||||
|
unsigned long align, unsigned long size);
|
||||||
|
|
||||||
/* Functions provided by the slab allocators */
|
/* Functions provided by the slab allocators */
|
||||||
extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags);
|
extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags);
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,34 @@ static inline int kmem_cache_sanity_check(const char *name, size_t size)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out what the alignment of the objects will be given a set of
|
||||||
|
* flags, a user specified alignment and the size of the objects.
|
||||||
|
*/
|
||||||
|
unsigned long calculate_alignment(unsigned long flags,
|
||||||
|
unsigned long align, unsigned long size)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If the user wants hardware cache aligned objects then follow that
|
||||||
|
* suggestion if the object is sufficiently large.
|
||||||
|
*
|
||||||
|
* The hardware cache alignment cannot override the specified
|
||||||
|
* alignment though. If that is greater then use it.
|
||||||
|
*/
|
||||||
|
if (flags & SLAB_HWCACHE_ALIGN) {
|
||||||
|
unsigned long ralign = cache_line_size();
|
||||||
|
while (size <= ralign / 2)
|
||||||
|
ralign /= 2;
|
||||||
|
align = max(align, ralign);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (align < ARCH_SLAB_MINALIGN)
|
||||||
|
align = ARCH_SLAB_MINALIGN;
|
||||||
|
|
||||||
|
return ALIGN(align, sizeof(void *));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kmem_cache_create - Create a cache.
|
* kmem_cache_create - Create a cache.
|
||||||
* @name: A string which is used in /proc/slabinfo to identify this cache.
|
* @name: A string which is used in /proc/slabinfo to identify this cache.
|
||||||
|
@ -124,7 +152,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align
|
||||||
s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
|
s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
|
||||||
if (s) {
|
if (s) {
|
||||||
s->object_size = s->size = size;
|
s->object_size = s->size = size;
|
||||||
s->align = align;
|
s->align = calculate_alignment(flags, align, size);
|
||||||
s->ctor = ctor;
|
s->ctor = ctor;
|
||||||
s->name = kstrdup(name, GFP_KERNEL);
|
s->name = kstrdup(name, GFP_KERNEL);
|
||||||
if (!s->name) {
|
if (!s->name) {
|
||||||
|
@ -211,7 +239,7 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t siz
|
||||||
|
|
||||||
s->name = name;
|
s->name = name;
|
||||||
s->size = s->object_size = size;
|
s->size = s->object_size = size;
|
||||||
s->align = ARCH_KMALLOC_MINALIGN;
|
s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
|
||||||
err = __kmem_cache_create(s, flags);
|
err = __kmem_cache_create(s, flags);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
|
10
mm/slob.c
10
mm/slob.c
|
@ -123,7 +123,6 @@ static inline void clear_slob_page_free(struct page *sp)
|
||||||
|
|
||||||
#define SLOB_UNIT sizeof(slob_t)
|
#define SLOB_UNIT sizeof(slob_t)
|
||||||
#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
|
#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
|
||||||
#define SLOB_ALIGN L1_CACHE_BYTES
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct slob_rcu is inserted at the tail of allocated slob blocks, which
|
* struct slob_rcu is inserted at the tail of allocated slob blocks, which
|
||||||
|
@ -527,20 +526,11 @@ EXPORT_SYMBOL(ksize);
|
||||||
|
|
||||||
int __kmem_cache_create(struct kmem_cache *c, unsigned long flags)
|
int __kmem_cache_create(struct kmem_cache *c, unsigned long flags)
|
||||||
{
|
{
|
||||||
size_t align = c->size;
|
|
||||||
|
|
||||||
if (flags & SLAB_DESTROY_BY_RCU) {
|
if (flags & SLAB_DESTROY_BY_RCU) {
|
||||||
/* leave room for rcu footer at the end of object */
|
/* leave room for rcu footer at the end of object */
|
||||||
c->size += sizeof(struct slob_rcu);
|
c->size += sizeof(struct slob_rcu);
|
||||||
}
|
}
|
||||||
c->flags = flags;
|
c->flags = flags;
|
||||||
/* ignore alignment unless it's forced */
|
|
||||||
c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
|
|
||||||
if (c->align < ARCH_SLAB_MINALIGN)
|
|
||||||
c->align = ARCH_SLAB_MINALIGN;
|
|
||||||
if (c->align < align)
|
|
||||||
c->align = align;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
mm/slub.c
38
mm/slub.c
|
@ -2760,32 +2760,6 @@ static inline int calculate_order(int size, int reserved)
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Figure out what the alignment of the objects will be.
|
|
||||||
*/
|
|
||||||
static unsigned long calculate_alignment(unsigned long flags,
|
|
||||||
unsigned long align, unsigned long size)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* If the user wants hardware cache aligned objects then follow that
|
|
||||||
* suggestion if the object is sufficiently large.
|
|
||||||
*
|
|
||||||
* The hardware cache alignment cannot override the specified
|
|
||||||
* alignment though. If that is greater then use it.
|
|
||||||
*/
|
|
||||||
if (flags & SLAB_HWCACHE_ALIGN) {
|
|
||||||
unsigned long ralign = cache_line_size();
|
|
||||||
while (size <= ralign / 2)
|
|
||||||
ralign /= 2;
|
|
||||||
align = max(align, ralign);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (align < ARCH_SLAB_MINALIGN)
|
|
||||||
align = ARCH_SLAB_MINALIGN;
|
|
||||||
|
|
||||||
return ALIGN(align, sizeof(void *));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_kmem_cache_node(struct kmem_cache_node *n)
|
init_kmem_cache_node(struct kmem_cache_node *n)
|
||||||
{
|
{
|
||||||
|
@ -2919,7 +2893,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
|
||||||
{
|
{
|
||||||
unsigned long flags = s->flags;
|
unsigned long flags = s->flags;
|
||||||
unsigned long size = s->object_size;
|
unsigned long size = s->object_size;
|
||||||
unsigned long align = s->align;
|
|
||||||
int order;
|
int order;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2990,20 +2963,12 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
|
||||||
size += sizeof(void *);
|
size += sizeof(void *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine the alignment based on various parameters that the
|
|
||||||
* user specified and the dynamic determination of cache line size
|
|
||||||
* on bootup.
|
|
||||||
*/
|
|
||||||
align = calculate_alignment(flags, align, s->object_size);
|
|
||||||
s->align = align;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SLUB stores one object immediately after another beginning from
|
* SLUB stores one object immediately after another beginning from
|
||||||
* offset 0. In order to align the objects we have to simply size
|
* offset 0. In order to align the objects we have to simply size
|
||||||
* each object to conform to the alignment.
|
* each object to conform to the alignment.
|
||||||
*/
|
*/
|
||||||
size = ALIGN(size, align);
|
size = ALIGN(size, s->align);
|
||||||
s->size = size;
|
s->size = size;
|
||||||
if (forced_order >= 0)
|
if (forced_order >= 0)
|
||||||
order = forced_order;
|
order = forced_order;
|
||||||
|
@ -3032,7 +2997,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
|
||||||
s->max = s->oo;
|
s->max = s->oo;
|
||||||
|
|
||||||
return !!oo_objects(s->oo);
|
return !!oo_objects(s->oo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
|
static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
|
||||||
|
|
Loading…
Reference in New Issue