diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
commit | 03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch) | |
tree | 88db8dba75ae06ba3bad08e42c5e52efc162535c /mm | |
parent | 257730f99381dd26e10b832fce4c94cae7ac1176 (diff) |
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 8 | ||||
-rw-r--r-- | mm/memory.c | 1 | ||||
-rw-r--r-- | mm/mmap.c | 2 | ||||
-rw-r--r-- | mm/page_alloc.c | 3 | ||||
-rw-r--r-- | mm/page_io.c | 1 | ||||
-rw-r--r-- | mm/slab.c | 4 | ||||
-rw-r--r-- | mm/swap.c | 12 | ||||
-rw-r--r-- | mm/swap_state.c | 132 | ||||
-rw-r--r-- | mm/swapfile.c | 205 | ||||
-rw-r--r-- | mm/vmscan.c | 22 |
10 files changed, 250 insertions, 140 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index d0bf1270f..ffda2b7c1 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -7,7 +7,7 @@ /* * This file handles the generic file mmap semantics used by * most "normal" filesystems (but you don't /have/ to use this: - * the NFS filesystem does this differently, for example) + * the NFS filesystem used to do this differently, for example) */ #include <linux/stat.h> #include <linux/sched.h> @@ -172,12 +172,10 @@ static inline int shrink_one_page(struct page *page, int gfp_mask) break; } age_page(page); -#if 0 if (page->age) break; if (page_cache_size * 100 < (page_cache.min_percent * num_physpages)) break; -#endif if (PageSwapCache(page)) { delete_from_swap_cache(page); return 1; @@ -213,8 +211,8 @@ int shrink_mmap(int priority, int gfp_mask) struct page * page; int count_max, count_min; - count_max = (limit<<1) >> (priority>>1); - count_min = (limit<<1) >> (priority); + count_max = (limit<<2) >> (priority>>1); + count_min = (limit<<2) >> (priority); page = mem_map + clock; do { diff --git a/mm/memory.c b/mm/memory.c index 77a814f07..388d9ce03 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -35,7 +35,6 @@ #include <linux/signal.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> @@ -688,7 +688,7 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l mm->mmap_cache = NULL; /* Kill the cache. */ } -__initfunc(void vma_init(void)) +void __init vma_init(void) { vm_area_cachep = kmem_cache_create("vm_area_struct", sizeof(struct vm_area_struct), diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c51db59d9..70cad74eb 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -8,7 +8,6 @@ #include <linux/config.h> #include <linux/mm.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -318,7 +317,7 @@ void show_free_areas(void) * - mark all memory queues empty * - clear the memory bitmaps */ -__initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init free_area_init(unsigned long start_mem, unsigned long end_mem) { mem_map_t * p; unsigned long mask = PAGE_MASK; diff --git a/mm/page_io.c b/mm/page_io.c index 7e5a35186..44f592df8 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -11,7 +11,6 @@ #include <linux/mm.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -410,7 +410,7 @@ static kmem_cache_t *cache_slabp = NULL; static unsigned long bufctl_limit = 0; /* Initialisation - setup the `cache' cache. */ -__initfunc(long kmem_cache_init(long start, long end)) +long __init kmem_cache_init(long start, long end) { size_t size, i; @@ -464,7 +464,7 @@ __initfunc(long kmem_cache_init(long start, long end)) /* Initialisation - setup remaining internal and general caches. * Called after the gfp() functions have been enabled, and before smp_init(). */ -__initfunc(void kmem_cache_sizes_init(void)) +void __init kmem_cache_sizes_init(void) { unsigned int found = 0; @@ -15,7 +15,6 @@ #include <linux/mm.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -56,12 +55,15 @@ atomic_t nr_async_pages = ATOMIC_INIT(0); * Constants for the page aging mechanism: the maximum age (actually, * the maximum "youthfulness"); the quanta by which pages rejuvenate * and age; and the initial age for new pages. + * + * The "pageout_weight" is strictly a fixedpoint number with the + * ten low bits being the fraction (ie 8192 really means "8.0"). */ - swap_control_t swap_control = { 20, 3, 1, 3, /* Page aging */ 32, 4, /* Aging cluster */ - 8192, 8192, /* Pageout and bufferout weights */ + 8192, /* sc_pageout_weight aka PAGEOUT_WEIGHT */ + 8192, /* sc_bufferout_weight aka BUFFEROUT_WEIGHT */ }; swapstat_t swapstats = {0}; @@ -69,11 +71,11 @@ swapstat_t swapstats = {0}; buffer_mem_t buffer_mem = { 5, /* minimum percent buffer */ 25, /* borrow percent buffer */ - 50 /* maximum percent buffer */ + 60 /* maximum percent buffer */ }; buffer_mem_t page_cache = { - 10, /* minimum percent page cache */ + 5, /* minimum percent page cache */ 30, /* borrow percent page cache */ 75 /* maximum */ }; diff --git a/mm/swap_state.c b/mm/swap_state.c index 401c7a1fc..2aaf0c46b 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -9,7 +9,6 @@ #include <linux/mm.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -24,14 +23,6 @@ #include <asm/bitops.h> #include <asm/pgtable.h> -#ifdef SWAP_CACHE_INFO -unsigned long swap_cache_add_total = 0; -unsigned long swap_cache_add_success = 0; -unsigned long swap_cache_del_total = 0; -unsigned long swap_cache_del_success = 0; -unsigned long swap_cache_find_total = 0; -unsigned long swap_cache_find_success = 0; - /* * Keep a reserved false inode which we will use to mark pages in the * page cache are acting as swap cache instead of file cache. @@ -43,6 +34,13 @@ unsigned long swap_cache_find_success = 0; */ struct inode swapper_inode; +#ifdef SWAP_CACHE_INFO +unsigned long swap_cache_add_total = 0; +unsigned long swap_cache_add_success = 0; +unsigned long swap_cache_del_total = 0; +unsigned long swap_cache_del_success = 0; +unsigned long swap_cache_find_total = 0; +unsigned long swap_cache_find_success = 0; void show_swap_cache_info(void) { @@ -63,13 +61,13 @@ int add_to_swap_cache(struct page *page, unsigned long entry) page_address(page), atomic_read(&page->count), entry); #endif if (PageTestandSetSwapCache(page)) { - printk("swap_cache: replacing non-empty entry %08lx " + printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx " "on page %08lx\n", page->offset, page_address(page)); return 0; } if (page->inode) { - printk("swap_cache: replacing page-cached entry " + printk(KERN_ERR "swap_cache: replacing page-cached entry " "on page %08lx\n", page_address(page)); return 0; } @@ -85,12 +83,16 @@ int add_to_swap_cache(struct page *page, unsigned long entry) } /* - * If swap_map[] reaches 127, the entries are treated as "permanent". + * Verify that a swap entry is valid and increment its swap map count. + * + * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as + * "permanent", but will be reclaimed by the next swapoff. */ -void swap_duplicate(unsigned long entry) +int swap_duplicate(unsigned long entry) { struct swap_info_struct * p; unsigned long offset, type; + int result = 0; if (!entry) goto out; @@ -105,36 +107,44 @@ void swap_duplicate(unsigned long entry) goto bad_offset; if (!p->swap_map[offset]) goto bad_unused; - if (p->swap_map[offset] < 126) + /* + * Entry is valid, so increment the map count. + */ + if (p->swap_map[offset] < SWAP_MAP_MAX) p->swap_map[offset]++; else { static int overflow = 0; if (overflow++ < 5) - printk("swap_duplicate: entry %08lx map count=%d\n", + printk(KERN_WARNING + "swap_duplicate: entry %08lx map count=%d\n", entry, p->swap_map[offset]); - p->swap_map[offset] = 127; + p->swap_map[offset] = SWAP_MAP_MAX; } + result = 1; #ifdef DEBUG_SWAP printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n", entry, p->swap_map[offset]); #endif out: - return; + return result; bad_file: - printk("swap_duplicate: Trying to duplicate nonexistent swap-page\n"); + printk(KERN_ERR + "swap_duplicate: entry %08lx, nonexistent swap file\n", entry); goto out; bad_offset: - printk("swap_duplicate: offset exceeds max\n"); + printk(KERN_ERR + "swap_duplicate: entry %08lx, offset exceeds max\n", entry); goto out; bad_unused: - printk("swap_duplicate at %8p: unused page\n", - __builtin_return_address(0)); + printk(KERN_ERR + "swap_duplicate at %8p: entry %08lx, unused page\n", + __builtin_return_address(0), entry); goto out; } -void remove_from_swap_cache(struct page *page) +static inline void remove_from_swap_cache(struct page *page) { if (!page->inode) { printk ("VM: Removing swap cache page with zero inode hash " @@ -163,7 +173,7 @@ void remove_from_swap_cache(struct page *page) } -int delete_from_swap_cache(struct page *page) +void delete_from_swap_cache(struct page *page) { #ifdef SWAP_CACHE_INFO swap_cache_del_total++; @@ -180,9 +190,7 @@ int delete_from_swap_cache(struct page *page) #endif remove_from_swap_cache (page); swap_free (entry); - return 1; } - return 0; } /* @@ -218,57 +226,67 @@ static struct page * lookup_swap_cache(unsigned long entry) found = find_page(&swapper_inode, entry); if (!found) return 0; - if (found->inode != &swapper_inode - || !PageSwapCache(found)) { - __free_page(found); - printk ("VM: Found a non-swapper swap page!\n"); - return 0; - } + if (found->inode != &swapper_inode || !PageSwapCache(found)) + goto out_bad; if (!PageLocked(found)) return found; __free_page(found); __wait_on_page(found); } + +out_bad: + printk (KERN_ERR "VM: Found a non-swapper swap page!\n"); + __free_page(found); + return 0; } /* * Locate a page of swap in physical memory, reserving swap cache space * and reading the disk if it is not already cached. If wait==0, we are * only doing readahead, so don't worry if the page is already locked. + * + * A failure return means that either the page allocation failed or that + * the swap entry is no longer in use. */ struct page * read_swap_cache_async(unsigned long entry, unsigned long addr, int wait) { - struct page *found_page, *new_page = 0; - unsigned long new_page_addr = 0; + struct page *found_page, *new_page; + unsigned long new_page_addr; #ifdef DEBUG_SWAP printk("DebugVM: read_swap_cache_async entry %08lx%s\n", entry, wait ? ", wait" : ""); #endif -repeat: + /* + * Look for the page in the swap cache. + */ found_page = lookup_swap_cache(entry); - if (found_page) { - if (new_page) - __free_page(new_page); - return found_page; - } + if (found_page) + goto out; + + new_page_addr = __get_free_page(GFP_KERNEL); + if (!new_page_addr) + goto out; /* Out of memory */ + new_page = mem_map + MAP_NR(new_page_addr); + + /* + * Check the swap cache again, in case we stalled above. + */ + found_page = lookup_swap_cache(entry); + if (found_page) + goto out_free_page; + /* + * Make sure the swap entry is still in use. + */ + if (!swap_duplicate(entry)) /* Account for the swap cache */ + goto out_free_page; + /* + * Add it to the swap cache and read its contents. + */ + if (!add_to_swap_cache(new_page, entry)) + goto out_free_page; - /* The entry is not present. Lock down a new page, add it to - * the swap cache and read its contents. */ - if (!new_page) { - new_page_addr = get_user_page(addr); - if (!new_page_addr) - return 0; /* Out of memory */ - new_page = mem_map + MAP_NR(new_page_addr); - goto repeat; /* We might have stalled */ - } - - if (!add_to_swap_cache(new_page, entry)) { - free_page(new_page_addr); - return 0; - } - swap_duplicate(entry); /* Account for the swap cache */ set_bit(PG_locked, &new_page->flags); rw_swap_page(READ, entry, (char *) new_page_addr, wait); #ifdef DEBUG_SWAP @@ -277,5 +295,9 @@ repeat: entry, (char *) page_address(new_page)); #endif return new_page; -} +out_free_page: + __free_page(new_page); +out: + return found_page; +} diff --git a/mm/swapfile.c b/mm/swapfile.c index 45f73de02..b7446b3b5 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -9,7 +9,6 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -22,6 +21,7 @@ #include <linux/blkdev.h> /* for blk_size */ #include <linux/vmalloc.h> #include <linux/pagemap.h> +#include <linux/shm.h> #include <asm/bitops.h> #include <asm/pgtable.h> @@ -116,10 +116,7 @@ unsigned long get_swap_page(void) } } -/* - * If the swap count overflows (swap_map[] == 127), the entry is considered - * "permanent" and can't be reclaimed until the swap device is closed. - */ + void swap_free(unsigned long entry) { struct swap_info_struct * p; @@ -147,7 +144,7 @@ void swap_free(unsigned long entry) p->highest_bit = offset; if (!p->swap_map[offset]) goto bad_free; - if (p->swap_map[offset] < 127) { + if (p->swap_map[offset] < SWAP_MAP_MAX) { if (!--p->swap_map[offset]) nr_swap_pages++; } @@ -299,44 +296,55 @@ static int try_to_unuse(unsigned int type) { struct swap_info_struct * si = &swap_info[type]; struct task_struct *p; - unsigned long page = 0; struct page *page_map; - unsigned long entry; + unsigned long entry, page; int i; while (1) { /* * Find a swap page in use and read it in. */ - for (i = 1 , entry = 0; i < si->max ; i++) { - if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) { - entry = SWP_ENTRY(type, i); - break; + for (i = 1; i < si->max ; i++) { + if (si->swap_map[i] > 0 && si->swap_map[i] != SWAP_MAP_BAD) { + goto found_entry; } } - if (!entry) - break; + break; + + found_entry: + entry = SWP_ENTRY(type, i); /* Get a page for the entry, using the existing swap cache page if there is one. Otherwise, get a clean page and read the swap into it. */ page_map = read_swap_cache(entry, 0); - if (!page_map) + if (!page_map) { + /* + * Continue searching if the entry became unused. + */ + if (si->swap_map[i] == 0) + continue; return -ENOMEM; + } page = page_address(page_map); read_lock(&tasklist_lock); for_each_task(p) unuse_process(p->mm, entry, page); read_unlock(&tasklist_lock); + shm_unuse(entry, page); /* Now get rid of the extra reference to the temporary page we've been using. */ if (PageSwapCache(page_map)) delete_from_swap_cache(page_map); - free_page(page); + __free_page(page_map); + /* + * Check for and clear any overflowed swap map counts. + */ if (si->swap_map[i] != 0) { - if (si->swap_map[i] != 127) - printk("try_to_unuse: entry %08lx " - "not in use\n", entry); + if (si->swap_map[i] != SWAP_MAP_MAX) + printk(KERN_ERR + "try_to_unuse: entry %08lx count=%d\n", + entry, si->swap_map[i]); si->swap_map[i] = 0; nr_swap_pages++; } @@ -377,10 +385,9 @@ asmlinkage int sys_swapoff(const char * specialfile) prev = type; } err = -EINVAL; - if (type < 0){ - dput(dentry); - goto out; - } + if (type < 0) + goto out_dput; + if (prev < 0) { swap_list.head = p->next; } else { @@ -393,7 +400,6 @@ asmlinkage int sys_swapoff(const char * specialfile) p->flags = SWP_USED; err = try_to_unuse(type); if (err) { - dput(dentry); /* re-insert swap space back into swap_list */ for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next) if (p->prio >= swap_info[i].prio) @@ -404,7 +410,7 @@ asmlinkage int sys_swapoff(const char * specialfile) else swap_info[prev].next = p - swap_info; p->flags = SWP_WRITEOK; - goto out; + goto out_dput; } if(p->swap_device){ memset(&filp, 0, sizeof(filp)); @@ -419,16 +425,19 @@ asmlinkage int sys_swapoff(const char * specialfile) } dput(dentry); - nr_swap_pages -= p->pages; - dput(p->swap_file); + dentry = p->swap_file; p->swap_file = NULL; + nr_swap_pages -= p->pages; p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - free_page((long) p->swap_lockmap); + vfree(p->swap_lockmap); p->swap_lockmap = NULL; p->flags = 0; err = 0; + +out_dput: + dput(dentry); out: unlock_kernel(); return err; @@ -458,7 +467,7 @@ int get_swaparea_info(char *buf) usedswap = 0; for (j = 0; j < ptr->max; ++j) switch (ptr->swap_map[j]) { - case 128: + case SWAP_MAP_BAD: case 0: continue; default: @@ -486,7 +495,12 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) int error = -EPERM; struct file filp; static int least_priority = 0; - + union swap_header *swap_header = 0; + int swap_header_version; + int lock_map_size = PAGE_SIZE; + int nr_good_pages = 0; + unsigned long tmp_lock_map = 0; + lock_kernel(); if (!capable(CAP_SYS_ADMIN)) goto out; @@ -547,54 +561,114 @@ asmlinkage int sys_swapon(const char * specialfile, int swap_flags) } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + swap_header = (void *) __get_free_page(GFP_USER); + if (!swap_header) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) p->swap_lockmap); - if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { + + p->swap_lockmap = (char *) &tmp_lock_map; + rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) swap_header); + p->swap_lockmap = NULL; + + if (!memcmp("SWAP-SPACE",swap_header->magic.magic,10)) + swap_header_version = 1; + else if (!memcmp("SWAPSPACE2",swap_header->magic.magic,10)) + swap_header_version = 2; + else { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); - j = 0; - p->lowest_bit = 0; - p->highest_bit = 0; - for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,p->swap_lockmap)) { - if (!p->lowest_bit) - p->lowest_bit = i; - p->highest_bit = i; - p->max = i+1; - j++; + + switch (swap_header_version) { + case 1: + memset(((char *) swap_header)+PAGE_SIZE-10,0,10); + j = 0; + p->lowest_bit = 0; + p->highest_bit = 0; + for (i = 1 ; i < 8*PAGE_SIZE ; i++) { + if (test_bit(i,(char *) swap_header)) { + if (!p->lowest_bit) + p->lowest_bit = i; + p->highest_bit = i; + p->max = i+1; + j++; + } + } + nr_good_pages = j; + p->swap_map = vmalloc(p->max * sizeof(short)); + if (!p->swap_map) { + error = -ENOMEM; + goto bad_swap; + } + for (i = 1 ; i < p->max ; i++) { + if (test_bit(i,(char *) swap_header)) + p->swap_map[i] = 0; + else + p->swap_map[i] = SWAP_MAP_BAD; + } + break; + + case 2: + /* Check the swap header's sub-version and the size of + the swap file and bad block lists */ + if (swap_header->info.version != 1) { + printk(KERN_WARNING + "Unable to handle swap header version %d\n", + swap_header->info.version); + error = -EINVAL; + goto bad_swap; + } + + p->lowest_bit = 1; + p->highest_bit = swap_header->info.last_page - 1; + p->max = swap_header->info.last_page; + + if (p->max >= 0x7fffffffL/PAGE_SIZE || + (void *) &swap_header->info.badpages[swap_header->info.nr_badpages-1] >= (void *) swap_header->magic.magic) { + error = -EINVAL; + goto bad_swap; } + + /* OK, set up the swap map and apply the bad block list */ + if (!(p->swap_map = vmalloc (p->max * sizeof(short)))) { + error = -ENOMEM; + goto bad_swap; + } + + error = 0; + memset(p->swap_map, 0, p->max * sizeof(short)); + for (i=0; i<swap_header->info.nr_badpages; i++) { + int page = swap_header->info.badpages[i]; + if (page <= 0 || page >= swap_header->info.last_page) + error = -EINVAL; + else + p->swap_map[page] = SWAP_MAP_BAD; + } + nr_good_pages = swap_header->info.last_page - i; + lock_map_size = (p->max + 7) / 8; + if (error) + goto bad_swap; } - if (!j) { - printk("Empty swap-file\n"); + + if (!nr_good_pages) { + printk(KERN_WARNING "Empty swap-file\n"); error = -EINVAL; goto bad_swap; } - p->swap_map = (unsigned char *) vmalloc(p->max); - if (!p->swap_map) { + p->swap_map[0] = SWAP_MAP_BAD; + if (!(p->swap_lockmap = vmalloc (lock_map_size))) { error = -ENOMEM; goto bad_swap; } - for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,p->swap_lockmap)) - p->swap_map[i] = 0; - else - p->swap_map[i] = 0x80; - } - p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); + memset(p->swap_lockmap,0,lock_map_size); p->flags = SWP_WRITEOK; - p->pages = j; - nr_swap_pages += j; + p->pages = nr_good_pages; + nr_swap_pages += nr_good_pages; printk(KERN_INFO "Adding Swap: %dk swap-space (priority %d)\n", - j<<(PAGE_SHIFT-10), p->prio); + nr_good_pages<<(PAGE_SHIFT-10), p->prio); /* insert swap space into swap_list: */ prev = -1; @@ -616,8 +690,10 @@ bad_swap: if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); - vfree(p->swap_map); + if (p->swap_lockmap) + vfree(p->swap_lockmap); + if (p->swap_map) + vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; @@ -625,6 +701,8 @@ bad_swap_2: p->swap_lockmap = NULL; p->flags = 0; out: + if (swap_header) + free_page((long) swap_header); unlock_kernel(); return error; } @@ -639,7 +717,7 @@ void si_swapinfo(struct sysinfo *val) continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) { - case 128: + case SWAP_MAP_BAD: continue; case 0: ++val->freeswap; @@ -651,4 +729,3 @@ void si_swapinfo(struct sysinfo *val) val->totalswap <<= PAGE_SHIFT; return; } - diff --git a/mm/vmscan.c b/mm/vmscan.c index b586bce72..884e67150 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -12,7 +12,6 @@ #include <linux/mm.h> #include <linux/sched.h> -#include <linux/head.h> #include <linux/kernel.h> #include <linux/kernel_stat.h> #include <linux/errno.h> @@ -24,6 +23,7 @@ #include <linux/dcache.h> #include <linux/fs.h> #include <linux/pagemap.h> +#include <linux/init.h> #include <asm/bitops.h> #include <asm/pgtable.h> @@ -491,7 +491,7 @@ static int do_try_to_free_page(int gfp_mask) * may be printed in the middle of another driver's init * message). It looks very bad when that happens. */ -void kswapd_setup(void) +void __init kswapd_setup(void) { int i; char *revision="$Revision: 1.5 $", *s, *e; @@ -529,6 +529,20 @@ int kswapd(void *unused) namings for POSIX.4 realtime scheduling priorities. */ + /* + * Tell the memory management that we're a "memory allocator", + * and that if we need more memory we should get access to it + * regardless (see "try_to_free_pages()"). "kswapd" should + * never get caught in the normal page freeing logic. + * + * (Kswapd normally doesn't need memory anyway, but sometimes + * you need a small amount of memory in order to be able to + * page out something else, and this flag essentially protects + * us from recursively trying to free more memory as we're + * trying to free the first piece of memory in the first place). + */ + current->flags |= PF_MEMALLOC; + init_swap_timer(); add_wait_queue(&kswapd_wait, &wait); while (1) { @@ -592,7 +606,7 @@ int try_to_free_pages(unsigned int gfp_mask, int count) int retval = 1; lock_kernel(); - if (current->flags & PF_MEMALLOC) { + if (!(current->flags & PF_MEMALLOC)) { current->flags |= PF_MEMALLOC; do { retval = do_try_to_free_page(gfp_mask); @@ -600,7 +614,7 @@ int try_to_free_pages(unsigned int gfp_mask, int count) break; count--; } while (count > 0); - current->flags &= PF_MEMALLOC; + current->flags &= ~PF_MEMALLOC; } unlock_kernel(); return retval; |