Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 5df19638ae7b362a07b4f8c7b1647a3adcb53862)
+++ kernel/generic/src/mm/as.c	(revision b0b4592eb25faf25f7b76856933e928c3b8c004a)
@@ -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);
 	
 	/*
