free_page_and_swap_cache sleeps (so sleep also zap_page_range)

Andrea Arcangeli (andrea@suse.de)
Tue, 29 Jun 1999 18:14:35 +0200 (CEST)


When vmtruncate calls zap_page_range() then zap_page_range() can call
free_page_and_swap_cache (that can sleep in pre5). But I think vmtruncate
couldn't sleep (since it owns only the i_sem and the big kernel lock).

The trivial fix is to not release the pagecache from zap_page_range (and
left this task only to shrink_mmap). I am not convinced if that's what we
want though...

(anyway a completly untested patch against pre-2.3.9-5 follows)

Index: linux//include/linux/swap.h
===================================================================
RCS file: /var/cvs/linux/include/linux/swap.h,v
retrieving revision 1.1.1.9
diff -u -r1.1.1.9 swap.h
--- linux//include/linux/swap.h 1999/06/22 22:36:11 1.1.1.9
+++ linux//include/linux/swap.h 1999/06/29 16:04:50
@@ -108,7 +108,6 @@
*/
extern void __delete_from_swap_cache(struct page *page);
extern void delete_from_swap_cache(struct page *page);
-extern void free_page_and_swap_cache(unsigned long addr);

/* linux/mm/swapfile.c */
extern unsigned int nr_swapfiles;
Index: linux//mm/memory.c
===================================================================
RCS file: /var/cvs/linux/mm/memory.c,v
retrieving revision 1.1.1.10
diff -u -r1.1.1.10 memory.c
--- linux//mm/memory.c 1999/06/28 15:10:09 1.1.1.10
+++ linux//mm/memory.c 1999/06/29 16:03:59
@@ -305,7 +305,7 @@
* free_page() used to be able to clear swap cache
* entries. We may now have to do it manually.
*/
- free_page_and_swap_cache(addr);
+ free_page(addr);
return 1;
}
swap_free(pte_val(page));
Index: linux//mm/page_alloc.c
===================================================================
RCS file: /var/cvs/linux/mm/page_alloc.c,v
retrieving revision 1.1.1.14
diff -u -r1.1.1.14 page_alloc.c
--- linux//mm/page_alloc.c 1999/06/22 22:36:36 1.1.1.14
+++ linux//mm/page_alloc.c 1999/06/29 16:04:14
@@ -403,7 +403,7 @@
}
if (pte_val(*page_table) != entry) {
if (page_map)
- free_page_and_swap_cache(page_address(page_map));
+ __free_page(page_map);
return;
}
if (!page_map) {
Index: linux//mm/swap_state.c
===================================================================
RCS file: /var/cvs/linux/mm/swap_state.c,v
retrieving revision 1.1.1.8
diff -u -r1.1.1.8 swap_state.c
--- linux//mm/swap_state.c 1999/06/28 15:10:10 1.1.1.8
+++ linux//mm/swap_state.c 1999/06/29 16:05:05
@@ -253,31 +253,6 @@
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.
- */
-
-void free_page_and_swap_cache(unsigned long addr)
-{
- struct page *page = mem_map + MAP_NR(addr);
-
- /*
- * If we are the only user, then free up the swap cache.
- */
- lock_page(page);
- if (PageSwapCache(page) && !is_page_shared(page)) {
- long entry = page->offset;
- remove_from_swap_cache(page);
- swap_free(entry);
- page_cache_release(page);
- }
- UnlockPage(page);
-
- __free_page(page);
-}
-
-
/*
* 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

Andrea

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/