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/swap_state.c | |
parent | 257730f99381dd26e10b832fce4c94cae7ac1176 (diff) |
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'mm/swap_state.c')
-rw-r--r-- | mm/swap_state.c | 132 |
1 files changed, 77 insertions, 55 deletions
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; +} |