diff options
Diffstat (limited to 'mm/swap_state.c')
-rw-r--r-- | mm/swap_state.c | 106 |
1 files changed, 71 insertions, 35 deletions
diff --git a/mm/swap_state.c b/mm/swap_state.c index 8c5e7176c..21723c1db 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -25,7 +25,31 @@ * ensure that any mistaken dereferences of this structure cause a * kernel oops. */ -struct inode swapper_inode; + +static struct inode_operations swapper_inode_operations = { + NULL, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* readpage */ + NULL, /* writepage */ + block_flushpage, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +struct inode swapper_inode = { i_op: &swapper_inode_operations }; #ifdef SWAP_CACHE_INFO unsigned long swap_cache_add_total = 0; @@ -49,20 +73,20 @@ int add_to_swap_cache(struct page *page, unsigned long entry) #endif #ifdef DEBUG_SWAP printk("DebugVM: add_to_swap_cache(%08lx count %d, entry %08lx)\n", - page_address(page), atomic_read(&page->count), entry); + page_address(page), page_count(page), entry); #endif if (PageTestandSetSwapCache(page)) { printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx " - "on page %08lx\n", - page->offset, page_address(page)); + "on page %08lx\n", + page->offset, page_address(page)); return 0; } if (page->inode) { printk(KERN_ERR "swap_cache: replacing page-cached entry " - "on page %08lx\n", page_address(page)); + "on page %08lx\n", page_address(page)); return 0; } - atomic_inc(&page->count); + get_page(page); page->inode = &swapper_inode; page->offset = entry; add_page_to_hash_queue(page, &swapper_inode, entry); @@ -111,7 +135,7 @@ int swap_duplicate(unsigned long entry) result = 1; #ifdef DEBUG_SWAP printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n", - entry, p->swap_map[offset]); + entry, p->swap_map[offset]); #endif out: return result; @@ -127,7 +151,7 @@ bad_offset: bad_unused: printk(KERN_ERR "swap_duplicate at %8p: entry %08lx, unused page\n", - __builtin_return_address(0), entry); + __builtin_return_address(0), entry); goto out; } @@ -153,7 +177,7 @@ int swap_count(unsigned long entry) retval = p->swap_map[offset]; #ifdef DEBUG_SWAP printk("DebugVM: swap_count(entry %08lx, count %d)\n", - entry, retval); + entry, retval); #endif out: return retval; @@ -163,16 +187,16 @@ bad_entry: goto out; bad_file: printk(KERN_ERR - "swap_count: entry %08lx, nonexistent swap file!\n", entry); + "swap_count: entry %08lx, nonexistent swap file!\n", entry); goto out; bad_offset: printk(KERN_ERR - "swap_count: entry %08lx, offset exceeds max!\n", entry); + "swap_count: entry %08lx, offset exceeds max!\n", entry); goto out; bad_unused: printk(KERN_ERR - "swap_count at %8p: entry %08lx, unused page!\n", - __builtin_return_address(0), entry); + "swap_count at %8p: entry %08lx, unused page!\n", + __builtin_return_address(0), entry); goto out; } @@ -190,18 +214,17 @@ static inline void remove_from_swap_cache(struct page *page) #ifdef DEBUG_SWAP printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n", - page_address(page), atomic_read(&page->count)); + page_address(page), page_count(page)); #endif - PageClearSwapCache (page); + PageClearSwapCache(page); remove_inode_page(page); } - /* * This must be called only on pages that have * been verified to be in the swap cache. */ -void delete_from_swap_cache(struct page *page) +void __delete_from_swap_cache(struct page *page) { long entry = page->offset; @@ -210,13 +233,27 @@ void delete_from_swap_cache(struct page *page) #endif #ifdef DEBUG_SWAP printk("DebugVM: delete_from_swap_cache(%08lx count %d, " - "entry %08lx)\n", - page_address(page), atomic_read(&page->count), entry); + "entry %08lx)\n", + page_address(page), page_count(page), entry); #endif remove_from_swap_cache (page); swap_free (entry); } +/* + * This must be called only on pages that have + * been verified to be in the swap cache. + */ +void delete_from_swap_cache(struct page *page) +{ + lock_page(page); + + __delete_from_swap_cache(page); + + UnlockPage(page); + page_cache_release(page); +} + /* * Perform a free_page(), also freeing any swap cache associated with * this page if it is the last user of the page. @@ -229,18 +266,18 @@ void free_page_and_swap_cache(unsigned long addr) /* * If we are the only user, then free up the swap cache. */ - if (PageSwapCache(page) && !is_page_shared(page)) { + if (PageSwapCache(page) && !is_page_shared(page)) delete_from_swap_cache(page); - } __free_page(page); } /* - * Lookup a swap entry in the swap cache. We need to be careful about - * locked pages. A found page will be returned with its refcount - * incremented. + * Lookup a swap entry in the swap cache. A found page will be returned + * unlocked and with its refcount incremented - we rely on the kernel + * lock getting page table operations atomic even if we drop the page + * lock before returning. */ struct page * lookup_swap_cache(unsigned long entry) @@ -251,23 +288,21 @@ struct page * lookup_swap_cache(unsigned long entry) swap_cache_find_total++; #endif while (1) { - found = find_page(&swapper_inode, entry); + found = find_lock_page(&swapper_inode, entry); if (!found) return 0; if (found->inode != &swapper_inode || !PageSwapCache(found)) goto out_bad; - if (!PageLocked(found)) { #ifdef SWAP_CACHE_INFO - swap_cache_find_success++; + swap_cache_find_success++; #endif - return found; - } - __free_page(found); - __wait_on_page(found); + UnlockPage(found); + return found; } out_bad: printk (KERN_ERR "VM: Found a non-swapper swap page!\n"); + UnlockPage(found); __free_page(found); return 0; } @@ -288,7 +323,7 @@ struct page * read_swap_cache_async(unsigned long entry, int wait) #ifdef DEBUG_SWAP printk("DebugVM: read_swap_cache_async entry %08lx%s\n", - entry, wait ? ", wait" : ""); + entry, wait ? ", wait" : ""); #endif /* * Make sure the swap entry is still in use. @@ -319,12 +354,12 @@ struct page * read_swap_cache_async(unsigned long entry, int wait) if (!add_to_swap_cache(new_page, entry)) goto out_free_page; - set_bit(PG_locked, &new_page->flags); + LockPage(new_page); rw_swap_page(READ, entry, (char *) new_page_addr, wait); #ifdef DEBUG_SWAP printk("DebugVM: read_swap_cache_async created " - "entry %08lx at %p\n", - entry, (char *) page_address(new_page)); + "entry %08lx at %p\n", + entry, (char *) page_address(new_page)); #endif return new_page; @@ -335,3 +370,4 @@ out_free_swap: out: return found_page; } + |