radix-tree pagecache for 2.5
Subsystems (11)
PATCH 1/1 radix-tree pagecache for 2.5
I think I have a first release candidate of the radix-tree pagecache for the 2.5 tree. This patch contains the following changes over the last version
- improved OOM handling all over the place (Andrew Morton)
- minor fixes/cleanuos (Andrew Morton, me)
- switch mapping->page_lock to a r/w lock (me)
The patch can be found at:
ftp://ftp.kernel.org/pub/linux/kernel/people/hch/patches/v2.5/2.5.8-pre2/linux-2.5.8-ratcache.patch.gz ftp://ftp.kernel.org/pub/linux/kernel/people/hch/patches/v2.5/2.5.8-pre2/linux-2.5.8-ratcache.patch.bz2
In addition a BitKeeper tree is available at http://hkernel.bkbits.net.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
Quoted 3 lines · Christoph Hellwig
I think I have a first release candidate of the radix-tree pagecache for the 2.5 tree.
Hi, Christoph.
There are a few places where I believe a write_lock is needed rather than a read_lock. Places where we hold the lock seemingly for read, then later on go and modify the tree, or the mapping's inode lists.
I'll rediff against -pre3, test with the following incremental patch on the quad and if it survives, pass on to Linus.
I'll add a FIXME at the mempool allocation site too. 512 ratnodes is maybe 300k. We need to justify pinning that amount of memory... And work out a means of scaling the pool according to the number of pages in the system...
mm/vmscan.c renamed from mm/vmscan.c~dallocbase-07-new_ratcache_fixes +5 -5
@@ -483,10 +483,10 @@ static int shrink_cache(int nr_pages, zo* This is the non-racy check for busy page. */ if (mapping) { -read_lock (&mapping->page_lock); +write_lock (&mapping->page_lock);if (is_page_cache_freeable (page)) goto page_freeable; -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock); }UnlockPage (page); page_mapped:
@@ -507,7 +507,7 @@ page_freeable:* the page is freeable* so not in use by anybody. */ if (PageDirty (page)) { -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);UnlockPage (page);continue ; }
@@ -515,12 +515,12 @@ page_freeable:/* point of no return */ if (likely (!PageSwapCache (page))) {__remove_inode_page (page); -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock); }else {swp_entry_t swap; swap.val = page->index;__delete_from_swap_cache (page); -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);swap_free (swap); }
mm/filemap.c renamed from mm/filemap.c~dallocbase-07-new_ratcache_fixes +11 -11
@@ -59,7 +59,7 @@ spinlock_t pagemap_lru_lock __cacheline_/* * Remove a page from the page cache and free it. Caller has to make * sure the page is locked and that nobody else uses it - or that usage -* is safe. +* is safe. The caller must hold a write_lock on the mapping's page_lock. */ void __remove_inode_page (struct page *page) {
@@ -574,6 +574,7 @@ int filemap_fdatawait(struct address_spa/* * This adds a page to the page cache, starting out as locked, * owned by us, but unreferenced, not uptodate and with no errors. +* The caller must hold a write_lock on the mapping->page_lock. */ static int __add_to_page_cache (struct page *page,struct address_space *mapping,unsigned long offset)
@@ -874,19 +875,19 @@ struct page * find_or_create_page(structif (!page) {struct page *newpage =alloc_page (gfp_mask);if (newpage) { -read_lock (&mapping->page_lock); +write_lock (&mapping->page_lock); page =__find_lock_page (mapping, index);if (likely (!page)) { page = newpage;if (__add_to_page_cache (page, mapping, index)) { -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);page_cache_release (page); page =NULL ; goto out; } newpage =NULL ; } -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);if (newpage ==NULL )lru_cache_add (page);else
@@ -1280,13 +1281,13 @@ void do_generic_file_read(struct file ** Try to find the data in the page cache.. */ -read_lock (&mapping->page_lock); +write_lock (&mapping->page_lock); page =radix_tree_lookup (&mapping->page_tree, index);if (!page) goto no_cached_page; found_page:page_cache_get (page); -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);if (!Page_Uptodate (page)) goto page_not_up_to_date;
@@ -1380,7 +1381,7 @@ no_cached_page:* We get here with the page cache lock held. */ if (!cached_page) { -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock); cached_page =page_cache_alloc (mapping);if (!cached_page) { desc->error = -ENOMEM ;
@@ -1391,7 +1392,7 @@ no_cached_page:* Somebody may have added the page while we * dropped the page cache lock. Check for that. */ -read_lock (&mapping->page_lock); +write_lock (&mapping->page_lock); page =radix_tree_lookup (&mapping->page_tree, index);if (page) goto found_page;
@@ -1401,12 +1402,12 @@ no_cached_page:* Ok, add the new page to the hash-queues... */ if (__add_to_page_cache (cached_page, mapping, index) <0 ) { -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock); desc->error = -ENOMEM ;break ; } page = cached_page; -read_unlock (&mapping->page_lock); +write_unlock (&mapping->page_lock);lru_cache_add (page); cached_page =NULL ; --
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
PATCH 1/1 Velikov/Hellwig radix-tree pagecache
It was tested for a couple of hours under heavy load, 4 CPU.
It works fine. Here's the rolled-up diff against -pre3.
Before the mempool was added, the VM was getting many, many 0-order allocation failures due to the atomic ratnode allocations inside swap_out. That monster mempool is doing its job - drove a 256meg machine a gigabyte into swap with no ratnode allocation failures at all.
So we do need to trim that pool a bit, and also handle the case where swap_out fails, and not just keep pointlessly calling it.
drivers/block/rd.c renamed from drivers/block/rd.c~dallocbase-05-new_ratcache +1 -3
@@ -156,7 +156,6 @@ static int rd_blkdev_pagecache_IO(int rw do { int count; - struct page ** hash; struct page * page; char * src, * dst; int unlock = 0;
@@ -166,8 +165,7 @@ static int rd_blkdev_pagecache_IO(int rw count = size; size -= count; - hash =page_hash (mapping, index); - page =__find_get_page (mapping, index, hash); + page =find_get_page (mapping, index);if (!page) { page =grab_cache_page (mapping, index); err = -ENOMEM ;
fs/inode.c renamed from fs/inode.c~dallocbase-05-new_ratcache +2 -0
@@ -143,6 +143,8 @@ void inode_init_once(struct inode *inodeINIT_LIST_HEAD (&inode->i_dirty_data_buffers);INIT_LIST_HEAD (&inode->i_devices);sema_init (&inode->i_sem,1 ); +INIT_RADIX_TREE (&inode->i_data.page_tree,GFP_ATOMIC ); +rwlock_init (&inode->i_data.page_lock);spin_lock_init (&inode->i_data.i_shared_lock);INIT_LIST_HEAD (&inode->i_data.i_mmap);INIT_LIST_HEAD (&inode->i_data.i_mmap_shared);
include/linux/fs.h renamed from include/linux/fs.h~dallocbase-05-new_ratcache +3 -0
@@ -21,6 +21,7 @@#include <linux/cache.h> #include <linux/stddef.h> #include <linux/string.h> +#include <linux/radix-tree.h> #include <asm/atomic.h> #include <asm/bitops.h>
@@ -370,6 +371,8 @@ struct address_space_operations { };struct address_space { +struct radix_tree_root page_tree;/* radix tree of all pages */ +rwlock_t page_lock;/* and rwlock protecting it */ struct list_head clean_pages;/* list of clean pages */ struct list_head dirty_pages;/* list of dirty pages */ struct list_head locked_pages;/* list of locked pages */
include/linux/mm.h renamed from include/linux/mm.h~dallocbase-05-new_ratcache +2 -6
@@ -149,14 +149,11 @@ typedef struct page {struct list_head list;/* ->mapping has some page lists. */ struct address_space *mapping;/* The inode (or ...) we belong to. */ unsigned long index;/* Our offset within mapping. */ -struct page *next_hash;/* Next page sharing our hash bucket in -the pagecache hash table. */ atomic_t count;/* Usage count, see below. */ unsigned long flags;/* atomic flags, some possibly updated asynchronously */ struct list_head lru;/* Pageout list, eg. active_list; protected by pagemap_lru_lock !! */ -struct page **pprev_hash;/* Complement to *next_hash. */ struct buffer_head * buffers;/* Buffer maps us to a disk block. */ /*
@@ -236,9 +233,8 @@ typedef struct page {* using the page->list list_head. These fields are also used for * freelist managemet (when page->count==0). * -* There is also a hash table mapping (mapping,index) to the page -* in memory if present. The lists for this hash table use the fields -* page->next_hash and page->pprev_hash. +* There is also a per-mapping radix tree mapping index to the page +* in memory if present. The tree is rooted at mapping->root. * * All process pages can do I/O: * - inode pages may need to be read from disk,
include/linux/pagemap.h renamed from include/linux/pagemap.h~dallocbase-05-new_ratcache +27 -44
89 lines not on this page · raw message
include/linux/radix-tree.h new file +49 -0
49 lines not on this page · raw message
include/linux/swap.h renamed from include/linux/swap.h~dallocbase-05-new_ratcache +4 -1
@@ -109,7 +109,7 @@ extern void __remove_inode_page(struct pstruct task_struct ;struct vm_area_struct ;struct sysinfo ; - +struct address_space ;struct zone_t ;/* linux/mm/swap.c */
@@ -139,6 +139,9 @@ extern void show_swap_cache_info(void);extern int add_to_swap_cache (struct page *,swp_entry_t );extern void __delete_from_swap_cache (struct page *page);extern void delete_from_swap_cache (struct page *page); +extern int move_to_swap_cache (struct page *page,swp_entry_t entry); +extern int move_from_swap_cache (struct page *page,unsigned long index, +struct address_space *mapping);extern void free_page_and_swap_cache (struct page *page);extern struct page *lookup_swap_cache (swp_entry_t );extern struct page *read_swap_cache_async (swp_entry_t );
init/main.c renamed from init/main.c~dallocbase-05-new_ratcache +2 -1
@@ -69,6 +69,7 @@ extern void sbus_init(void);extern void sysctl_init (void );extern void signals_init (void ); +extern void radix_tree_init (void );extern void free_initmem (void );#ifdef CONFIG_TC
@@ -392,7 +393,7 @@ asmlinkage void __init start_kernel(voidproc_caches_init ();vfs_caches_init (mempages);buffer_init (mempages); -page_cache_init (mempages); +radix_tree_init ();#if defined(CONFIG_ARCH_S390 )ccwcache_init ();#endif
kernel/ksyms.c renamed from kernel/ksyms.c~dallocbase-05-new_ratcache +2 -4
@@ -224,8 +224,6 @@ EXPORT_SYMBOL(generic_file_write);EXPORT_SYMBOL (generic_file_mmap);EXPORT_SYMBOL (generic_ro_fops);EXPORT_SYMBOL (generic_buffer_fdatasync); -EXPORT_SYMBOL (page_hash_bits); -EXPORT_SYMBOL (page_hash_table);EXPORT_SYMBOL (file_lock_list);EXPORT_SYMBOL (locks_init_lock);EXPORT_SYMBOL (locks_copy_lock);
@@ -266,8 +264,8 @@ EXPORT_SYMBOL(no_llseek);EXPORT_SYMBOL (__pollwait);EXPORT_SYMBOL (poll_freewait);EXPORT_SYMBOL (ROOT_DEV ); -EXPORT_SYMBOL (__find_get_page); -EXPORT_SYMBOL (__find_lock_page); +EXPORT_SYMBOL (find_get_page); +EXPORT_SYMBOL (find_lock_page);EXPORT_SYMBOL (grab_cache_page);EXPORT_SYMBOL (grab_cache_page_nowait);EXPORT_SYMBOL (read_cache_page);
lib/Makefile renamed from lib/Makefile~dallocbase-05-new_ratcache +4 -2
@@ -8,9 +8,11 @@ L_TARGET := lib.a -export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o rbtree.o +export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \ + crc32.o rbtree.o radix-tree.o -obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o +obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \ + bust_spinlocks.o rbtree.o radix-tree.o obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
lib/radix-tree.c new file +296 -0
296 lines not on this page · raw message
mm/filemap.c renamed from mm/filemap.c~dallocbase-05-new_ratcache +197 -271
878 lines not on this page · raw message
mm/mincore.c renamed from mm/mincore.c~dallocbase-05-new_ratcache +2 -2
@@ -27,9 +27,9 @@ static unsigned char mincore_page(struct {unsigned char present =0 ;struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping; -struct page * page, ** hash =page_hash (as, pgoff); +struct page * page; - page =__find_get_page (as, pgoff, hash); + page =find_get_page (as, pgoff);if (page) { present =Page_Uptodate (page);page_cache_release (page);
mm/shmem.c renamed from mm/shmem.c~dallocbase-05-new_ratcache +39 -39
146 lines not on this page · raw message
mm/swapfile.c renamed from mm/swapfile.c~dallocbase-05-new_ratcache +4 -4
@@ -239,10 +239,10 @@ static int exclusive_swap_page(struct pa/* Is the only swap cache user the cache itself? */ if (p->swap_map[SWP_OFFSET (entry)] ==1 ) {/* Recheck the page count with the pagecache lock held.. */ -spin_lock (&pagecache_lock); +read_lock (&swapper_space.page_lock);if (page_count (page) - !!page->buffers ==2 ) retval =1 ; -spin_unlock (&pagecache_lock); +read_unlock (&swapper_space.page_lock); }swap_info_put (p); }
@@ -307,13 +307,13 @@ int remove_exclusive_swap_page(struct pa retval =0 ;if (p->swap_map[SWP_OFFSET (entry)] ==1 ) {/* Recheck the page count with the pagecache lock held.. */ -spin_lock (&pagecache_lock); +read_lock (&swapper_space.page_lock);if (page_count (page) - !!page->buffers ==2 ) {__delete_from_swap_cache (page);SetPageDirty (page); retval =1 ; } -spin_unlock (&pagecache_lock); +read_unlock (&swapper_space.page_lock); }swap_info_put (p);
mm/swap_state.c renamed from mm/swap_state.c~dallocbase-05-new_ratcache +101 -12
156 lines not on this page · raw message
mm/vmscan.c renamed from mm/vmscan.c~dallocbase-05-new_ratcache +34 -23
116 lines not on this page · raw message
-
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/