Index: genarch/src/mm/as_ht.c
===================================================================
--- genarch/src/mm/as_ht.c	(revision 25d77096d63abbb97d50a9cafaf9e3e5379a6f5d)
+++ genarch/src/mm/as_ht.c	(revision 2ba1f399b0ec9f1f1ad59e12cea559c929b36ddf)
@@ -35,9 +35,15 @@
 #include <memstr.h>
 #include <adt/hash_table.h>
+#include <synch/spinlock.h>
 
 static pte_t *ht_create(int flags);
 
+static void ht_lock(as_t *as, bool lock);
+static void ht_unlock(as_t *as, bool unlock);
+
 as_operations_t as_ht_operations = {
-	.page_table_create = ht_create
+	.page_table_create = ht_create,
+	.page_table_lock = ht_lock,
+	.page_table_unlock = ht_unlock,
 };
 
@@ -59,2 +65,32 @@
 	return NULL;
 }
+
+/** Lock page table.
+ *
+ * Lock address space and page hash table.
+ * Interrupts must be disabled.
+ *
+ * @param as Address space.
+ * @param lock If false, do not attempt to lock the address space.
+ */
+void ht_lock(as_t *as, bool lock)
+{
+	if (lock)
+		spinlock_lock(&as->lock);
+	spinlock_lock(&page_ht_lock);
+}
+
+/** Unlock page table.
+ *
+ * Unlock address space and page hash table.
+ * Interrupts must be disabled.
+ *
+ * @param as Address space.
+ * @param unlock If false, do not attempt to lock the address space.
+ */
+void ht_unlock(as_t *as, bool unlock)
+{
+	spinlock_unlock(&page_ht_lock);
+	if (unlock)
+		spinlock_unlock(&as->lock);
+}
Index: genarch/src/mm/as_pt.c
===================================================================
--- genarch/src/mm/as_pt.c	(revision 25d77096d63abbb97d50a9cafaf9e3e5379a6f5d)
+++ genarch/src/mm/as_pt.c	(revision 2ba1f399b0ec9f1f1ad59e12cea559c929b36ddf)
@@ -40,6 +40,11 @@
 static pte_t *ptl0_create(int flags);
 
+static void pt_lock(as_t *as, bool lock);
+static void pt_unlock(as_t *as, bool unlock);
+
 as_operations_t as_pt_operations = {
-	.page_table_create = ptl0_create
+	.page_table_create = ptl0_create,
+	.page_table_lock = pt_lock,
+	.page_table_unlock = pt_unlock
 };
 
@@ -77,2 +82,30 @@
 	return (pte_t *) KA2PA((__address) dst_ptl0);
 }
+
+/** Lock page tables.
+ *
+ * Lock only the address space.
+ * Interrupts must be disabled.
+ *
+ * @param as Address space.
+ * @param lock If false, do not attempt to lock the address space.
+ */
+void pt_lock(as_t *as, bool lock)
+{
+	if (lock)
+		spinlock_lock(&as->lock);
+}
+
+/** Unlock page tables.
+ *
+ * Unlock the address space.
+ * Interrupts must be disabled.
+ *
+ * @param as Address space.
+ * @param unlock If false, do not attempt to unlock the address space.
+ */
+void pt_unlock(as_t *as, bool unlock)
+{
+	if (unlock)
+		spinlock_unlock(&as->lock);
+}
Index: genarch/src/mm/page_ht.c
===================================================================
--- genarch/src/mm/page_ht.c	(revision 25d77096d63abbb97d50a9cafaf9e3e5379a6f5d)
+++ genarch/src/mm/page_ht.c	(revision 2ba1f399b0ec9f1f1ad59e12cea559c929b36ddf)
@@ -53,5 +53,7 @@
 
 /**
- * This lock protects the page hash table.
+ * This lock protects the page hash table. It must be acquired
+ * after address space lock and after any address space area
+ * locks.
  */
 SPINLOCK_INITIALIZE(page_ht_lock);
@@ -156,5 +158,5 @@
  * using 'flags'. 
  *
- * The address space must be locked and interruptsmust be disabled.
+ * The page table must be locked and interrupts must be disabled.
  *
  * @param as Address space to which page belongs.
@@ -168,6 +170,4 @@
 	__native key[2] = { (__address) as, page = ALIGN_DOWN(page, PAGE_SIZE) };
 	
-	spinlock_lock(&page_ht_lock);
-
 	if (!hash_table_find(&page_ht, key)) {
 		t = (pte_t *) malloc(sizeof(pte_t), FRAME_ATOMIC);
@@ -187,6 +187,4 @@
 		hash_table_insert(&page_ht, key, &t->link);
 	}
-	
-	spinlock_unlock(&page_ht_lock);
 }
 
@@ -197,5 +195,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.
@@ -206,6 +204,4 @@
 	__native key[2] = { (__address) as, page = ALIGN_DOWN(page, PAGE_SIZE) };
 	
-	spinlock_lock(&page_ht_lock);
-
 	/*
 	 * Note that removed PTE's will be freed
@@ -213,6 +209,4 @@
 	 */
 	hash_table_remove(&page_ht, key, 2);
-
-	spinlock_unlock(&page_ht_lock);
 }
 
@@ -222,5 +216,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.
@@ -235,11 +229,8 @@
 	__native key[2] = { (__address) as, page = ALIGN_DOWN(page, PAGE_SIZE) };
 	
-	spinlock_lock(&page_ht_lock);
-
 	hlp = hash_table_find(&page_ht, key);
 	if (hlp)
 		t = hash_table_get_instance(hlp, pte_t, link);
 
-	spinlock_unlock(&page_ht_lock);
 	return t;
 }
Index: genarch/src/mm/page_pt.c
===================================================================
--- genarch/src/mm/page_pt.c	(revision 25d77096d63abbb97d50a9cafaf9e3e5379a6f5d)
+++ genarch/src/mm/page_pt.c	(revision 2ba1f399b0ec9f1f1ad59e12cea559c929b36ddf)
@@ -53,5 +53,5 @@
  * using 'flags'.
  *
- * 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.
@@ -106,5 +106,5 @@
  * Empty page tables except PTL0 are freed.
  *
- * 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.
@@ -226,5 +226,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 which page belongs.
