patch-2.3.30 linux/mm/swap_state.c
Next file: linux/mm/swapfile.c
Previous file: linux/mm/swap.c
Back to the patch index
Back to the overall index
- Lines: 194
- Date:
Mon Dec 6 10:19:45 1999
- Orig file:
v2.3.29/linux/mm/swap_state.c
- Orig date:
Sun Nov 7 16:37:34 1999
diff -u --recursive --new-file v2.3.29/linux/mm/swap_state.c linux/mm/swap_state.c
@@ -52,100 +52,13 @@
add_to_page_cache(page, &swapper_space, entry.val);
}
-/*
- * 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.
- */
-int swap_duplicate(swp_entry_t entry)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
- int result = 0;
-
- /* Swap entry 0 is illegal */
- if (!entry.val)
- goto out;
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_file;
- p = type + swap_info;
- offset = SWP_OFFSET(entry);
- if (offset >= p->max)
- goto bad_offset;
- if (!p->swap_map[offset])
- goto bad_unused;
- /*
- * 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("VM: swap entry overflow\n");
- p->swap_map[offset] = SWAP_MAP_MAX;
- }
- result = 1;
-out:
- return result;
-
-bad_file:
- printk("Bad swap file entry %08lx\n", entry.val);
- goto out;
-bad_offset:
- printk("Bad swap offset entry %08lx\n", entry.val);
- goto out;
-bad_unused:
- printk("Unused swap offset entry %08lx\n", entry.val);
- goto out;
-}
-
-int swap_count(struct page *page)
-{
- struct swap_info_struct * p;
- unsigned long offset, type;
- swp_entry_t entry;
- int retval = 0;
-
- entry.val = page->index;
- if (!entry.val)
- goto bad_entry;
- type = SWP_TYPE(entry);
- if (type >= nr_swapfiles)
- goto bad_file;
- p = type + swap_info;
- offset = SWP_OFFSET(entry);
- if (offset >= p->max)
- goto bad_offset;
- if (!p->swap_map[offset])
- goto bad_unused;
- retval = p->swap_map[offset];
-out:
- return retval;
-
-bad_entry:
- printk(KERN_ERR "swap_count: null entry!\n");
- goto out;
-bad_file:
- printk("Bad swap file entry %08lx\n", entry.val);
- goto out;
-bad_offset:
- printk("Bad swap offset entry %08lx\n", entry.val);
- goto out;
-bad_unused:
- printk("Unused swap offset entry %08lx\n", entry.val);
- goto out;
-}
-
static inline void remove_from_swap_cache(struct page *page)
{
struct address_space *mapping = page->mapping;
if (mapping != &swapper_space)
BUG();
- if (!PageSwapCache(page))
+ if (!PageSwapCache(page) || !PageLocked(page))
PAGE_BUG(page);
PageClearSwapCache(page);
@@ -166,49 +79,49 @@
swap_cache_del_total++;
#endif
remove_from_swap_cache(page);
- lock_kernel();
swap_free(entry);
- unlock_kernel();
}
-static void delete_from_swap_cache_nolock(struct page *page)
+/*
+ * This will never put the page into the free list, the caller has
+ * a reference on the page.
+ */
+void delete_from_swap_cache_nolock(struct page *page)
{
- if (block_flushpage(NULL, page, 0))
+ if (block_flushpage(page, 0))
lru_cache_del(page);
__delete_from_swap_cache(page);
+ page_cache_release(page);
}
/*
* This must be called only on pages that have
- * been verified to be in the swap cache.
+ * been verified to be in the swap cache and locked.
*/
void delete_from_swap_cache(struct page *page)
{
lock_page(page);
-
delete_from_swap_cache_nolock(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.
+ * this page if it is the last user of the page. Can not do a lock_page,
+ * as we are holding the page_table_lock spinlock.
*/
-
void free_page_and_swap_cache(struct page *page)
{
/*
- * If we are the only user, then free up the swap cache.
+ * If we are the only user, then try to free up the swap cache.
*/
- lock_page(page);
- if (PageSwapCache(page) && !is_page_shared(page)) {
- delete_from_swap_cache_nolock(page);
- page_cache_release(page);
+ if (PageSwapCache(page) && !TryLockPage(page)) {
+ if (!is_page_shared(page)) {
+ delete_from_swap_cache_nolock(page);
+ }
+ UnlockPage(page);
}
- UnlockPage(page);
clear_bit(PG_swap_entry, &page->flags);
@@ -234,10 +147,24 @@
/*
* Right now the pagecache is 32-bit only. But it's a 32 bit index. =)
*/
+repeat:
found = find_lock_page(&swapper_space, entry.val);
if (!found)
return 0;
- if (found->mapping != &swapper_space || !PageSwapCache(found))
+ /*
+ * Though the "found" page was in the swap cache an instant
+ * earlier, it might have been removed by shrink_mmap etc.
+ * Re search ... Since find_lock_page grabs a reference on
+ * the page, it can not be reused for anything else, namely
+ * it can not be associated with another swaphandle, so it
+ * is enough to check whether the page is still in the scache.
+ */
+ if (!PageSwapCache(found)) {
+ UnlockPage(found);
+ __free_page(found);
+ goto repeat;
+ }
+ if (found->mapping != &swapper_space)
goto out_bad;
#ifdef SWAP_CACHE_INFO
swap_cache_find_success++;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)