Re: kernel BUGs when removing largish files with the SLOB allocator

From: Aubrey
Date: Tue Sep 12 2006 - 04:04:31 EST


On 9/6/06, Nick Piggin <nickpiggin@xxxxxxxxxxxx> wrote:
Aubrey wrote:

> Yeah, I agree with most of your opinion. Using PG_slab is really a
> quickest way to determine the size of the object. But I think using a
> flag named "PG_slab" on a memory algorithm named "slob" seems not
> reasonable. It may confuse the people who start to read the kernel
> source code. So I'm writing to ask if there is a better solution to
> fix the issue.


No, confusing would be a "slab replacement" that doesn't provide the same
API as slab and thus requires users to use ifdefs.

I've already suggested exact same thing as David in the exact same situation
about 6 months ago. It is the right way to go.

OK. Here is the patch and work properly on my side.
Welcome any suggestions and comments.

Thanks,
-Aubrey
=================================================================
diff --git a/mm/slob.c b/mm/slob.c
index 7b52b20..18ed170 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -109,6 +109,7 @@ static void *slob_alloc(size_t size, gfp

slob_free(cur, PAGE_SIZE);
spin_lock_irqsave(&slob_lock, flags);
+ SetPageSlab(virt_to_page(cur));
cur = slobfree;
}
}
@@ -162,6 +163,8 @@ void *kmalloc(size_t size, gfp_t gfp)
slob_t *m;
bigblock_t *bb;
unsigned long flags;
+ int i;
+ struct page *page;

if (size < PAGE_SIZE - SLOB_UNIT) {
m = slob_alloc(size + SLOB_UNIT, gfp, 0);
@@ -173,12 +176,17 @@ void *kmalloc(size_t size, gfp_t gfp)
return 0;

bb->order = find_order(size);
- bb->pages = (void *)__get_free_pages(gfp, bb->order);
+ page = alloc_pages(gfp, bb->order);
+ bb->pages = (void *)page_address(page);

if (bb->pages) {
spin_lock_irqsave(&block_lock, flags);
bb->next = bigblocks;
bigblocks = bb;
+ for (i = 0; i < (1 << bb->order); i++) {
+ SetPageSlab(page);
+ page++;
+ }
spin_unlock_irqrestore(&block_lock, flags);
return bb->pages;
}
@@ -202,8 +210,16 @@ void kfree(const void *block)
spin_lock_irqsave(&block_lock, flags);
for (bb = bigblocks; bb; last = &bb->next, bb = bb->next) {
if (bb->pages == block) {
+ struct page *page = virt_to_page(bb->pages);
+ int i;
+
*last = bb->next;
spin_unlock_irqrestore(&block_lock, flags);
+ for (i = 0; i < (1 << bb->order); i++) {
+ if (!TestClearPageSlab(page))
+ BUG();
+ page++;
+ }
free_pages((unsigned long)block, bb->order);
slob_free(bb, sizeof(bigblock_t));
return;
@@ -332,10 +348,12 @@ static struct timer_list slob_timer = TI

void kmem_cache_init(void)
{
+#if 0
void *p = slob_alloc(PAGE_SIZE, 0, PAGE_SIZE-1);

if (p)
free_page((unsigned long)p);
+#endif

mod_timer(&slob_timer, jiffies + HZ);
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/