patch-2.3.9 linux/mm/filemap.c

Next file: linux/mm/memory.c
Previous file: linux/lib/string.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.8/linux/mm/filemap.c linux/mm/filemap.c
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/swapctl.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -35,7 +36,8 @@
  */
 
 atomic_t page_cache_size = ATOMIC_INIT(0);
-struct page * page_hash_table[PAGE_HASH_SIZE];
+unsigned int page_hash_bits;
+struct page **page_hash_table;
 
 spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
 
@@ -273,8 +275,8 @@
 			continue;
 		}
 		if (!page_count(page)) {
-//			BUG();
 			spin_unlock(&pagecache_lock);
+			BUG();
 			continue;
 		}
 		get_page(page);
@@ -292,13 +294,18 @@
 
 		/* Is it a buffer page? */
 		if (page->buffers) {
+			int mem = page->inode ? 0 : PAGE_CACHE_SIZE;
 			spin_unlock(&pagecache_lock);
-			if (try_to_free_buffers(page))
-				goto made_progress;
+			if (!try_to_free_buffers(page))
+				goto unlock_continue;
+			atomic_sub(mem, &buffermem);
 			spin_lock(&pagecache_lock);
 		}
 
-		/* We can't free pages unless there's just one user */
+		/*
+		 * We can't free pages unless there's just one user
+		 * (count == 2 because we added one ourselves above).
+		 */
 		if (page_count(page) != 2)
 			goto spin_unlock_continue;
 
@@ -354,6 +361,7 @@
 		if (page->offset == offset)
 			break;
 	}
+	set_bit(PG_referenced, &page->flags);
 not_found:
 	return page;
 }
@@ -1138,7 +1146,6 @@
 {
 	ssize_t retval;
 
-	unlock_kernel();
 	retval = -EFAULT;
 	if (access_ok(VERIFY_WRITE, buf, count)) {
 		retval = 0;
@@ -1156,7 +1163,6 @@
 				retval = desc.error;
 		}
 	}
-	lock_kernel();
 	return retval;
 }
 
@@ -1481,7 +1487,7 @@
 	 * If a task terminates while we're swapping the page, the vma and
 	 * and file could be released ... increment the count to be safe.
 	 */
-	file->f_count++;
+	atomic_inc(&file->f_count);
 	result = do_write_page(inode, file, (const char *) page, offset);
 	fput(file);
 	return result;
@@ -1829,8 +1835,6 @@
 		count = limit - pos;
 	}
 
-	unlock_kernel();
-
 	while (count) {
 		unsigned long bytes, pgpos, offset;
 		/*
@@ -1892,7 +1896,6 @@
 		page_cache_free(page_cache);
 
 	err = written ? written : status;
-	lock_kernel();
 out:
 	return err;
 }
@@ -1913,4 +1916,31 @@
 		panic("put_cached_page: page count=%d\n", 
 			page_count(page));
 	page_cache_release(page);
+}
+
+void __init page_cache_init(unsigned long memory_size)
+{
+	unsigned long htable_size, order;
+
+	htable_size = memory_size >> PAGE_SHIFT;
+	htable_size *= sizeof(struct page *);
+	for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
+		;
+
+	do {
+		unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
+
+		page_hash_bits = 0;
+		while((tmp >>= 1UL) != 0UL)
+			page_hash_bits++;
+
+		page_hash_table = (struct page **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(page_hash_table == NULL && --order > 0);
+
+	printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+	       (1 << page_hash_bits), order, (PAGE_SIZE << order));
+	if (!page_hash_table)
+		panic("Failed to allocate page hash table\n");
+	memset(page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)