mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Fixed 2 bugs in kmalloc. (phew)
When allocating a new area, the alignment calculation of new area structure was wrong. Hopefully this is now fixed. The original function with bad alignment was preserved. When freeing a new area and merging it with adjacent areas, pointer to previous area was mistakenly used instead of pointer to next. modified: tasks/libmem/kmalloc/kmalloc.c
This commit is contained in:
@@ -105,13 +105,84 @@ void kmalloc_init()
|
||||
/* NOTE: If needed, initialise mutex here */
|
||||
}
|
||||
|
||||
static struct km_area *
|
||||
find_free_km_area(int size, struct list_head *km_areas)
|
||||
{
|
||||
struct km_area *new;
|
||||
struct km_area *area;
|
||||
const unsigned long max = SZ_WORD - 1;
|
||||
int used= 0, unused = 0;
|
||||
|
||||
/* The minimum size needed if the area will be divided into two */
|
||||
int dividable = size + sizeof(struct km_area) + max;
|
||||
|
||||
list_for_each_entry (area, km_areas, list) {
|
||||
/* Is this a free region that fits? */
|
||||
if ((area->size) >= dividable && !area->used) {
|
||||
unsigned long addr, aligned;
|
||||
|
||||
/*
|
||||
* Cut the free area from the end, as much as
|
||||
* we want to use
|
||||
*/
|
||||
area->size -= size + sizeof(struct km_area);
|
||||
|
||||
addr = (area->vaddr + area->size);
|
||||
aligned = align(addr, SZ_WORD); /* Align by rewinding */
|
||||
used = addr - aligned; /* We rewinded this much bytes */
|
||||
unused = max - used;
|
||||
|
||||
/*
|
||||
* Reduce the extra bit that's rewinded for alignment
|
||||
* to original subpage
|
||||
*/
|
||||
area->size -= used;
|
||||
|
||||
/*
|
||||
* Allocate the new link structure at the end
|
||||
* of the free area shortened previously.
|
||||
*/
|
||||
new = (struct km_area *)aligned;
|
||||
|
||||
/*
|
||||
* Actual allocated memory starts after subpage
|
||||
* descriptor
|
||||
*/
|
||||
new->vaddr = (unsigned long)new
|
||||
+ sizeof(struct km_area);
|
||||
new->size = size + sizeof(struct km_area)
|
||||
+ used;
|
||||
new->used = 1;
|
||||
|
||||
/* Divides other allocated page(s) */
|
||||
new->pg_alloc_pages = 0;
|
||||
|
||||
/* Add used region to the page area list */
|
||||
INIT_LIST_HEAD(&new->list);
|
||||
list_add(&new->list, &area->list);
|
||||
return new;
|
||||
|
||||
} else if (area->size < dividable &&
|
||||
area->size >= size && !area->used) {
|
||||
/*
|
||||
* Area not at dividable size but can satisfy request,
|
||||
* so it's simply returned.
|
||||
*/
|
||||
area->used = 1;
|
||||
return area;
|
||||
}
|
||||
}
|
||||
/* Traversed all areas and can't satisfy request. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a free list, finds a free region of requested size plus one subpage
|
||||
* area descriptor. Allocates and initialises the new descriptor, adds it to
|
||||
* the list and returns it.
|
||||
*/
|
||||
static struct km_area *
|
||||
find_free_km_area(int size, struct list_head *km_areas)
|
||||
struct km_area *
|
||||
find_free_km_area_orig(int size, struct list_head *km_areas)
|
||||
{
|
||||
struct km_area *new;
|
||||
struct km_area *area;
|
||||
@@ -339,7 +410,7 @@ found:
|
||||
if (area->list.next != areas) {
|
||||
next = list_entry(area->list.next, struct km_area, list);
|
||||
if (!next->used)
|
||||
if ((merged = km_merge_free_areas(prev, area)))
|
||||
if ((merged = km_merge_free_areas(area, next)))
|
||||
area = merged;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user