Index: generic/src/mm/as.c
===================================================================
--- generic/src/mm/as.c	(revision b6b576cff6e554b94baf578554e7488d2ac08253)
+++ generic/src/mm/as.c	(revision e898a8d77f67f8d3d4d935a99363c68ad93f35af)
@@ -174,5 +174,5 @@
 	
 	ipl = interrupts_disable();
-	spinlock_lock(&as->lock);
+	page_table_lock(as, true);
 	
 	area = find_area_and_lock(as, page);
@@ -184,5 +184,5 @@
 	
 	spinlock_unlock(&area->lock);
-	spinlock_unlock(&as->lock);
+	page_table_unlock(as, true);
 	interrupts_restore(ipl);
 }
@@ -199,10 +199,11 @@
 int as_page_fault(__address page)
 {
+	pte_t *pte;
 	as_area_t *area;
 	__address frame;
 	
 	ASSERT(AS);
+
 	spinlock_lock(&AS->lock);
-	
 	area = find_area_and_lock(AS, page);	
 	if (!area) {
@@ -213,4 +214,20 @@
 		spinlock_unlock(&AS->lock);
 		return 0;
+	}
+
+	page_table_lock(AS, false);
+	
+	/*
+	 * To avoid race condition between two page faults
+	 * on the same address, we need to make sure
+	 * the mapping has not been already inserted.
+	 */
+	if ((pte = page_mapping_find(AS, page))) {
+		if (PTE_PRESENT(pte)) {
+			page_table_unlock(AS, false);
+			spinlock_unlock(&area->lock);
+			spinlock_unlock(&AS->lock);
+			return 1;
+		}
 	}
 
@@ -238,8 +255,8 @@
 	 */
 	page_mapping_insert(AS, page, frame, get_area_flags(area));
+	page_table_unlock(AS, false);
 	
 	spinlock_unlock(&area->lock);
 	spinlock_unlock(&AS->lock);
-
 	return 1;
 }
@@ -358,4 +375,37 @@
 }
 
+/** Lock page table.
+ *
+ * This function should be called before any page_mapping_insert(),
+ * page_mapping_remove() and page_mapping_find().
+ * 
+ * Locking order is such that address space areas must be locked
+ * prior to this call. Address space can be locked prior to this
+ * call in which case the lock argument is false.
+ *
+ * @param as Address space.
+ * @param as_locked If false, do not attempt to lock as->lock.
+ */
+void page_table_lock(as_t *as, bool lock)
+{
+	ASSERT(as_operations);
+	ASSERT(as_operations->page_table_lock);
+
+	as_operations->page_table_lock(as, lock);
+}
+
+/** Unlock page table.
+ *
+ * @param as Address space.
+ * @param as_locked If false, do not attempt to unlock as->lock.
+ */
+void page_table_unlock(as_t *as, bool unlock)
+{
+	ASSERT(as_operations);
+	ASSERT(as_operations->page_table_unlock);
+
+	as_operations->page_table_unlock(as, unlock);
+}
+
 /** Find address space area and change it.
  *
@@ -398,10 +448,18 @@
 			 * Releasing physical memory.
 			 * This depends on the fact that the memory was allocated using frame_alloc().
-			 */ 
+			 */
+			page_table_lock(as, false);
 			pte = page_mapping_find(as, area->base + i*PAGE_SIZE);
 			if (pte && PTE_VALID(pte)) {
+				__address frame;
+
 				ASSERT(PTE_PRESENT(pte));
-				frame_free(ADDR2PFN(PTE_GET_FRAME(pte)));
+				frame = PTE_GET_FRAME(pte);
 				page_mapping_remove(as, area->base + i*PAGE_SIZE);
+				page_table_unlock(as, false);
+
+				frame_free(ADDR2PFN(frame));
+			} else {
+				page_table_unlock(as, false);
 			}
 		}
Index: generic/src/mm/page.c
===================================================================
--- generic/src/mm/page.c	(revision b6b576cff6e554b94baf578554e7488d2ac08253)
+++ generic/src/mm/page.c	(revision e898a8d77f67f8d3d4d935a99363c68ad93f35af)
@@ -77,5 +77,5 @@
  * using 'flags'. Allocate and setup any missing page tables.
  *
- * The address space must be locked and interrupts must be disabled.
+ * The page table must be locked and interrupts must be disabled.
  *
  * @param as Address space to wich page belongs.
@@ -98,5 +98,5 @@
  * this call visible.
  *
- * The address space must be locked and interrupts must be disabled.
+ * The page table must be locked and interrupts must be disabled.
  *
  * @param as Address space to wich page belongs.
@@ -115,5 +115,5 @@
  * Find mapping for virtual page.
  *
- * The address space must be locked and interrupts must be disabled.
+ * The page table must be locked and interrupts must be disabled.
  *
  * @param as Address space to wich page belongs.
