Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision dbb29de402aedf0e136e946bd4ad53cc6beecc25)
+++ kernel/generic/src/mm/as.c	(revision 8cffdf5617a1f3e25f0ecdc728addb5bdd6718c2)
@@ -520,4 +520,47 @@
 }
 
+/** Remove reference to address space area share info.
+ *
+ * If the reference count drops to 0, the sh_info is deallocated.
+ *
+ * @param sh_info Pointer to address space area share info.
+ *
+ */
+NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
+{
+	bool dealloc = false;
+	
+	mutex_lock(&sh_info->lock);
+	ASSERT(sh_info->refcount);
+	
+	if (--sh_info->refcount == 0) {
+		dealloc = true;
+		
+		/*
+		 * Now walk carefully the pagemap B+tree and free/remove
+		 * reference from all frames found there.
+		 */
+		list_foreach(sh_info->pagemap.leaf_list, leaf_link,
+		    btree_node_t, node) {
+			btree_key_t i;
+			
+			for (i = 0; i < node->keys; i++)
+				frame_free((uintptr_t) node->value[i], 1);
+		}
+		
+	}
+	mutex_unlock(&sh_info->lock);
+	
+	if (dealloc) {
+		if (sh_info->backend && sh_info->backend->destroy_shared_data) {
+			sh_info->backend->destroy_shared_data(
+			    sh_info->backend_shared_data);
+		}
+		btree_destroy(&sh_info->pagemap);
+		free(sh_info);
+	}
+}
+
+
 /** Create address space area of common attributes.
  *
@@ -566,6 +609,8 @@
 	}
 
-	if (overflows_into_positive(*base, size))
+	if (overflows_into_positive(*base, size)) {
+		mutex_unlock(&as->lock);
 		return NULL;
+	}
 
 	if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
@@ -584,6 +629,6 @@
 	area->resident = 0;
 	area->base = *base;
+	area->backend = backend;
 	area->sh_info = NULL;
-	area->backend = backend;
 	
 	if (backend_data)
@@ -591,13 +636,43 @@
 	else
 		memsetb(&area->backend_data, sizeof(area->backend_data), 0);
-	
+
+	share_info_t *si = NULL;
+
+	/*
+ 	 * Create the sharing info structure.
+ 	 * We do this in advance for every new area, even if it is not going
+ 	 * to be shared.
+ 	 */
+	if (!(attrs & AS_AREA_ATTR_PARTIAL)) {
+		si = (share_info_t *) malloc(sizeof(share_info_t), 0);
+		mutex_initialize(&si->lock, MUTEX_PASSIVE);
+		si->refcount = 1;
+		si->shared = false;
+		si->backend_shared_data = NULL;
+		si->backend = backend;
+		btree_create(&si->pagemap);
+
+		area->sh_info = si;
+	
+		if (area->backend && area->backend->create_shared_data) {
+			if (!area->backend->create_shared_data(area)) {
+				free(area);
+				mutex_unlock(&as->lock);
+				sh_info_remove_reference(si);
+				return NULL;
+			}
+		}
+	}
+
 	if (area->backend && area->backend->create) {
 		if (!area->backend->create(area)) {
 			free(area);
 			mutex_unlock(&as->lock);
+			if (!(attrs & AS_AREA_ATTR_PARTIAL))
+				sh_info_remove_reference(si);
 			return NULL;
 		}
 	}
-	
+
 	btree_create(&area->used_space);
 	btree_insert(&as->as_area_btree, *base, (void *) area,
@@ -709,13 +784,16 @@
 	}
 	
-	if (area->sh_info) {
+	mutex_lock(&area->sh_info->lock);
+	if (area->sh_info->shared) {
 		/*
 		 * Remapping of shared address space areas
 		 * is not supported.
 		 */
+		mutex_unlock(&area->sh_info->lock);
 		mutex_unlock(&area->lock);
 		mutex_unlock(&as->lock);
 		return ENOTSUP;
 	}
+	mutex_unlock(&area->sh_info->lock);
 	
 	size_t pages = SIZE2FRAMES((address - area->base) + size);
@@ -881,42 +959,4 @@
 }
 
