Repeated similar panics on -STABLE
Terry Lambert
tlambert2 at mindspring.com
Sat Apr 19 12:07:57 PDT 2003
Don Lewis wrote:
> Ok, here's a Reader's Digest version of the code in question:
>
> if (kbp->kb_next == NULL) {
> kbp->kb_last = NULL;
> if (size > MAXALLOCSAVE)
> allocsize = roundup(size, PAGE_SIZE);
> else
> allocsize = 1 << indx;
> npg = btoc(allocsize);
> va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags
> );
> /*
> * Just in case we blocked while allocating memory,
> * and someone else also allocated memory for this
> * bucket, don't assume the list is still empty.
> */
> savedlist = kbp->kb_next;
> kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
> for (;;) {
> freep = (struct freelist *)cp;
> if (cp <= va)
> break;
> cp -= allocsize;
> freep->next = cp;
> }
> freep->next = savedlist;
Take an interrupt somewhere around here, and have the available
entries removed from the freelist by an interrupt level driver.
Or take a page fault, and have the same thing happen with
page-related metadata coming from the freelist in question.
> if (kbp->kb_last == NULL)
> kbp->kb_last = (caddr_t)freep;
> }
> va = kbp->kb_next;
> kbp->kb_next = ((struct freelist *)va)->next;
[ ... ]
> This code bothers me, though, because if allocsize ever happened to not
> evenly divide (npg * PAGE_SIZE), the loop termination condition would be
> wrong and the end of the previous page (or more) would end up on the
> free list. If va were small enough and allocsize were big enough, it
> would even be possible to wrap around.
That actually can't happen. Basically, the allocators "waste"
the ends of pages. See the:
if (cp <= va)
break;
cp -= allocsize;
? The "<= saves you.
-- Terry
More information about the freebsd-hackers
mailing list