--- include/linux/rmap.h | 14 +------------- mm/migrate.c | 4 ++-- mm/rmap.c | 41 ++++++++++++++++++++--------------------- 3 files changed, 23 insertions(+), 36 deletions(-) Index: linux-2.6/include/linux/rmap.h =================================================================== --- linux-2.6.orig/include/linux/rmap.h 2008-03-22 00:12:50.000000000 -0700 +++ linux-2.6/include/linux/rmap.h 2008-03-22 00:12:58.000000000 -0700 @@ -26,7 +26,6 @@ */ struct anon_vma { struct rw_semaphore sem;/* Serialize access to vma list */ - atomic_t refcount; /* vmas on the list */ struct list_head head; /* List of private "related" vmas */ }; @@ -44,18 +43,7 @@ static inline void anon_vma_free(struct kmem_cache_free(anon_vma_cachep, anon_vma); } -struct anon_vma *grab_anon_vma(struct page *page); - -static inline void get_anon_vma(struct anon_vma *anon_vma) -{ - atomic_inc(&anon_vma->refcount); -} - -static inline void put_anon_vma(struct anon_vma *anon_vma) -{ - if (atomic_dec_and_test(&anon_vma->refcount)) - anon_vma_free(anon_vma); -} +struct anon_vma *page_lock_anon_vma(struct page *page); static inline void anon_vma_lock(struct vm_area_struct *vma) { Index: linux-2.6/mm/migrate.c =================================================================== --- linux-2.6.orig/mm/migrate.c 2008-03-22 00:12:50.000000000 -0700 +++ linux-2.6/mm/migrate.c 2008-03-22 00:12:58.000000000 -0700 @@ -655,7 +655,7 @@ static int unmap_and_move(new_page_t get * just care Anon page here. */ if (PageAnon(page)) - anon_vma = grab_anon_vma(page); + anon_vma = page_lock_anon_vma(page); /* * Corner case handling: @@ -695,7 +695,7 @@ static int unmap_and_move(new_page_t get mem_cgroup_end_migration(newpage); rcu_unlock: if (anon_vma) - put_anon_vma(anon_vma); + up_read(&anon_vma->sem); unlock: Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2008-03-22 00:12:50.000000000 -0700 +++ linux-2.6/mm/rmap.c 2008-03-22 00:12:58.000000000 -0700 @@ -80,7 +80,6 @@ int anon_vma_prepare(struct vm_area_stru /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { - get_anon_vma(anon_vma); vma->anon_vma = anon_vma; list_add_tail(&vma->anon_vma_node, &anon_vma->head); allocated = NULL; @@ -99,17 +98,14 @@ void __anon_vma_merge(struct vm_area_str { BUG_ON(vma->anon_vma != next->anon_vma); list_del(&next->anon_vma_node); - put_anon_vma(vma->anon_vma); } void __anon_vma_link(struct vm_area_struct *vma) { struct anon_vma *anon_vma = vma->anon_vma; - if (anon_vma) { - get_anon_vma(anon_vma); + if (anon_vma) list_add_tail(&vma->anon_vma_node, &anon_vma->head); - } } void anon_vma_link(struct vm_area_struct *vma) @@ -117,7 +113,6 @@ void anon_vma_link(struct vm_area_struct struct anon_vma *anon_vma = vma->anon_vma; if (anon_vma) { - get_anon_vma(anon_vma); down_write(&anon_vma->sem); list_add_tail(&vma->anon_vma_node, &anon_vma->head); up_write(&anon_vma->sem); @@ -127,14 +122,19 @@ void anon_vma_link(struct vm_area_struct void anon_vma_unlink(struct vm_area_struct *vma) { struct anon_vma *anon_vma = vma->anon_vma; + int empty; if (!anon_vma) return; down_write(&anon_vma->sem); list_del(&vma->anon_vma_node); + /* We must garbage collect the anon_vma if it's empty */ + empty = list_empty(&anon_vma->head); up_write(&anon_vma->sem); - put_anon_vma(anon_vma); + + if (empty) + anon_vma_free(anon_vma); } static void anon_vma_ctor(struct kmem_cache *cachep, void *data) @@ -142,7 +142,6 @@ static void anon_vma_ctor(struct kmem_ca struct anon_vma *anon_vma = data; init_rwsem(&anon_vma->sem); - atomic_set(&anon_vma->refcount, 0); INIT_LIST_HEAD(&anon_vma->head); } @@ -156,11 +155,13 @@ void __init anon_vma_init(void) * Getting a lock on a stable anon_vma from a page off the LRU is * tricky: page_lock_anon_vma rely on RCU to guard against the races. */ -struct anon_vma *grab_anon_vma(struct page *page) +struct anon_vma *page_lock_anon_vma(struct page *page) { - struct anon_vma *anon_vma = NULL; + struct anon_vma *anon_vma; unsigned long anon_mapping; +retry: + anon_vma = NULL; rcu_read_lock(); anon_mapping = (unsigned long) page->mapping; if (!(anon_mapping & PAGE_MAPPING_ANON)) @@ -169,26 +170,24 @@ struct anon_vma *grab_anon_vma(struct pa goto out; anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); - if (!atomic_inc_not_zero(&anon_vma->refcount)) + if (unlikely(!down_read_trylock(&anon_vma->sem))) { + /* We behave like a spinlock here sigh... */ + rcu_read_unlock(); + cpu_relax(); + goto retry; + } + if (list_empty(&anon_vma->head)) { + up_read(&anon_vma->sem); anon_vma = NULL; + } out: rcu_read_unlock(); return anon_vma; } -static struct anon_vma *page_lock_anon_vma(struct page *page) -{ - struct anon_vma *anon_vma = grab_anon_vma(page); - - if (anon_vma) - down_read(&anon_vma->sem); - return anon_vma; -} - static void page_unlock_anon_vma(struct anon_vma *anon_vma) { up_read(&anon_vma->sem); - put_anon_vma(anon_vma); } /*