-/** Remove reference to address space area share info.
- *
- * If the reference count drops to 0, the sh_info is deallocated.
- *
- * @param sh_info Pointer to address space area share info.
- *
- */
-NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
-{
-	bool dealloc = false;
-	
-	mutex_lock(&sh_info->lock);
-	ASSERT(sh_info->refcount);
-	
-	if (--sh_info->refcount == 0) {
-		dealloc = true;
-		
-		/*
-		 * Now walk carefully the pagemap B+tree and free/remove
-		 * reference from all frames found there.
-		 */
-		list_foreach(sh_info->pagemap.leaf_list, leaf_link,
-		    btree_node_t, node) {
-			btree_key_t i;
-			
-			for (i = 0; i < node->keys; i++)
-				frame_free((uintptr_t) node->value[i], 1);
-		}
-		
-	}
-	mutex_unlock(&sh_info->lock);
-	
-	if (dealloc) {
-		btree_destroy(&sh_info->pagemap);
-		free(sh_info);
-	}
-}
-
 /** Destroy address space area.
  *
@@ -1000,6 +1040,5 @@
 	area->attributes |= AS_AREA_ATTR_PARTIAL;
 	
-	if (area->sh_info)
-		sh_info_remove_reference(area->sh_info);
+	sh_info_remove_reference(area->sh_info);
 	
 	mutex_unlock(&area->lock);
@@ -1088,19 +1127,17 @@
 	 */
 	share_info_t *sh_info = src_area->sh_info;
-	if (!sh_info) {
-		sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
-		mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
-		sh_info->refcount = 2;
-		btree_create(&sh_info->pagemap);
-		src_area->sh_info = sh_info;
-		
+	
+	mutex_lock(&sh_info->lock);
+	sh_info->refcount++;
+	bool shared = sh_info->shared;
+	sh_info->shared = true;
+	mutex_unlock(&sh_info->lock);
+
+	if (!shared) {
 		/*
 		 * Call the backend to setup sharing.
+		 * This only happens once for each sh_info.
 		 */
 		src_area->backend->share(src_area);
-	} else {
-		mutex_lock(&sh_info->lock);
-		sh_info->refcount++;
-		mutex_unlock(&sh_info->lock);
 	}
 	
@@ -1221,6 +1258,5 @@
 	}
 	
-	if ((area->sh_info) || (area->backend != &anon_backend)) {
-		/* Copying shared areas not supported yet */
+	if (area->backend != &anon_backend) {
 		/* Copying non-anonymous memory not supported yet */
 		mutex_unlock(&area->lock);
@@ -1228,4 +1264,14 @@
 		return ENOTSUP;
 	}
+
+	mutex_lock(&area->sh_info->lock);
+	if (area->sh_info->shared) {
+		/* Copying shared areas not supported yet */
+		mutex_unlock(&area->sh_info->lock);
+		mutex_unlock(&area->lock);
+		mutex_unlock(&as->lock);
+		return ENOTSUP;
+	}
+	mutex_unlock(&area->sh_info->lock);
 	
 	/*
Index: kernel/generic/src/mm/backend_anon.c
===================================================================
--- kernel/generic/src/mm/backend_anon.c	(revision dbb29de402aedf0e136e946bd4ad53cc6beecc25)
+++ kernel/generic/src/mm/backend_anon.c	(revision 8cffdf5617a1f3e25f0ecdc728addb5bdd6718c2)
@@ -76,4 +76,7 @@
 	.page_fault = anon_page_fault,
 	.frame_free = anon_frame_free,
+
+	.create_shared_data = NULL,
+	.destroy_shared_data = NULL
 };
 
@@ -190,5 +193,6 @@
 		return AS_PF_FAULT;
 
-	if (area->sh_info) {
+	mutex_lock(&area->sh_info->lock);
+	if (area->sh_info->shared) {
 		btree_node_t *leaf;
 		
@@ -200,5 +204,4 @@
 		 * mapping, a new frame is allocated and the mapping is created.
 		 */
-		mutex_lock(&area->sh_info->lock);
 		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
 		    upage - area->base, &leaf);
@@ -232,5 +235,4 @@
 		}
 		frame_reference_add(ADDR2PFN(frame));
-		mutex_unlock(&area->sh_info->lock);
 	} else {
 
@@ -254,6 +256,8 @@
 			 * Reserve the memory for this page now.
 			 */
-			if (!reserve_try_alloc(1))
+			if (!reserve_try_alloc(1)) {
+				mutex_unlock(&area->sh_info->lock);
 				return AS_PF_SILENT;
+			}
 		}
 
