slub,rcu: don't assume the size of struct rcu_head
The size of struct rcu_head may be changed. When it becomes larger, it will pollute the page array. We reserve some some bytes for struct rcu_head when a slab is allocated in this situation. Changed from V1: use VM_BUG_ON instead BUG_ON Acked-by: Christoph Lameter <cl@linux.com> Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Pekka Enberg
parent
ab9a0f196f
commit
da9a638c6f
30
mm/slub.c
30
mm/slub.c
@@ -1254,21 +1254,38 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
|
|||||||
__free_pages(page, order);
|
__free_pages(page, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define need_reserve_slab_rcu \
|
||||||
|
(sizeof(((struct page *)NULL)->lru) < sizeof(struct rcu_head))
|
||||||
|
|
||||||
static void rcu_free_slab(struct rcu_head *h)
|
static void rcu_free_slab(struct rcu_head *h)
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
|
||||||
page = container_of((struct list_head *)h, struct page, lru);
|
if (need_reserve_slab_rcu)
|
||||||
|
page = virt_to_head_page(h);
|
||||||
|
else
|
||||||
|
page = container_of((struct list_head *)h, struct page, lru);
|
||||||
|
|
||||||
__free_slab(page->slab, page);
|
__free_slab(page->slab, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_slab(struct kmem_cache *s, struct page *page)
|
static void free_slab(struct kmem_cache *s, struct page *page)
|
||||||
{
|
{
|
||||||
if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
|
if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
|
||||||
/*
|
struct rcu_head *head;
|
||||||
* RCU free overloads the RCU head over the LRU
|
|
||||||
*/
|
if (need_reserve_slab_rcu) {
|
||||||
struct rcu_head *head = (void *)&page->lru;
|
int order = compound_order(page);
|
||||||
|
int offset = (PAGE_SIZE << order) - s->reserved;
|
||||||
|
|
||||||
|
VM_BUG_ON(s->reserved != sizeof(*head));
|
||||||
|
head = page_address(page) + offset;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* RCU free overloads the RCU head over the LRU
|
||||||
|
*/
|
||||||
|
head = (void *)&page->lru;
|
||||||
|
}
|
||||||
|
|
||||||
call_rcu(head, rcu_free_slab);
|
call_rcu(head, rcu_free_slab);
|
||||||
} else
|
} else
|
||||||
@@ -2356,6 +2373,9 @@ static int kmem_cache_open(struct kmem_cache *s,
|
|||||||
s->flags = kmem_cache_flags(size, flags, name, ctor);
|
s->flags = kmem_cache_flags(size, flags, name, ctor);
|
||||||
s->reserved = 0;
|
s->reserved = 0;
|
||||||
|
|
||||||
|
if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
|
||||||
|
s->reserved = sizeof(struct rcu_head);
|
||||||
|
|
||||||
if (!calculate_sizes(s, -1))
|
if (!calculate_sizes(s, -1))
|
||||||
goto error;
|
goto error;
|
||||||
if (disable_higher_order_debug) {
|
if (disable_higher_order_debug) {
|
||||||
|
Reference in New Issue
Block a user