--- include/linux/rmap.h | 2 +- mm/rmap.c | 38 ++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) Index: linux-2.6/include/linux/rmap.h =================================================================== --- linux-2.6.orig/include/linux/rmap.h 2008-02-27 20:06:44.000000000 -0800 +++ linux-2.6/include/linux/rmap.h 2008-02-27 20:07:05.000000000 -0800 @@ -25,7 +25,7 @@ * pointing to this anon_vma once its vma list is empty. */ struct anon_vma { - spinlock_t lock; /* Serialize access to vma list */ + struct rw_semaphore sem;/* Serialize access to vma list */ struct list_head head; /* List of private "related" vmas */ }; Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c 2008-02-27 20:06:21.000000000 -0800 +++ linux-2.6/mm/rmap.c 2008-02-27 20:13:04.000000000 -0800 @@ -25,7 +25,7 @@ * mm->mmap_sem * page->flags PG_locked (lock_page) * mapping->i_mmap_sem - * anon_vma->lock + * anon_vma->sem * mm->page_table_lock or pte_lock * zone->lru_lock (in mark_page_accessed, isolate_lru_page) * swap_lock (in swap_duplicate, swap_info_get) @@ -68,7 +68,7 @@ int anon_vma_prepare(struct vm_area_stru if (anon_vma) { allocated = NULL; locked = anon_vma; - spin_lock(&locked->lock); + down_write(&locked->sem); } else { anon_vma = anon_vma_alloc(); if (unlikely(!anon_vma)) @@ -87,7 +87,7 @@ int anon_vma_prepare(struct vm_area_stru spin_unlock(&mm->page_table_lock); if (locked) - spin_unlock(&locked->lock); + up_write(&locked->sem); if (unlikely(allocated)) anon_vma_free(allocated); } @@ -113,9 +113,9 @@ void anon_vma_link(struct vm_area_struct struct anon_vma *anon_vma = vma->anon_vma; if (anon_vma) { - spin_lock(&anon_vma->lock); + down_write(&anon_vma->sem); list_add_tail(&vma->anon_vma_node, &anon_vma->head); - spin_unlock(&anon_vma->lock); + up_write(&anon_vma->sem); } } @@ -127,12 +127,12 @@ void anon_vma_unlink(struct vm_area_stru if (!anon_vma) return; - spin_lock(&anon_vma->lock); + 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); - spin_unlock(&anon_vma->lock); + up_write(&anon_vma->lock); if (empty) anon_vma_free(anon_vma); @@ -142,7 +142,7 @@ static void anon_vma_ctor(struct kmem_ca { struct anon_vma *anon_vma = data; - spin_lock_init(&anon_vma->lock); + init_rwsem(&anon_vma->sem); INIT_LIST_HEAD(&anon_vma->head); } @@ -156,7 +156,7 @@ 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. */ -static struct anon_vma *page_lock_anon_vma(struct page *page) +static struct anon_vma *page_lock_anon_vma(struct page *page, int write) { struct anon_vma *anon_vma; unsigned long anon_mapping; @@ -169,16 +169,22 @@ static struct anon_vma *page_lock_anon_v goto out; anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); - spin_lock(&anon_vma->lock); + if (write) + down_write(&anon_vma->sem); + else + down_read(&anon_vma->sem); return anon_vma; out: rcu_read_unlock(); return NULL; } -static void page_unlock_anon_vma(struct anon_vma *anon_vma) +static void page_unlock_anon_vma(struct anon_vma *anon_vma, int write) { - spin_unlock(&anon_vma->lock); + if (write) + up_write(&anon_vma->sem); + else + up_read(&anon_vma->sem); rcu_read_unlock(); } @@ -310,7 +316,7 @@ static int page_referenced_anon(struct p struct vm_area_struct *vma; int referenced = 0; - anon_vma = page_lock_anon_vma(page); + anon_vma = page_lock_anon_vma(page, 0); if (!anon_vma) return referenced; @@ -328,7 +334,7 @@ static int page_referenced_anon(struct p break; } - page_unlock_anon_vma(anon_vma); + page_unlock_anon_vma(anon_vma, 0); return referenced; } @@ -873,7 +879,7 @@ static int try_to_unmap_anon(struct page struct vm_area_struct *vma; int ret = SWAP_AGAIN; - anon_vma = page_lock_anon_vma(page); + anon_vma = page_lock_anon_vma(page, 0); if (!anon_vma) return ret; @@ -883,7 +889,7 @@ static int try_to_unmap_anon(struct page break; } - page_unlock_anon_vma(anon_vma); + page_unlock_anon_vma(anon_vma, 0); return ret; }