@@ -262,4 +266,5 @@
 		km_temporary_page_put(kpage);
 	}
+	mutex_unlock(&area->sh_info->lock);
 	
 	/*
Index: kernel/generic/src/mm/backend_elf.c
===================================================================
--- kernel/generic/src/mm/backend_elf.c	(revision dbb29de402aedf0e136e946bd4ad53cc6beecc25)
+++ kernel/generic/src/mm/backend_elf.c	(revision 8cffdf5617a1f3e25f0ecdc728addb5bdd6718c2)
@@ -75,4 +75,7 @@
 	.page_fault = elf_page_fault,
 	.frame_free = elf_frame_free,
+
+	.create_shared_data = NULL,
+	.destroy_shared_data = NULL
 };
 
@@ -274,5 +277,6 @@
 	start_anon = entry->p_vaddr + entry->p_filesz;
 
-	if (area->sh_info) {
+	mutex_lock(&area->sh_info->lock);
+	if (area->sh_info->shared) {
 		bool found = false;
 
@@ -281,5 +285,4 @@
 		 */
 		
-		mutex_lock(&area->sh_info->lock);
 		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
 		    upage - area->base, &leaf);
@@ -384,5 +387,5 @@
 	}
 
-	if (dirty && area->sh_info) {
+	if (dirty && area->sh_info->shared) {
 		frame_reference_add(ADDR2PFN(frame));
 		btree_insert(&area->sh_info->pagemap, upage - area->base,
@@ -390,6 +393,5 @@
 	}
 
-	if (area->sh_info)
-		mutex_unlock(&area->sh_info->lock);
+	mutex_unlock(&area->sh_info->lock);
 
 	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
Index: kernel/generic/src/mm/backend_phys.c
===================================================================
--- kernel/generic/src/mm/backend_phys.c	(revision dbb29de402aedf0e136e946bd4ad53cc6beecc25)
+++ kernel/generic/src/mm/backend_phys.c	(revision 8cffdf5617a1f3e25f0ecdc728addb5bdd6718c2)
@@ -55,6 +55,13 @@
 static bool phys_is_shareable(as_area_t *);
 
+static int phys_page_fault(as_area_t *, uintptr_t, pf_access_t);
 
-static int phys_page_fault(as_area_t *, uintptr_t, pf_access_t);
+static bool phys_create_shared_data(as_area_t *);
+static void phys_destroy_shared_data(void *);
+
+typedef struct {
+	uintptr_t base;
+	size_t frames;	
+} phys_shared_data_t;
 
 mem_backend_t phys_backend = {
@@ -69,5 +76,9 @@
 	.page_fault = phys_page_fault,
 	.frame_free = NULL,
+	
+	.create_shared_data = phys_create_shared_data,
+	.destroy_shared_data = phys_destroy_shared_data
 };
+
 
 bool phys_create(as_area_t *area)
@@ -92,16 +103,9 @@
 void phys_destroy(as_area_t *area)
 {
-	mem_backend_data_t *data = &area->backend_data;
-	bool last = true;
-
-	if (area->sh_info) {
-		mutex_lock(&area->sh_info->lock);
-		if (area->sh_info->refcount != 1)
-			last = false;
-		mutex_unlock(&area->sh_info->lock);
-	}
-	
-	if (last && data->anonymous)
-		frame_free(data->base, data->frames);
+	/*
+	 * Nothing to do.
+	 * The anonymous frames, if any, are released in
+	 * phys_destroy_shared_data().
+	 */
 }
 
@@ -149,4 +153,32 @@
 }
 
+bool phys_create_shared_data(as_area_t *area)
+{
+	/*
+	 * For anonymous phys areas, create the shared data.
+	 */
+	if (area->backend_data.anonymous) {
+		phys_shared_data_t *data;
+
+		data = (phys_shared_data_t *) malloc(sizeof(*data), 0);
+
+		data->base = area->backend_data.base;
+		data->frames = area->backend_data.frames;
+		area->sh_info->backend_shared_data = data;
+	}
+
+	return true;
+}
+
+void phys_destroy_shared_data(void *opaque_data)
+{
+	phys_shared_data_t *data = (phys_shared_data_t *) opaque_data;
+
+	if (data) {
+		frame_free(data->base, data->frames);
+		free(data);
+	}
+}
+
 /** @}
  */
