patch-2.1.110 linux/mm/filemap.c
Next file: linux/mm/page_alloc.c
Previous file: linux/kernel/sched.c
Back to the patch index
Back to the overall index
- Lines: 191
- Date:
Fri Jul 17 11:41:46 1998
- Orig file:
v2.1.109/linux/mm/filemap.c
- Orig date:
Thu Jul 16 18:09:30 1998
diff -u --recursive --new-file v2.1.109/linux/mm/filemap.c linux/mm/filemap.c
@@ -117,12 +117,98 @@
}
}
+/*
+ * Remove a page from the page cache and free it.
+ */
+void remove_inode_page(struct page *page)
+{
+ remove_page_from_hash_queue(page);
+ remove_page_from_inode_queue(page);
+ __free_page(page);
+}
+
+/*
+ * Check whether we can free this page.
+ */
+static inline int shrink_one_page(struct page *page, int gfp_mask)
+{
+ struct buffer_head *tmp, *bh;
+
+ if (PageLocked(page))
+ goto next;
+ if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
+ goto next;
+ /* First of all, regenerate the page's referenced bit
+ * from any buffers in the page
+ */
+ bh = page->buffers;
+ if (bh) {
+ tmp = bh;
+ do {
+ if (buffer_touched(tmp)) {
+ clear_bit(BH_Touched, &tmp->b_state);
+ set_bit(PG_referenced, &page->flags);
+ }
+ tmp = tmp->b_this_page;
+ } while (tmp != bh);
+
+ /* Refuse to swap out all buffer pages */
+ if ((buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.min_percent * num_physpages))
+ goto next;
+ }
+
+ /* We can't throw away shared pages, but we do mark
+ them as referenced. This relies on the fact that
+ no page is currently in both the page cache and the
+ buffer cache; we'd have to modify the following
+ test to allow for that case. */
+
+ switch (atomic_read(&page->count)) {
+ case 1:
+ /* is it a swap-cache or page-cache page? */
+ if (page->inode) {
+ if (test_and_clear_bit(PG_referenced, &page->flags)) {
+ touch_page(page);
+ break;
+ }
+ age_page(page);
+ if (page->age)
+ break;
+ if (page_cache_size * 100 < (page_cache.min_percent * num_physpages))
+ break;
+ if (PageSwapCache(page)) {
+ delete_from_swap_cache(page);
+ return 1;
+ }
+ remove_inode_page(page);
+ return 1;
+ }
+ /* It's not a cache page, so we don't do aging.
+ * If it has been referenced recently, don't free it */
+ if (test_and_clear_bit(PG_referenced, &page->flags))
+ break;
+
+ /* is it a buffer cache page? */
+ if ((gfp_mask & __GFP_IO) && bh && try_to_free_buffer(bh, &bh, 6))
+ return 1;
+ break;
+
+ default:
+ /* more than one user: we can't throw it away */
+ set_bit(PG_referenced, &page->flags);
+ /* fall through */
+ case 0:
+ /* nothing */
+ }
+next:
+ return 0;
+}
+
int shrink_mmap(int priority, int gfp_mask)
{
static unsigned long clock = 0;
- struct page * page;
unsigned long limit = num_physpages;
- struct buffer_head *tmp, *bh;
+ struct page * page;
int count_max, count_min;
count_max = (limit<<2) >> (priority>>1);
@@ -130,76 +216,11 @@
page = mem_map + clock;
do {
+ if (shrink_one_page(page, gfp_mask))
+ return 1;
count_max--;
if (page->inode || page->buffers)
count_min--;
-
- if (PageLocked(page))
- goto next;
- if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
- goto next;
- /* First of all, regenerate the page's referenced bit
- from any buffers in the page */
- bh = page->buffers;
- if (bh) {
- tmp = bh;
- do {
- if (buffer_touched(tmp)) {
- clear_bit(BH_Touched, &tmp->b_state);
- set_bit(PG_referenced, &page->flags);
- }
- tmp = tmp->b_this_page;
- } while (tmp != bh);
-
- /* Refuse to swap out all buffer pages */
- if ((buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.min_percent * num_physpages))
- goto next;
- }
-
- /* We can't throw away shared pages, but we do mark
- them as referenced. This relies on the fact that
- no page is currently in both the page cache and the
- buffer cache; we'd have to modify the following
- test to allow for that case. */
-
- switch (atomic_read(&page->count)) {
- case 1:
- /* is it a swap-cache or page-cache page? */
- if (page->inode) {
- if (test_and_clear_bit(PG_referenced, &page->flags)) {
- touch_page(page);
- break;
- }
- age_page(page);
- if (page->age || page_cache_size * 100 < (page_cache.min_percent * num_physpages))
- break;
- if (PageSwapCache(page)) {
- delete_from_swap_cache(page);
- return 1;
- }
- remove_page_from_hash_queue(page);
- remove_page_from_inode_queue(page);
- __free_page(page);
- return 1;
- }
- /* It's not a cache page, so we don't do aging.
- * If it has been referenced recently, don't free it */
- if (test_and_clear_bit(PG_referenced, &page->flags))
- break;
-
- /* is it a buffer cache page? */
- if ((gfp_mask & __GFP_IO) && bh && try_to_free_buffer(bh, &bh, 6))
- return 1;
- break;
-
- default:
- /* more than one users: we can't throw it away */
- set_bit(PG_referenced, &page->flags);
- /* fall through */
- case 0:
- /* nothing */
- }
-next:
page++;
clock++;
if (clock >= limit) {
@@ -226,9 +247,7 @@
return count;
if (PageSwapCache(page))
panic ("Doing a normal page_unuse of a swap cache page");
- remove_page_from_hash_queue(page);
- remove_page_from_inode_queue(page);
- __free_page(page);
+ remove_inode_page(page);
return 1;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov