[PATCH] slab: fix offslab_limit in calculate_slab_order (Was: Slabcorruption in 2.6.16-rc5-mm2)

From: Pekka J Enberg
Date: Tue Mar 07 2006 - 03:48:12 EST


On Mon, 6 Mar 2006, Linus Torvalds wrote:
> In particular, as far as I can tell, that
>
> + /* More than offslab_limit objects will cause problems */
> + if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit)
> + break;
>
> has been incorrectly translated for several reasons:
>
> - we shouldn't check "cachep->num > offslab_limit". We should check just
> "num > offslab_limit" (cachep->num is the _previous_ number we tested).
>
> - when we do "break", we've already incremented "gfporder", and we should
> correct for that.
>
> Now, maybe I'm just off my rocker again (I've certainly been batting 0.000
> so far, even if I think I've been finding real bugs). So who knows. But I
> get the feeling that that patch is broken.
>
> Either revert it, or try this (TOTALLY UNTESTED!!!) patch..
>
> And hey, maybe I'm just crazy.

No you're not, it's broken. However, I think you're forgetting to reset
cachep->num when we go over MAX_GFP_ORDER, no? This patch boots although
I don't hit offslab limit.

Pekka

[PATCH] slab: fix offslab_limit in calculate_slab_order

From: Linus Torvalds <torvalds@xxxxxxxx>

The commit "[PATCH] slab: extract slab order calculation to separate
function" broke offslab_limit handling:

- We should check for num instead of cachep->num because the latter
is the number of objects for the _previous_ gfp order.

- After hitting the offslab_limit, we need to correct gfporder and
calculate left_over and cachep->num for that before exiting. We
do this by keeping current state in local variables and previous
state in cachep.

Linus spotted the problem and wrote the patch. I fixed gfporder
resetting when we go over MAX_GFP_ORDER and tested it with UM.

Cc: Andrew Morton <akpm@xxxxxxxx>
Signed-off-by: Pekka Enberg <penberg@xxxxxxxxxxxxxx>
---

diff --git a/mm/slab.c b/mm/slab.c
index add05d8..fe63479 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1628,25 +1628,22 @@ static inline size_t calculate_slab_orde
size_t size, size_t align, unsigned long flags)
{
size_t left_over = 0;
+ int gfporder;

- for (;; cachep->gfporder++) {
+ for (gfporder = 0 ; gfporder <= MAX_GFP_ORDER; gfporder++) {
unsigned int num;
size_t remainder;

- if (cachep->gfporder > MAX_GFP_ORDER) {
- cachep->num = 0;
- break;
- }
-
- cache_estimate(cachep->gfporder, size, align, flags,
- &remainder, &num);
+ cache_estimate(gfporder, size, align, flags, &remainder, &num);
if (!num)
continue;
+
/* More than offslab_limit objects will cause problems */
- if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit)
+ if ((flags & CFLGS_OFF_SLAB) && num > offslab_limit)
break;

cachep->num = num;
+ cachep->gfporder = gfporder;
left_over = remainder;

/*
@@ -1660,6 +1657,9 @@ static inline size_t calculate_slab_orde
/* Acceptable internal fragmentation */
break;
}
+ if (cachep->gfporder > MAX_GFP_ORDER)
+ cachep->num = 0;
+
return left_over;
}

-
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/