[PATCH] adapt page_lock_anon_vma() to PREEMPT_RCU

Oleg Nesterov
2007-02-25T20:06:24Z

page_lock_anon_vma() uses spin_lock() to block RCU. This doesn't work with
PREEMPT_RCU, we have to do rcu_read_lock() explicitely. Otherwise, it is
theoretically possible that slab returns anon_vma's memory to the system
before we do spin_unlock(&anon_vma->lock).

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>

--- WQ/mm/rmap.c~ 2007-02-18 22:56:49.000000000 +0300
+++ WQ/mm/rmap.c 2007-02-25 22:43:00.000000000 +0300
@@ -183,7 +183,7 @@ void __init anon_vma_init(void)
*/
static 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;

rcu_read_lock();
@@ -195,9 +195,16 @@ static struct anon_vma *page_lock_anon_v

anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
spin_lock(&anon_vma->lock);
+ return anon_vma;
out:
rcu_read_unlock();
- return anon_vma;
+ return NULL;
+}
+
+static void page_unlock_anon_vma(struct anon_vma *anon_vma)
+{
+ spin_unlock(&anon_vma->lock);
+ rcu_read_unlock();
}

/*
@@ -333,7 +340,8 @@ static int page_referenced_anon(struct p
if (!mapcount)
break;
}
- spin_unlock(&anon_vma->lock);
+
+ page_unlock_anon_vma(anon_vma);
return referenced;
}

@@ -809,7 +817,8 @@ static int try_to_unmap_anon(struct page
!page_mapped(page))
break;
}
- spin_unlock(&anon_vma->lock);
+
+ page_unlock_anon_vma(anon_vma);
return ret;
}