diff -urNp vm/include/linux/sched.h vm-7/include/linux/sched.h --- vm/include/linux/sched.h Wed May 29 04:31:52 2002 +++ vm-7/include/linux/sched.h Wed May 29 04:35:13 2002 @@ -332,6 +332,18 @@ extern struct user_struct root_user; typedef struct prio_array prio_array_t; +struct zone_struct; + +/* + * Used when a task if trying to free some pages for its own + * use - to prevent other tasks/CPUs from stealing the just-freed + * pages. + */ +struct local_page { + struct page *page; + struct zone_struct * classzone; +}; + struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care @@ -367,9 +379,7 @@ struct task_struct { task_t *next_task, *prev_task; struct mm_struct *mm, *active_mm; - struct list_head local_pages; - - unsigned int allocation_order, nr_local_pages; + struct local_page local_page; /* task state */ struct linux_binfmt *binfmt; diff -urNp vm/kernel/fork.c vm-7/kernel/fork.c --- vm/kernel/fork.c Wed May 29 04:31:52 2002 +++ vm-7/kernel/fork.c Wed May 29 04:34:31 2002 @@ -679,7 +679,7 @@ int do_fork(unsigned long clone_flags, u p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; - INIT_LIST_HEAD(&p->local_pages); + p->local_page.page = NULL; retval = -ENOMEM; /* copy all the process information */ diff -urNp vm/mm/page_alloc.c vm-7/mm/page_alloc.c --- vm/mm/page_alloc.c Wed May 29 04:32:52 2002 +++ vm-7/mm/page_alloc.c Wed May 29 04:34:31 2002 @@ -101,7 +101,7 @@ static void __free_pages_ok (struct page BUG(); page->flags &= ~((1<flags & PF_FREE_PAGES) + if (order == 0 && current->flags & PF_FREE_PAGES) goto local_freelist; back_local_freelist: @@ -154,14 +154,12 @@ static void __free_pages_ok (struct page return; local_freelist: - if (current->nr_local_pages) + if ((current->local_page.page) || + !memclass(page_zone(page), current->local_page.classzone) || + in_interrupt()) goto back_local_freelist; - if (in_interrupt()) - goto back_local_freelist; - list_add(&page->list, ¤t->local_pages); - page->index = order; - current->nr_local_pages++; + current->local_page.page = page; } #define MARK_USED(index, order, area) \ @@ -248,70 +246,49 @@ static struct page * balance_classzone(z struct page * page = NULL; int __freed = 0; - if (!(gfp_mask & __GFP_WAIT)) - goto out; if (in_interrupt()) BUG(); - current->allocation_order = order; + if (current->local_page.page) + BUG(); + current->local_page.classzone = classzone; current->flags |= PF_MEMALLOC | PF_FREE_PAGES; __freed = try_to_free_pages(classzone, gfp_mask, order); current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES); - if (current->nr_local_pages) { - struct list_head * entry, * local_pages; - struct page * tmp; - int nr_pages; - - local_pages = ¤t->local_pages; - - if (likely(__freed)) { - /* pick from the last inserted so we're lifo */ - entry = local_pages->next; - do { - tmp = list_entry(entry, struct page, list); - if (tmp->index == order && memclass(page_zone(tmp), classzone)) { - list_del(entry); - current->nr_local_pages--; - set_page_count(tmp, 1); - page = tmp; - - if (page->buffers) - BUG(); - if (page->mapping) - BUG(); - if (!VALID_PAGE(page)) - BUG(); - if (PageSwapCache(page)) - BUG(); - if (PageLocked(page)) - BUG(); - if (PageLRU(page)) - BUG(); - if (PageActive(page)) - BUG(); - if (PageDirty(page)) - BUG(); - - break; - } - } while ((entry = entry->next) != local_pages); + if (current->local_page.page) { + page = current->local_page.page; + current->local_page.page = NULL; + + if (order != 0) { + /* The local page won't suit */ + __free_pages_ok(page, 0); + page = NULL; + goto out; } - - nr_pages = current->nr_local_pages; - /* free in reverse order so that the global order will be lifo */ - while ((entry = local_pages->prev) != local_pages) { - list_del(entry); - tmp = list_entry(entry, struct page, list); - __free_pages_ok(tmp, tmp->index); - if (!nr_pages--) - BUG(); - } - current->nr_local_pages = 0; + if (!memclass(page_zone(page), classzone)) + BUG(); + set_page_count(page, 1); + if (page->buffers) + BUG(); + if (page->mapping) + BUG(); + if (!VALID_PAGE(page)) + BUG(); + if (PageSwapCache(page)) + BUG(); + if (PageLocked(page)) + BUG(); + if (PageLRU(page)) + BUG(); + if (PageActive(page)) + BUG(); + if (PageDirty(page)) + BUG(); } - out: +out: *freed = __freed; return page; }