Index: .gitignore
===================================================================
--- .gitignore	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ .gitignore	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -110,5 +110,4 @@
 uspace/app/init/init
 uspace/app/init/init.gz
-uspace/app/lprint/lprint
 uspace/app/kill/kill
 uspace/app/killall/killall
@@ -134,4 +133,6 @@
 uspace/app/ping6/ping6
 uspace/app/pkg/pkg
+uspace/app/rcubench/rcubench
+uspace/app/rcutest/rcutest
 uspace/app/redir/redir
 uspace/app/sbi/sbi
@@ -210,4 +211,6 @@
 uspace/dist/app/ping6
 uspace/dist/app/pkg
+uspace/dist/app/rcubench
+uspace/dist/app/rcutest
 uspace/dist/app/redir
 uspace/dist/app/sbi
@@ -311,5 +314,4 @@
 uspace/drv/char/msim-con/msim-con
 uspace/drv/char/ns8250/ns8250
-uspace/drv/char/pc-lpt/pc-lpt
 uspace/drv/char/pl050/pl050
 uspace/drv/char/ps2mouse/ps2mouse
Index: abi/doc/doxygroups.h
===================================================================
--- abi/doc/doxygroups.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ abi/doc/doxygroups.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -50,5 +50,5 @@
 
 /**
- * @defgroup abi_riscv64 riscv64
+ * @defgroup abi_riscv5 riscv5
  * @ingroup abi
  */
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ boot/Makefile.common	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -183,5 +183,4 @@
 	killall \
 	loc \
-	lprint \
 	mixerctl \
 	modplay \
@@ -193,4 +192,6 @@
 	nic \
 	perf \
+	rcutest \
+	rcubench \
 	sbi \
 	sportdmp \
Index: boot/arch/amd64/Makefile.inc
===================================================================
--- boot/arch/amd64/Makefile.inc	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ boot/arch/amd64/Makefile.inc	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -46,5 +46,4 @@
 	audio/hdaudio \
 	char/ns8250 \
-	char/pc-lpt \
 	time/cmos-rtc \
 	bus/usb/ehci\
Index: contrib/qemu/build-from-scratch.sh
===================================================================
--- contrib/qemu/build-from-scratch.sh	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ contrib/qemu/build-from-scratch.sh	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -29,5 +29,5 @@
 #
 
-VERSION=3.1.0
+VERSION=3.0.0
 BASENAME=qemu-${VERSION}
 BASENAME_MASTER=qemu-master
Index: defaults/arm32/beagleboardxm/Makefile.config
===================================================================
--- defaults/arm32/beagleboardxm/Makefile.config	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ defaults/arm32/beagleboardxm/Makefile.config	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -10,5 +10,2 @@
 CONFIG_BFB_MODE = 1024x768
 CONFIG_BFB_BPP = 24
-
-# Barebone build with essential binaries only
-CONFIG_BAREBONE = y
Index: defaults/arm32/beaglebone/Makefile.config
===================================================================
--- defaults/arm32/beaglebone/Makefile.config	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ defaults/arm32/beaglebone/Makefile.config	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -7,5 +7,2 @@
 #framebuffer
 CONFIG_FB = n
-
-# Barebone build with essential binaries only
-CONFIG_BAREBONE = y
Index: kernel/Makefile
===================================================================
--- kernel/Makefile	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/Makefile	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -162,4 +162,5 @@
 GENERIC_SOURCES = \
 	generic/src/adt/bitmap.c \
+	generic/src/adt/btree.c \
 	generic/src/adt/hash_table.c \
 	generic/src/adt/list.c \
@@ -278,4 +279,5 @@
 		test/test.c \
 		test/atomic/atomic1.c \
+		test/btree/btree1.c \
 		test/fault/fault1.c \
 		test/mm/falloc1.c \
@@ -312,4 +314,5 @@
 ifeq ($(CONFIG_TRACE),y)
 	INSTRUMENTED_SOURCES = \
+		generic/src/adt/btree.c \
 		generic/src/cpu/cpu.c \
 		generic/src/ddi/ddi.c \
Index: kernel/arch/arm32/include/arch/context.h
===================================================================
--- kernel/arch/arm32/include/arch/context.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/arch/arm32/include/arch/context.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -40,5 +40,4 @@
 #include <arch/stack.h>
 #include <arch/context_struct.h>
-#include <arch/regutils.h>
 
 /* Put one item onto the stack to support get_stack_base() and align it up. */
@@ -50,5 +49,4 @@
 		(c)->sp = ((uintptr_t) (stack)) + (size) - SP_DELTA; \
 		(c)->fp = 0; \
-		(c)->cpu_mode = SUPERVISOR_MODE; \
 	} while (0)
 
Index: kernel/arch/sparc64/src/sun4v/start.S
===================================================================
--- kernel/arch/sparc64/src/sun4v/start.S	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/arch/sparc64/src/sun4v/start.S	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -162,7 +162,7 @@
 
 	! map kernel in context 1
-	set kernel_load_address, %o0				! virt. address
+	set kernel_image_start, %o0				! virt. address
 	set 1, %o1						! context
-	TTE_DATA(kernel_load_address, %l5, %g2, %g3, %o2)	! TTE data
+	TTE_DATA(kernel_image_start, %l5, %g2, %g3, %o2)	! TTE data
 	set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3			! MMU flags
 	__HYPERCALL_HYPERFAST(MMU_MAP_ADDR)
@@ -181,7 +181,7 @@
 
 	! install permanent mapping for kernel in context 0
-	set kernel_load_address, %o0				! virtual address
+	set kernel_image_start, %o0				! virtual address
 	set 0, %o1						! context
-	TTE_DATA(kernel_load_address, %l5, %g2, %g3, %o2)	! TTE data
+	TTE_DATA(kernel_image_start, %l5, %g2, %g3, %o2)	! TTE data
 	set MMU_FLAG_DTLB | MMU_FLAG_ITLB, %o3			! MMU flags
 	__HYPERCALL_FAST(MMU_MAP_PERM_ADDR)
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -55,8 +55,8 @@
 	/*
 	 * Find last occurence of '/' before 'end'. If found, place start at
-	 * next character. Otherwise, place start at beginning of command line.
+	 * next character. Otherwise, place start at beginning of buffer.
 	 */
 	const char *cp = end;
-	const char *start = cmd_line;
+	const char *start = buf;
 
 	while (cp != start) {
Index: kernel/generic/include/adt/btree.h
===================================================================
--- kernel/generic/include/adt/btree.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
+++ kernel/generic/include/adt/btree.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kernel_generic_adt
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KERN_BTREE_H_
+#define KERN_BTREE_H_
+
+#include <adt/list.h>
+#include <stddef.h>
+
+#define BTREE_M		5
+#define BTREE_MAX_KEYS	(BTREE_M - 1)
+
+typedef uint64_t btree_key_t;
+
+/** B-tree node structure. */
+typedef struct btree_node {
+	/** Number of keys. */
+	size_t keys;
+
+	/**
+	 * Keys. We currently support only single keys. Additional room for one
+	 * extra key is provided.
+	 */
+	btree_key_t key[BTREE_MAX_KEYS + 1];
+
+	/**
+	 * Pointers to values. Sorted according to the key array. Defined only in
+	 * leaf-level. There is room for storing value for the extra key.
+	 */
+	void *value[BTREE_MAX_KEYS + 1];
+
+	/**
+	 * Pointers to descendants of this node sorted according to the key
+	 * array.
+	 *
+	 * subtree[0] points to subtree with keys lesser than to key[0].
+	 * subtree[1] points to subtree with keys greater than or equal to
+	 *	      key[0] and lesser than key[1].
+	 * ...
+	 * There is room for storing a subtree pointer for the extra key.
+	 */
+	struct btree_node *subtree[BTREE_M + 1];
+
+	/** Pointer to parent node. Root node has NULL parent. */
+	struct btree_node *parent;
+
+	/**
+	 * Link connecting leaf-level nodes. Defined only when this node is a
+	 * leaf.
+	 */
+	link_t leaf_link;
+
+	/* Variables needed by btree_print(). */
+	link_t bfs_link;
+	int depth;
+} btree_node_t;
+
+/** B-tree structure. */
+typedef struct {
+	btree_node_t *root;	/**< B-tree root node pointer. */
+	list_t leaf_list;	/**< List of leaves. */
+} btree_t;
+
+extern void btree_init(void);
+
+extern void btree_create(btree_t *t);
+extern void btree_destroy(btree_t *t);
+
+extern void btree_insert(btree_t *t, btree_key_t key, void *value,
+    btree_node_t *leaf_node);
+extern void btree_remove(btree_t *t, btree_key_t key, btree_node_t *leaf_node);
+extern void *btree_search(btree_t *t, btree_key_t key, btree_node_t **leaf_node);
+
+extern btree_node_t *btree_leaf_node_left_neighbour(btree_t *t,
+    btree_node_t *node);
+extern btree_node_t *btree_leaf_node_right_neighbour(btree_t *t,
+    btree_node_t *node);
+
+extern void btree_print(btree_t *t);
+
+extern unsigned long btree_count(btree_t *t);
+
+#endif
+
+/** @}
+ */
Index: kernel/generic/include/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/include/mm/as.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -45,4 +45,5 @@
 #include <synch/mutex.h>
 #include <adt/list.h>
+#include <adt/btree.h>
 #include <adt/odict.h>
 #include <lib/elf.h>
@@ -136,48 +137,4 @@
 } as_operations_t;
 
-/** Single anonymous page mapping. */
-typedef struct {
-	/** Containing pagemap structure */
-	struct as_pagemap *pagemap;
-	/** Link to @c shinfo->pagemap ordered dictionary */
-	odlink_t lpagemap;
-	/** Virtual address */
-	uintptr_t vaddr;
-	/** Physical frame address */
-	uintptr_t frame;
-} as_page_mapping_t;
-
-/** Map of anonymous pages in a shared area. */
-typedef struct as_pagemap {
-	/**
-	 * Dictionary ordered by virtual address. Members are of type
-	 * as_page_mapping_t
-	 */
-	odict_t map;
-} as_pagemap_t;
-
-/** Used space interval */
-typedef struct {
-	/** Containing used_space structure */
-	struct used_space *used_space;
-	/** Link to @c used_space->ivals */
-	odlink_t lused_space;
-	/** First page address */
-	uintptr_t page;
-	/** Count of pages */
-	size_t count;
-} used_space_ival_t;
-
-/** Map of used space in an address space area */
-typedef struct used_space {
-	/**
-	 * Dictionary of intervals by start address.
-	 * Members are of type @c used_space_ival_t.
-	 */
-	odict_t ivals;
-	/** Total number of used pages. */
-	size_t pages;
-} used_space_t;
-
 /**
  * This structure contains information associated with the shared address space
@@ -193,6 +150,8 @@
 	bool shared;
 
-	/** Complete map of anonymous pages of the shared area. */
-	as_pagemap_t pagemap;
+	/**
+	 * B+tree containing complete map of anonymous pages of the shared area.
+	 */
+	btree_t pagemap;
 
 	/** Address space area backend. */
@@ -262,9 +221,12 @@
 	size_t pages;
 
+	/** Number of resident pages in the area. */
+	size_t resident;
+
 	/** Base address of this area. */
 	uintptr_t base;
 
 	/** Map of used space. */
-	used_space_t used_space;
+	btree_t used_space;
 
 	/**
@@ -321,19 +283,9 @@
 extern as_area_t *as_area_next(as_area_t *);
 
-extern void as_pagemap_initialize(as_pagemap_t *);
-extern void as_pagemap_finalize(as_pagemap_t *);
-extern as_page_mapping_t *as_pagemap_first(as_pagemap_t *);
-extern as_page_mapping_t *as_pagemap_next(as_page_mapping_t *);
-extern errno_t as_pagemap_find(as_pagemap_t *, uintptr_t, uintptr_t *);
-extern void as_pagemap_insert(as_pagemap_t *, uintptr_t, uintptr_t);
-extern void as_pagemap_remove(as_page_mapping_t *);
-
 extern unsigned int as_area_get_flags(as_area_t *);
 extern bool as_area_check_access(as_area_t *, pf_access_t);
 extern size_t as_area_get_size(uintptr_t);
-extern used_space_ival_t *used_space_first(used_space_t *);
-extern used_space_ival_t *used_space_next(used_space_ival_t *);
-extern used_space_ival_t *used_space_find_gteq(used_space_t *, uintptr_t);
-extern bool used_space_insert(used_space_t *, uintptr_t, size_t);
+extern bool used_space_insert(as_area_t *, uintptr_t, size_t);
+extern bool used_space_remove(as_area_t *, uintptr_t, size_t);
 
 /* Interface to be implemented by architectures. */
Index: kernel/generic/src/adt/btree.c
===================================================================
--- kernel/generic/src/adt/btree.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
+++ kernel/generic/src/adt/btree.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup kernel_generic_adt
+ * @{
+ */
+
+/**
+ * @file
+ * @brief B+tree implementation.
+ *
+ * This file implements B+tree type and operations.
+ *
+ * The B+tree has the following properties:
+ * @li it is a balanced 3-4-5 tree (i.e. BTREE_M = 5)
+ * @li values (i.e. pointers to values) are stored only in leaves
+ * @li leaves are linked in a list
+ *
+ * Be careful when using these trees. They need to allocate
+ * and deallocate memory for their index nodes and as such
+ * can sleep.
+ */
+
+#include <adt/btree.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <mm/slab.h>
+#include <panic.h>
+#include <stdio.h>
+#include <trace.h>
+
+static slab_cache_t *btree_node_cache;
+
+#define ROOT_NODE(n)   (!(n)->parent)
+#define INDEX_NODE(n)  ((n)->subtree[0] != NULL)
+#define LEAF_NODE(n)   ((n)->subtree[0] == NULL)
+
+#define FILL_FACTOR  ((BTREE_M - 1) / 2)
+
+#define MEDIAN_LOW_INDEX(n)   (((n)->keys-1) / 2)
+#define MEDIAN_HIGH_INDEX(n)  ((n)->keys / 2)
+#define MEDIAN_LOW(n)         ((n)->key[MEDIAN_LOW_INDEX((n))]);
+#define MEDIAN_HIGH(n)        ((n)->key[MEDIAN_HIGH_INDEX((n))]);
+
+/** Initialize B-trees. */
+void btree_init(void)
+{
+	btree_node_cache = slab_cache_create("btree_node_t",
+	    sizeof(btree_node_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED);
+}
+
+/** Initialize B-tree node.
+ *
+ * @param node B-tree node.
+ *
+ */
+NO_TRACE static void node_initialize(btree_node_t *node)
+{
+	unsigned int i;
+
+	node->keys = 0;
+
+	/* Clean also space for the extra key. */
+	for (i = 0; i < BTREE_MAX_KEYS + 1; i++) {
+		node->key[i] = 0;
+		node->value[i] = NULL;
+		node->subtree[i] = NULL;
+	}
+
+	node->subtree[i] = NULL;
+	node->parent = NULL;
+
+	link_initialize(&node->leaf_link);
+	link_initialize(&node->bfs_link);
+	node->depth = 0;
+}
+
+/** Create empty B-tree.
+ *
+ * @param t B-tree.
+ *
+ */
+void btree_create(btree_t *t)
+{
+	list_initialize(&t->leaf_list);
+	t->root = (btree_node_t *) slab_alloc(btree_node_cache, 0);
+	node_initialize(t->root);
+	list_append(&t->root->leaf_link, &t->leaf_list);
+}
+
+/** Destroy subtree rooted in a node.
+ *
+ * @param root Root of the subtree.
+ *
+ */
+NO_TRACE static void btree_destroy_subtree(btree_node_t *root)
+{
+	size_t i;
+
+	if (root->keys) {
+		for (i = 0; i < root->keys + 1; i++) {
+			if (root->subtree[i])
+				btree_destroy_subtree(root->subtree[i]);
+		}
+	}
+
+	slab_free(btree_node_cache, root);
+}
+
+/** Destroy empty B-tree. */
+void btree_destroy(btree_t *t)
+{
+	btree_destroy_subtree(t->root);
+}
+
+/** Insert key-value-rsubtree triplet into B-tree node.
+ *
+ * It is actually possible to have more keys than BTREE_MAX_KEYS.
+ * This feature is used during splitting the node when the
+ * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation
+ * also makes use of this feature.
+ *
+ * @param node     B-tree node into which the new key is to be inserted.
+ * @param key      The key to be inserted.
+ * @param value    Pointer to value to be inserted.
+ * @param rsubtree Pointer to the right subtree.
+ *
+ */
+NO_TRACE static void node_insert_key_and_rsubtree(btree_node_t *node,
+    btree_key_t key, void *value, btree_node_t *rsubtree)
+{
+	size_t i;
+
+	for (i = 0; i < node->keys; i++) {
+		if (key < node->key[i]) {
+			size_t j;
+
+			for (j = node->keys; j > i; j--) {
+				node->key[j] = node->key[j - 1];
+				node->value[j] = node->value[j - 1];
+				node->subtree[j + 1] = node->subtree[j];
+			}
+
+			break;
+		}
+	}
+
+	node->key[i] = key;
+	node->value[i] = value;
+	node->subtree[i + 1] = rsubtree;
+	node->keys++;
+}
+
+/** Find key by its left or right subtree.
+ *
+ * @param node    B-tree node.
+ * @param subtree Left or right subtree of a key found in node.
+ * @param right   If true, subtree is a right subtree. If false,
+ *                subtree is a left subtree.
+ *
+ * @return Index of the key associated with the subtree.
+ *
+ */
+NO_TRACE static size_t find_key_by_subtree(btree_node_t *node,
+    btree_node_t *subtree, bool right)
+{
+	size_t i;
+
+	for (i = 0; i < node->keys + 1; i++) {
+		if (subtree == node->subtree[i])
+			return i - (int) (right != false);
+	}
+
+	panic("Node %p does not contain subtree %p.", node, subtree);
+}
+
+/** Remove key and its left subtree pointer from B-tree node.
+ *
+ * Remove the key and eliminate gaps in node->key array.
+ * Note that the value pointer and the left subtree pointer
+ * is removed from the node as well.
+ *
+ * @param node B-tree node.
+ * @param key  Key to be removed.
+ *
+ */
+NO_TRACE static void node_remove_key_and_lsubtree(btree_node_t *node,
+    btree_key_t key)
+{
+	size_t i;
+	size_t j;
+
+	for (i = 0; i < node->keys; i++) {
+		if (key == node->key[i]) {
+			for (j = i + 1; j < node->keys; j++) {
+				node->key[j - 1] = node->key[j];
+				node->value[j - 1] = node->value[j];
+				node->subtree[j - 1] = node->subtree[j];
+			}
+
+			node->subtree[j - 1] = node->subtree[j];
+			node->keys--;
+
+			return;
+		}
+	}
+
+	panic("Node %p does not contain key %" PRIu64 ".", node, key);
+}
+
+/** Remove key and its right subtree pointer from B-tree node.
+ *
+ * Remove the key and eliminate gaps in node->key array.
+ * Note that the value pointer and the right subtree pointer
+ * is removed from the node as well.
+ *
+ * @param node B-tree node.
+ * @param key  Key to be removed.
+ *
+ */
+NO_TRACE static void node_remove_key_and_rsubtree(btree_node_t *node,
+    btree_key_t key)
+{
+	size_t i, j;
+
+	for (i = 0; i < node->keys; i++) {
+		if (key == node->key[i]) {
+			for (j = i + 1; j < node->keys; j++) {
+				node->key[j - 1] = node->key[j];
+				node->value[j - 1] = node->value[j];
+				node->subtree[j] = node->subtree[j + 1];
+			}
+
+			node->keys--;
+			return;
+		}
+	}
+
+	panic("Node %p does not contain key %" PRIu64 ".", node, key);
+}
+
+/** Insert key-value-lsubtree triplet into B-tree node.
+ *
+ * It is actually possible to have more keys than BTREE_MAX_KEYS.
+ * This feature is used during insert by right rotation.
+ *
+ * @param node     B-tree node into which the new key is to be inserted.
+ * @param key      The key to be inserted.
+ * @param value    Pointer to value to be inserted.
+ * @param lsubtree Pointer to the left subtree.
+ *
+ */
+NO_TRACE static void node_insert_key_and_lsubtree(btree_node_t *node,
+    btree_key_t key, void *value, btree_node_t *lsubtree)
+{
+	size_t i;
+
+	for (i = 0; i < node->keys; i++) {
+		if (key < node->key[i]) {
+			size_t j;
+
+			for (j = node->keys; j > i; j--) {
+				node->key[j] = node->key[j - 1];
+				node->value[j] = node->value[j - 1];
+				node->subtree[j + 1] = node->subtree[j];
+			}
+
+			node->subtree[j + 1] = node->subtree[j];
+			break;
+		}
+	}
+
+	node->key[i] = key;
+	node->value[i] = value;
+	node->subtree[i] = lsubtree;
+
+	node->keys++;
+}
+
+/** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling.
+ *
+ * The biggest key and its value and right subtree is rotated
+ * from the left node to the right. If the node is an index node,
+ * than the parent node key belonging to the left node takes part
+ * in the rotation.
+ *
+ * @param lnode Left sibling.
+ * @param rnode Right sibling.
+ * @param idx   Index of the parent node key that is taking part
+ *              in the rotation.
+ *
+ */
+NO_TRACE static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode,
+    size_t idx)
+{
+	btree_key_t key = lnode->key[lnode->keys - 1];
+
+	if (LEAF_NODE(lnode)) {
+		void *value = lnode->value[lnode->keys - 1];
+
+		node_remove_key_and_rsubtree(lnode, key);
+		node_insert_key_and_lsubtree(rnode, key, value, NULL);
+		lnode->parent->key[idx] = key;
+	} else {
+		btree_node_t *rsubtree = lnode->subtree[lnode->keys];
+
+		node_remove_key_and_rsubtree(lnode, key);
+		node_insert_key_and_lsubtree(rnode, lnode->parent->key[idx], NULL, rsubtree);
+		lnode->parent->key[idx] = key;
+
+		/* Fix parent link of the reconnected right subtree. */
+		rsubtree->parent = rnode;
+	}
+}
+
+/** Rotate one key-value-lsubtree triplet from the right sibling to the left sibling.
+ *
+ * The smallest key and its value and left subtree is rotated
+ * from the right node to the left. If the node is an index node,
+ * than the parent node key belonging to the right node takes part
+ * in the rotation.
+ *
+ * @param lnode Left sibling.
+ * @param rnode Right sibling.
+ * @param idx   Index of the parent node key that is taking part
+ *              in the rotation.
+ *
+ */
+NO_TRACE static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode,
+    size_t idx)
+{
+	btree_key_t key = rnode->key[0];
+
+	if (LEAF_NODE(rnode)) {
+		void *value = rnode->value[0];
+
+		node_remove_key_and_lsubtree(rnode, key);
+		node_insert_key_and_rsubtree(lnode, key, value, NULL);
+		rnode->parent->key[idx] = rnode->key[0];
+	} else {
+		btree_node_t *lsubtree = rnode->subtree[0];
+
+		node_remove_key_and_lsubtree(rnode, key);
+		node_insert_key_and_rsubtree(lnode, rnode->parent->key[idx], NULL, lsubtree);
+		rnode->parent->key[idx] = key;
+
+		/* Fix parent link of the reconnected left subtree. */
+		lsubtree->parent = lnode;
+	}
+}
+
+/** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done.
+ *
+ * Left sibling of the node (if it exists) is checked for free space.
+ * If there is free space, the key is inserted and the smallest key of
+ * the node is moved there. The index node which is the parent of both
+ * nodes is fixed.
+ *
+ * @param node     B-tree node.
+ * @param inskey   Key to be inserted.
+ * @param insvalue Value to be inserted.
+ * @param rsubtree Right subtree of inskey.
+ *
+ * @return True if the rotation was performed, false otherwise.
+ *
+ */
+NO_TRACE static bool try_insert_by_rotation_to_left(btree_node_t *node,
+    btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
+{
+	size_t idx;
+	btree_node_t *lnode;
+
+	/*
+	 * If this is root node, the rotation can not be done.
+	 */
+	if (ROOT_NODE(node))
+		return false;
+
+	idx = find_key_by_subtree(node->parent, node, true);
+	if ((int) idx == -1) {
+		/*
+		 * If this node is the leftmost subtree of its parent,
+		 * the rotation can not be done.
+		 */
+		return false;
+	}
+
+	lnode = node->parent->subtree[idx];
+	if (lnode->keys < BTREE_MAX_KEYS) {
+		/*
+		 * The rotaion can be done. The left sibling has free space.
+		 */
+		node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
+		rotate_from_right(lnode, node, idx);
+		return true;
+	}
+
+	return false;
+}
+
+/** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done.
+ *
+ * Right sibling of the node (if it exists) is checked for free space.
+ * If there is free space, the key is inserted and the biggest key of
+ * the node is moved there. The index node which is the parent of both
+ * nodes is fixed.
+ *
+ * @param node     B-tree node.
+ * @param inskey   Key to be inserted.
+ * @param insvalue Value to be inserted.
+ * @param rsubtree Right subtree of inskey.
+ *
+ * @return True if the rotation was performed, false otherwise.
+ *
+ */
+NO_TRACE static bool try_insert_by_rotation_to_right(btree_node_t *node,
+    btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
+{
+	size_t idx;
+	btree_node_t *rnode;
+
+	/*
+	 * If this is root node, the rotation can not be done.
+	 */
+	if (ROOT_NODE(node))
+		return false;
+
+	idx = find_key_by_subtree(node->parent, node, false);
+	if (idx == node->parent->keys) {
+		/*
+		 * If this node is the rightmost subtree of its parent,
+		 * the rotation can not be done.
+		 */
+		return false;
+	}
+
+	rnode = node->parent->subtree[idx + 1];
+	if (rnode->keys < BTREE_MAX_KEYS) {
+		/*
+		 * The rotation can be done. The right sibling has free space.
+		 */
+		node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
+		rotate_from_left(node, rnode, idx);
+		return true;
+	}
+
+	return false;
+}
+
+/** Split full B-tree node and insert new key-value-right-subtree triplet.
+ *
+ * This function will split a node and return a pointer to a newly created
+ * node containing keys greater than or equal to the greater of medians
+ * (or median) of the old keys and the newly added key. It will also write
+ * the median key to a memory address supplied by the caller.
+ *
+ * If the node being split is an index node, the median will not be
+ * included in the new node. If the node is a leaf node,
+ * the median will be copied there.
+ *
+ * @param node     B-tree node which is going to be split.
+ * @param key      The key to be inserted.
+ * @param value    Pointer to the value to be inserted.
+ * @param rsubtree Pointer to the right subtree of the key being added.
+ * @param median   Address in memory, where the median key will be stored.
+ *
+ * @return Newly created right sibling of node.
+ *
+ */
+NO_TRACE static btree_node_t *node_split(btree_node_t *node, btree_key_t key,
+    void *value, btree_node_t *rsubtree, btree_key_t *median)
+{
+	btree_node_t *rnode;
+	size_t i;
+	size_t j;
+
+	assert(median);
+	assert(node->keys == BTREE_MAX_KEYS);
+
+	/*
+	 * Use the extra space to store the extra node.
+	 */
+	node_insert_key_and_rsubtree(node, key, value, rsubtree);
+
+	/*
+	 * Compute median of keys.
+	 */
+	*median = MEDIAN_HIGH(node);
+
+	/*
+	 * Allocate and initialize new right sibling.
+	 */
+	rnode = (btree_node_t *) slab_alloc(btree_node_cache, 0);
+	node_initialize(rnode);
+	rnode->parent = node->parent;
+	rnode->depth = node->depth;
+
+	/*
+	 * Copy big keys, values and subtree pointers to the new right sibling.
+	 * If this is an index node, do not copy the median.
+	 */
+	i = (size_t) INDEX_NODE(node);
+	for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) {
+		rnode->key[j] = node->key[i];
+		rnode->value[j] = node->value[i];
+		rnode->subtree[j] = node->subtree[i];
+
+		/*
+		 * Fix parent links in subtrees.
+		 */
+		if (rnode->subtree[j])
+			rnode->subtree[j]->parent = rnode;
+	}
+
+	rnode->subtree[j] = node->subtree[i];
+	if (rnode->subtree[j])
+		rnode->subtree[j]->parent = rnode;
+
+	rnode->keys = j;  /* Set number of keys of the new node. */
+	node->keys /= 2;  /* Shrink the old node. */
+
+	return rnode;
+}
+
+/** Recursively insert into B-tree.
+ *
+ * @param t        B-tree.
+ * @param key      Key to be inserted.
+ * @param value    Value to be inserted.
+ * @param rsubtree Right subtree of the inserted key.
+ * @param node     Start inserting into this node.
+ *
+ */
+NO_TRACE static void _btree_insert(btree_t *t, btree_key_t key, void *value,
+    btree_node_t *rsubtree, btree_node_t *node)
+{
+	if (node->keys < BTREE_MAX_KEYS) {
+		/*
+		 * Node contains enough space, the key can be stored immediately.
+		 */
+		node_insert_key_and_rsubtree(node, key, value, rsubtree);
+	} else if (try_insert_by_rotation_to_left(node, key, value, rsubtree)) {
+		/*
+		 * The key-value-rsubtree triplet has been inserted because
+		 * some keys could have been moved to the left sibling.
+		 */
+	} else if (try_insert_by_rotation_to_right(node, key, value, rsubtree)) {
+		/*
+		 * The key-value-rsubtree triplet has been inserted because
+		 * some keys could have been moved to the right sibling.
+		 */
+	} else {
+		btree_node_t *rnode;
+		btree_key_t median;
+
+		/*
+		 * Node is full and both siblings (if both exist) are full too.
+		 * Split the node and insert the smallest key from the node containing
+		 * bigger keys (i.e. the new node) into its parent.
+		 */
+
+		rnode = node_split(node, key, value, rsubtree, &median);
+
+		if (LEAF_NODE(node)) {
+			list_insert_after(&rnode->leaf_link, &node->leaf_link);
+		}
+
+		if (ROOT_NODE(node)) {
+			/*
+			 * We split the root node. Create new root.
+			 */
+			t->root = (btree_node_t *) slab_alloc(btree_node_cache, 0);
+			node->parent = t->root;
+			rnode->parent = t->root;
+			node_initialize(t->root);
+
+			/*
+			 * Left-hand side subtree will be the old root (i.e. node).
+			 * Right-hand side subtree will be rnode.
+			 */
+			t->root->subtree[0] = node;
+
+			t->root->depth = node->depth + 1;
+		}
+		_btree_insert(t, median, NULL, rnode, node->parent);
+	}
+}
+
+/** Insert key-value pair into B-tree.
+ *
+ * @param t         B-tree.
+ * @param key       Key to be inserted.
+ * @param value     Value to be inserted.
+ * @param leaf_node Leaf node where the insertion should begin.
+ *
+ */
+void btree_insert(btree_t *t, btree_key_t key, void *value,
+    btree_node_t *leaf_node)
+{
+	btree_node_t *lnode;
+
+	assert(value);
+
+	lnode = leaf_node;
+	if (!lnode) {
+		if (btree_search(t, key, &lnode))
+			panic("B-tree %p already contains key %" PRIu64 ".", t, key);
+	}
+
+	_btree_insert(t, key, value, NULL, lnode);
+}
+
+/** Rotate in a key from the left sibling or from the index node, if this operation can be done.
+ *
+ * @param rnode Node into which to add key from its left sibling
+ *              or from the index node.
+ *
+ * @return True if the rotation was performed, false otherwise.
+ *
+ */
+NO_TRACE static bool try_rotation_from_left(btree_node_t *rnode)
+{
+	size_t idx;
+	btree_node_t *lnode;
+
+	/*
+	 * If this is root node, the rotation can not be done.
+	 */
+	if (ROOT_NODE(rnode))
+		return false;
+
+	idx = find_key_by_subtree(rnode->parent, rnode, true);
+	if ((int) idx == -1) {
+		/*
+		 * If this node is the leftmost subtree of its parent,
+		 * the rotation can not be done.
+		 */
+		return false;
+	}
+
+	lnode = rnode->parent->subtree[idx];
+	if (lnode->keys > FILL_FACTOR) {
+		rotate_from_left(lnode, rnode, idx);
+		return true;
+	}
+
+	return false;
+}
+
+/** Rotate in a key from the right sibling or from the index node, if this operation can be done.
+ *
+ * @param lnode Node into which to add key from its right sibling
+ *              or from the index node.
+ *
+ * @return True if the rotation was performed, false otherwise.
+ *
+ */
+NO_TRACE static bool try_rotation_from_right(btree_node_t *lnode)
+{
+	size_t idx;
+	btree_node_t *rnode;
+
+	/*
+	 * If this is root node, the rotation can not be done.
+	 */
+	if (ROOT_NODE(lnode))
+		return false;
+
+	idx = find_key_by_subtree(lnode->parent, lnode, false);
+	if (idx == lnode->parent->keys) {
+		/*
+		 * If this node is the rightmost subtree of its parent,
+		 * the rotation can not be done.
+		 */
+		return false;
+	}
+
+	rnode = lnode->parent->subtree[idx + 1];
+	if (rnode->keys > FILL_FACTOR) {
+		rotate_from_right(lnode, rnode, idx);
+		return true;
+	}
+
+	return false;
+}
+
+/** Combine node with any of its siblings.
+ *
+ * The siblings are required to be below the fill factor.
+ *
+ * @param node Node to combine with one of its siblings.
+ *
+ * @return Pointer to the rightmost of the two nodes.
+ *
+ */
+NO_TRACE static btree_node_t *node_combine(btree_node_t *node)
+{
+	size_t idx;
+	btree_node_t *rnode;
+	size_t i;
+
+	assert(!ROOT_NODE(node));
+
+	idx = find_key_by_subtree(node->parent, node, false);
+	if (idx == node->parent->keys) {
+		/*
+		 * Rightmost subtree of its parent, combine with the left sibling.
+		 */
+		idx--;
+		rnode = node;
+		node = node->parent->subtree[idx];
+	} else
+		rnode = node->parent->subtree[idx + 1];
+
+	/* Index nodes need to insert parent node key in between left and right node. */
+	if (INDEX_NODE(node))
+		node->key[node->keys++] = node->parent->key[idx];
+
+	/* Copy the key-value-subtree triplets from the right node. */
+	for (i = 0; i < rnode->keys; i++) {
+		node->key[node->keys + i] = rnode->key[i];
+		node->value[node->keys + i] = rnode->value[i];
+
+		if (INDEX_NODE(node)) {
+			node->subtree[node->keys + i] = rnode->subtree[i];
+			rnode->subtree[i]->parent = node;
+		}
+	}
+
+	if (INDEX_NODE(node)) {
+		node->subtree[node->keys + i] = rnode->subtree[i];
+		rnode->subtree[i]->parent = node;
+	}
+
+	node->keys += rnode->keys;
+	return rnode;
+}
+
+/** Recursively remove B-tree node.
+ *
+ * @param t    B-tree.
+ * @param key  Key to be removed from the B-tree along with its associated value.
+ * @param node Node where the key being removed resides.
+ *
+ */
+NO_TRACE static void _btree_remove(btree_t *t, btree_key_t key,
+    btree_node_t *node)
+{
+	if (ROOT_NODE(node)) {
+		if ((node->keys == 1) && (node->subtree[0])) {
+			/*
+			 * Free the current root and set new root.
+			 */
+			t->root = node->subtree[0];
+			t->root->parent = NULL;
+			slab_free(btree_node_cache, node);
+		} else {
+			/*
+			 * Remove the key from the root node.
+			 * Note that the right subtree is removed because when
+			 * combining two nodes, the left-side sibling is preserved
+			 * and the right-side sibling is freed.
+			 */
+			node_remove_key_and_rsubtree(node, key);
+		}
+
+		return;
+	}
+
+	if (node->keys <= FILL_FACTOR) {
+		/*
+		 * If the node is below the fill factor,
+		 * try to borrow keys from left or right sibling.
+		 */
+		if (!try_rotation_from_left(node))
+			try_rotation_from_right(node);
+	}
+
+	if (node->keys > FILL_FACTOR) {
+		size_t i;
+
+		/*
+		 * The key can be immediately removed.
+		 *
+		 * Note that the right subtree is removed because when
+		 * combining two nodes, the left-side sibling is preserved
+		 * and the right-side sibling is freed.
+		 */
+		node_remove_key_and_rsubtree(node, key);
+
+		for (i = 0; i < node->parent->keys; i++) {
+			if (node->parent->key[i] == key)
+				node->parent->key[i] = node->key[0];
+		}
+	} else {
+		size_t idx;
+		btree_node_t *rnode;
+		btree_node_t *parent;
+
+		/*
+		 * The node is below the fill factor as well as its left and right sibling.
+		 * Resort to combining the node with one of its siblings.
+		 * The node which is on the left is preserved and the node on the right is
+		 * freed.
+		 */
+		parent = node->parent;
+		node_remove_key_and_rsubtree(node, key);
+		rnode = node_combine(node);
+
+		if (LEAF_NODE(rnode))
+			list_remove(&rnode->leaf_link);
+
+		idx = find_key_by_subtree(parent, rnode, true);
+		assert((int) idx != -1);
+		slab_free(btree_node_cache, rnode);
+		_btree_remove(t, parent->key[idx], parent);
+	}
+}
+
+/** Remove B-tree node.
+ *
+ * @param t         B-tree.
+ * @param key       Key to be removed from the B-tree along
+ *                  with its associated value.
+ * @param leaf_node If not NULL, pointer to the leaf node where
+ *                  the key is found.
+ *
+ */
+void btree_remove(btree_t *t, btree_key_t key, btree_node_t *leaf_node)
+{
+	btree_node_t *lnode;
+
+	lnode = leaf_node;
+	if (!lnode) {
+		if (!btree_search(t, key, &lnode))
+			panic("B-tree %p does not contain key %" PRIu64 ".", t, key);
+	}
+
+	_btree_remove(t, key, lnode);
+}
+
+/** Search key in a B-tree.
+ *
+ * @param t         B-tree.
+ * @param key       Key to be searched.
+ * @param leaf_node Address where to put pointer to visited leaf node.
+ *
+ * @return Pointer to value or NULL if there is no such key.
+ *
+ */
+void *btree_search(btree_t *t, btree_key_t key, btree_node_t **leaf_node)
+{
+	btree_node_t *cur, *next;
+	bool descend;
+
+	/*
+	 * Iteratively descend to the leaf that can contain the searched key.
+	 */
+	for (cur = t->root; cur; cur = next) {
+		/*
+		 * Last iteration will set this with proper
+		 * leaf node address.
+		 */
+		*leaf_node = cur;
+
+		if (cur->keys == 0)
+			return NULL;
+
+		/*
+		 * The key can be in the leftmost subtree.
+		 * Test it separately.
+		 */
+		if (key < cur->key[0]) {
+			next = cur->subtree[0];
+			continue;
+		} else {
+			void *val;
+			size_t i;
+
+			/*
+			 * Now if the key is smaller than cur->key[i]
+			 * it can only mean that the value is in cur->subtree[i]
+			 * or it is not in the tree at all.
+			 */
+			descend = false;
+			for (i = 1; i < cur->keys; i++) {
+				if (key < cur->key[i]) {
+					next = cur->subtree[i];
+					val = cur->value[i - 1];
+
+					if (LEAF_NODE(cur))
+						return key == cur->key[i - 1] ? val : NULL;
+
+					descend = true;
+					break;
+				}
+			}
+
+			if (descend)
+				continue;
+
+			/*
+			 * Last possibility is that the key is
+			 * in the rightmost subtree.
+			 */
+			next = cur->subtree[i];
+			val = cur->value[i - 1];
+
+			if (LEAF_NODE(cur))
+				return key == cur->key[i - 1] ? val : NULL;
+		}
+	}
+
+	/*
+	 * The key was not found in the *leaf_node and
+	 * is smaller than any of its keys.
+	 */
+	return NULL;
+}
+
+/** Return pointer to B-tree leaf node's left neighbour.
+ *
+ * @param t    B-tree.
+ * @param node Node whose left neighbour will be returned.
+ *
+ * @return Left neighbour of the node or NULL if the node
+ *         does not have the left neighbour.
+ *
+ */
+btree_node_t *btree_leaf_node_left_neighbour(btree_t *t, btree_node_t *node)
+{
+	assert(LEAF_NODE(node));
+
+	if (node->leaf_link.prev != &t->leaf_list.head)
+		return list_get_instance(node->leaf_link.prev, btree_node_t, leaf_link);
+	else
+		return NULL;
+}
+
+/** Return pointer to B-tree leaf node's right neighbour.
+ *
+ * @param t    B-tree.
+ * @param node Node whose right neighbour will be returned.
+ *
+ * @return Right neighbour of the node or NULL if the node
+ *         does not have the right neighbour.
+ *
+ */
+btree_node_t *btree_leaf_node_right_neighbour(btree_t *t, btree_node_t *node)
+{
+	assert(LEAF_NODE(node));
+
+	if (node->leaf_link.next != &t->leaf_list.head)
+		return list_get_instance(node->leaf_link.next, btree_node_t, leaf_link);
+	else
+		return NULL;
+}
+
+/** Print B-tree.
+ *
+ * @param t Print out B-tree.
+ *
+ */
+void btree_print(btree_t *t)
+{
+	size_t i;
+	int depth = t->root->depth;
+	list_t list;
+
+	printf("Printing B-tree:\n");
+	list_initialize(&list);
+	list_append(&t->root->bfs_link, &list);
+
+	/*
+	 * Use BFS search to print out the tree.
+	 * Levels are distinguished from one another by node->depth.
+	 */
+	while (!list_empty(&list)) {
+		link_t *hlp;
+		btree_node_t *node;
+
+		hlp = list_first(&list);
+		assert(hlp != NULL);
+		node = list_get_instance(hlp, btree_node_t, bfs_link);
+		list_remove(hlp);
+
+		assert(node);
+
+		if (node->depth != depth) {
+			printf("\n");
+			depth = node->depth;
+		}
+
+		printf("(");
+
+		for (i = 0; i < node->keys; i++) {
+			printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
+			if (node->depth && node->subtree[i]) {
+				list_append(&node->subtree[i]->bfs_link, &list);
+			}
+		}
+
+		if (node->depth && node->subtree[i])
+			list_append(&node->subtree[i]->bfs_link, &list);
+
+		printf(")");
+	}
+
+	printf("\n");
+
+	printf("Printing list of leaves:\n");
+	list_foreach(t->leaf_list, leaf_link, btree_node_t, node) {
+		assert(node);
+
+		printf("(");
+
+		for (i = 0; i < node->keys; i++)
+			printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
+
+		printf(")");
+	}
+
+	printf("\n");
+}
+
+/** Return number of B-tree elements.
+ *
+ * @param t B-tree to count.
+ *
+ * @return Return number of B-tree elements.
+ *
+ */
+unsigned long btree_count(btree_t *t)
+{
+	unsigned long count = 0;
+
+	list_foreach(t->leaf_list, leaf_link, btree_node_t, node) {
+		count += node->keys;
+	}
+
+	return count;
+}
+
+/** @}
+ */
Index: kernel/generic/src/main/main.c
===================================================================
--- kernel/generic/src/main/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/main/main.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -83,4 +83,5 @@
 #include <ipc/ipc.h>
 #include <macros.h>
+#include <adt/btree.h>
 #include <smp/smp.h>
 #include <ddi/ddi.h>
@@ -248,4 +249,5 @@
 	ra_init();
 	sysinfo_init();
+	btree_init();
 	as_init();
 	page_init();
Index: kernel/generic/src/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/mm/as.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -63,4 +63,5 @@
 #include <synch/mutex.h>
 #include <adt/list.h>
+#include <adt/btree.h>
 #include <proc/task.h>
 #include <proc/thread.h>
@@ -88,12 +89,8 @@
 as_operations_t *as_operations = NULL;
 
-/** Cache for as_t objects */
+/** Slab for as_t objects.
+ *
+ */
 static slab_cache_t *as_cache;
-
-/** Cache for as_page_mapping_t objects */
-static slab_cache_t *as_page_mapping_cache;
-
-/** Cache for used_space_ival_t objects */
-static slab_cache_t *used_space_ival_cache;
 
 /** ASID subsystem lock.
@@ -119,12 +116,4 @@
 static int as_areas_cmp(void *, void *);
 
-static void used_space_initialize(used_space_t *);
-static void used_space_finalize(used_space_t *);
-static void *used_space_getkey(odlink_t *);
-static int used_space_cmp(void *, void *);
-static used_space_ival_t *used_space_last(used_space_t *);
-static void used_space_remove_ival(used_space_ival_t *);
-static void used_space_shorten_ival(used_space_ival_t *, size_t);
-
 NO_TRACE static errno_t as_constructor(void *obj, unsigned int flags)
 {
@@ -149,10 +138,4 @@
 	as_cache = slab_cache_create("as_t", sizeof(as_t), 0,
 	    as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
-
-	as_page_mapping_cache = slab_cache_create("as_page_mapping_t",
-	    sizeof(as_page_mapping_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED);
-
-	used_space_ival_cache = slab_cache_create("used_space_ival_t",
-	    sizeof(used_space_ival_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED);
 
 	AS_KERNEL = as_create(FLAG_AS_KERNEL);
@@ -541,149 +524,4 @@
 }
 
-/** Get key function for pagemap ordered dictionary.
- *
- * The key is the virtual address of the page (as_page_mapping_t.vaddr)
- *
- * @param odlink Link to as_pagemap_t.map ordered dictionary
- * @return Pointer to virtual address cast as @c void *
- */
-static void *as_pagemap_getkey(odlink_t *odlink)
-{
-	as_page_mapping_t *mapping;
-
-	mapping = odict_get_instance(odlink, as_page_mapping_t, lpagemap);
-	return (void *) &mapping->vaddr;
-}
-
-/** Comparison function for pagemap ordered dictionary.
- *
- * @param a Pointer to virtual address cast as @c void *
- * @param b Pointer to virtual address cast as @c void *
- * @return <0, =0, >0 if virtual address a is less than, equal to, or
- *         greater than b, respectively.
- */
-static int as_pagemap_cmp(void *a, void *b)
-{
-	uintptr_t va = *(uintptr_t *)a;
-	uintptr_t vb = *(uintptr_t *)b;
-
-	if (va < vb)
-		return -1;
-	else if (va == vb)
-		return 0;
-	else
-		return +1;
-}
-
-/** Initialize pagemap.
- *
- * @param pagemap Pagemap
- */
-NO_TRACE void as_pagemap_initialize(as_pagemap_t *pagemap)
-{
-	odict_initialize(&pagemap->map, as_pagemap_getkey, as_pagemap_cmp);
-}
-
-/** Finalize pagemap.
- *
- * Destroy any entries in the pagemap.
- *
- * @param pagemap Pagemap
- */
-NO_TRACE void as_pagemap_finalize(as_pagemap_t *pagemap)
-{
-	as_page_mapping_t *mapping = as_pagemap_first(pagemap);
-	while (mapping != NULL) {
-		as_pagemap_remove(mapping);
-		mapping = as_pagemap_first(pagemap);
-	}
-	odict_finalize(&pagemap->map);
-}
-
-/** Get first page mapping.
- *
- * @param pagemap Pagemap
- * @return First mapping or @c NULL if there is none
- */
-NO_TRACE as_page_mapping_t *as_pagemap_first(as_pagemap_t *pagemap)
-{
-	odlink_t *odlink;
-
-	odlink = odict_first(&pagemap->map);
-	if (odlink == NULL)
-		return NULL;
-
-	return odict_get_instance(odlink, as_page_mapping_t, lpagemap);
-}
-
-/** Get next page mapping.
- *
- * @param cur Current mapping
- * @return Next mapping or @c NULL if @a cur is the last one
- */
-NO_TRACE as_page_mapping_t *as_pagemap_next(as_page_mapping_t *cur)
-{
-	odlink_t *odlink;
-
-	odlink = odict_next(&cur->lpagemap, &cur->pagemap->map);
-	if (odlink == NULL)
-		return NULL;
-
-	return odict_get_instance(odlink, as_page_mapping_t, lpagemap);
-}
-
-/** Find frame by virtual address.
- *
- * @param pagemap Pagemap
- * @param vaddr Virtual address of page
- * @param rframe Place to store physical frame address
- * @return EOK on succcess or ENOENT if no mapping found
- */
-NO_TRACE errno_t as_pagemap_find(as_pagemap_t *pagemap, uintptr_t vaddr,
-    uintptr_t *rframe)
-{
-	odlink_t *odlink;
-	as_page_mapping_t *mapping;
-
-	odlink = odict_find_eq(&pagemap->map, &vaddr, NULL);
-	if (odlink == NULL)
-		return ENOENT;
-
-	mapping = odict_get_instance(odlink, as_page_mapping_t, lpagemap);
-	*rframe = mapping->frame;
-	return EOK;
-}
-
-/** Insert new page mapping.
- *
- * This function can block to allocate kernel memory.
- *
- * @param pagemap Pagemap
- * @param vaddr Virtual page address
- * @param frame Physical frame address
- */
-NO_TRACE void as_pagemap_insert(as_pagemap_t *pagemap, uintptr_t vaddr,
-    uintptr_t frame)
-{
-	as_page_mapping_t *mapping;
-
-	mapping = slab_alloc(as_page_mapping_cache, 0);
-	mapping->pagemap = pagemap;
-	odlink_initialize(&mapping->lpagemap);
-	mapping->vaddr = vaddr;
-	mapping->frame = frame;
-	odict_insert(&mapping->lpagemap, &pagemap->map, NULL);
-}
-
-/** Remove page mapping.
- *
- * @param mapping Mapping
- */
-NO_TRACE void as_pagemap_remove(as_page_mapping_t *mapping)
-{
-	odict_remove(&mapping->lpagemap);
-	slab_free(as_page_mapping_cache, mapping);
-}
-
 /** Remove reference to address space area share info.
  *
@@ -703,8 +541,14 @@
 		dealloc = true;
 
-		as_page_mapping_t *mapping = as_pagemap_first(&sh_info->pagemap);
-		while (mapping != NULL) {
-			frame_free(mapping->frame, 1);
-			mapping = as_pagemap_next(mapping);
+		/*
+		 * 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);
 		}
 
@@ -717,5 +561,5 @@
 			    sh_info->backend_shared_data);
 		}
-		as_pagemap_finalize(&sh_info->pagemap);
+		btree_destroy(&sh_info->pagemap);
 		free(sh_info);
 	}
@@ -792,4 +636,5 @@
 	area->attributes = attrs;
 	area->pages = pages;
+	area->resident = 0;
 	area->base = *base;
 	area->backend = backend;
@@ -820,5 +665,5 @@
 		si->backend_shared_data = NULL;
 		si->backend = backend;
-		as_pagemap_initialize(&si->pagemap);
+		btree_create(&si->pagemap);
 
 		area->sh_info = si;
@@ -844,5 +689,5 @@
 	}
 
-	used_space_initialize(&area->used_space);
+	btree_create(&area->used_space);
 	odict_insert(&area->las_areas, &as->as_areas, NULL);
 
@@ -952,96 +797,111 @@
 
 		/*
-		 * Start TLB shootdown sequence.
-		 */
-
-		ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES,
-		    as->asid, area->base + P2SZ(pages),
-		    area->pages - pages);
-
-		/*
 		 * Remove frames belonging to used space starting from
 		 * the highest addresses downwards until an overlap with
-		 * the resized address space area is found.
+		 * the resized address space area is found. Note that this
+		 * is also the right way to remove part of the used_space
+		 * B+tree leaf list.
 		 */
 		bool cond = true;
 		while (cond) {
-			used_space_ival_t *ival =
-			    used_space_last(&area->used_space);
-			assert(ival != NULL);
-
-			uintptr_t ptr = ival->page;
-			size_t pcount = ival->count;
-			size_t i = 0;
-
-			if (overlaps(ptr, P2SZ(pcount), area->base,
-			    P2SZ(pages))) {
-
-				if (ptr + P2SZ(pcount) <= start_free) {
+			assert(!list_empty(&area->used_space.leaf_list));
+
+			btree_node_t *node =
+			    list_get_instance(list_last(&area->used_space.leaf_list),
+			    btree_node_t, leaf_link);
+
+			if ((cond = (node->keys != 0))) {
+				uintptr_t ptr = node->key[node->keys - 1];
+				size_t node_size =
+				    (size_t) node->value[node->keys - 1];
+				size_t i = 0;
+
+				if (overlaps(ptr, P2SZ(node_size), area->base,
+				    P2SZ(pages))) {
+
+					if (ptr + P2SZ(node_size) <= start_free) {
+						/*
+						 * The whole interval fits
+						 * completely in the resized
+						 * address space area.
+						 */
+						break;
+					}
+
 					/*
-					 * The whole interval fits completely
-					 * in the resized address space area.
+					 * Part of the interval corresponding
+					 * to b and c overlaps with the resized
+					 * address space area.
 					 */
-					break;
+
+					/* We are almost done */
+					cond = false;
+					i = (start_free - ptr) >> PAGE_WIDTH;
+					if (!used_space_remove(area, start_free,
+					    node_size - i))
+						panic("Cannot remove used space.");
+				} else {
+					/*
+					 * The interval of used space can be
+					 * completely removed.
+					 */
+					if (!used_space_remove(area, ptr, node_size))
+						panic("Cannot remove used space.");
 				}
 
 				/*
-				 * Part of the interval corresponding to b and
-				 * c overlaps with the resized address space
-				 * area.
+				 * Start TLB shootdown sequence.
+				 *
+				 * The sequence is rather short and can be
+				 * repeated multiple times. The reason is that
+				 * we don't want to have used_space_remove()
+				 * inside the sequence as it may use a blocking
+				 * memory allocation for its B+tree. Blocking
+				 * while holding the tlblock spinlock is
+				 * forbidden and would hit a kernel assertion.
 				 */
 
-				/* We are almost done */
-				cond = false;
-				i = (start_free - ptr) >> PAGE_WIDTH;
-
-				/* Shorten the interval to @c i pages */
-				used_space_shorten_ival(ival, i);
-			} else {
+				ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES,
+				    as->asid, area->base + P2SZ(pages),
+				    area->pages - pages);
+
+				for (; i < node_size; i++) {
+					pte_t pte;
+					bool found = page_mapping_find(as,
+					    ptr + P2SZ(i), false, &pte);
+
+					(void) found;
+					assert(found);
+					assert(PTE_VALID(&pte));
+					assert(PTE_PRESENT(&pte));
+
+					if ((area->backend) &&
+					    (area->backend->frame_free)) {
+						area->backend->frame_free(area,
+						    ptr + P2SZ(i),
+						    PTE_GET_FRAME(&pte));
+					}
+
+					page_mapping_remove(as, ptr + P2SZ(i));
+				}
+
 				/*
-				 * The interval of used space can be completely
-				 * removed.
+				 * Finish TLB shootdown sequence.
 				 */
-				used_space_remove_ival(ival);
+
+				tlb_invalidate_pages(as->asid,
+				    area->base + P2SZ(pages),
+				    area->pages - pages);
+
+				/*
+				 * Invalidate software translation caches
+				 * (e.g. TSB on sparc64, PHT on ppc32).
+				 */
+				as_invalidate_translation_cache(as,
+				    area->base + P2SZ(pages),
+				    area->pages - pages);
+				tlb_shootdown_finalize(ipl);
 			}
-
-			for (; i < pcount; i++) {
-				pte_t pte;
-				bool found = page_mapping_find(as,
-				    ptr + P2SZ(i), false, &pte);
-
-				(void) found;
-				assert(found);
-				assert(PTE_VALID(&pte));
-				assert(PTE_PRESENT(&pte));
-
-				if ((area->backend) &&
-				    (area->backend->frame_free)) {
-					area->backend->frame_free(area,
-					    ptr + P2SZ(i),
-					    PTE_GET_FRAME(&pte));
-				}
-
-				page_mapping_remove(as, ptr + P2SZ(i));
-			}
-
-		}
-
-		/*
-		 * Finish TLB shootdown sequence.
-		 */
-
-		tlb_invalidate_pages(as->asid,
-		    area->base + P2SZ(pages),
-		    area->pages - pages);
-
-		/*
-		 * Invalidate software translation caches
-		 * (e.g. TSB on sparc64, PHT on ppc32).
-		 */
-		as_invalidate_translation_cache(as,
-		    area->base + P2SZ(pages),
-		    area->pages - pages);
-		tlb_shootdown_finalize(ipl);
-
+		}
 		page_table_unlock(as, false);
 	} else {
@@ -1102,4 +962,5 @@
 
 	page_table_lock(as, false);
+
 	/*
 	 * Start TLB shootdown sequence.
@@ -1109,32 +970,34 @@
 
 	/*
-	 * Visit only the pages mapped by used_space.
-	 */
-	used_space_ival_t *ival = used_space_first(&area->used_space);
-	while (ival != NULL) {
-		uintptr_t ptr = ival->page;
-
-		for (size_t size = 0; size < ival->count; size++) {
-			pte_t pte;
-			bool found = page_mapping_find(as,
-			    ptr + P2SZ(size), false, &pte);
-
-			(void) found;
-			assert(found);
-			assert(PTE_VALID(&pte));
-			assert(PTE_PRESENT(&pte));
-
-			if ((area->backend) &&
-			    (area->backend->frame_free)) {
-				area->backend->frame_free(area,
-				    ptr + P2SZ(size),
-				    PTE_GET_FRAME(&pte));
+	 * Visit only the pages mapped by used_space B+tree.
+	 */
+	list_foreach(area->used_space.leaf_list, leaf_link, btree_node_t,
+	    node) {
+		btree_key_t i;
+
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t ptr = node->key[i];
+			size_t size;
+
+			for (size = 0; size < (size_t) node->value[i]; size++) {
+				pte_t pte;
+				bool found = page_mapping_find(as,
+				    ptr + P2SZ(size), false, &pte);
+
+				(void) found;
+				assert(found);
+				assert(PTE_VALID(&pte));
+				assert(PTE_PRESENT(&pte));
+
+				if ((area->backend) &&
+				    (area->backend->frame_free)) {
+					area->backend->frame_free(area,
+					    ptr + P2SZ(size),
+					    PTE_GET_FRAME(&pte));
+				}
+
+				page_mapping_remove(as, ptr + P2SZ(size));
 			}
-
-			page_mapping_remove(as, ptr + P2SZ(size));
-		}
-
-		used_space_remove_ival(ival);
-		ival = used_space_first(&area->used_space);
+		}
 	}
 
@@ -1154,6 +1017,8 @@
 	page_table_unlock(as, false);
 
-	used_space_finalize(&area->used_space);
+	btree_destroy(&area->used_space);
+
 	area->attributes |= AS_AREA_ATTR_PARTIAL;
+
 	sh_info_remove_reference(area->sh_info);
 
@@ -1391,7 +1256,19 @@
 	mutex_unlock(&area->sh_info->lock);
 
+	/*
+	 * Compute total number of used pages in the used_space B+tree
+	 */
+	size_t used_pages = 0;
+
+	list_foreach(area->used_space.leaf_list, leaf_link, btree_node_t,
+	    node) {
+		btree_key_t i;
+
+		for (i = 0; i < node->keys; i++)
+			used_pages += (size_t) node->value[i];
+	}
+
 	/* An array for storing frame numbers */
-	uintptr_t *old_frame = malloc(area->used_space.pages *
-	    sizeof(uintptr_t));
+	uintptr_t *old_frame = malloc(used_pages * sizeof(uintptr_t));
 	if (!old_frame) {
 		mutex_unlock(&area->lock);
@@ -1414,26 +1291,28 @@
 	size_t frame_idx = 0;
 
-	used_space_ival_t *ival = used_space_first(&area->used_space);
-	while (ival != NULL) {
-		uintptr_t ptr = ival->page;
-		size_t size;
-
-		for (size = 0; size < ival->count; size++) {
-			pte_t pte;
-			bool found = page_mapping_find(as, ptr + P2SZ(size),
-			    false, &pte);
-
-			(void) found;
-			assert(found);
-			assert(PTE_VALID(&pte));
-			assert(PTE_PRESENT(&pte));
-
-			old_frame[frame_idx++] = PTE_GET_FRAME(&pte);
-
-			/* Remove old mapping */
-			page_mapping_remove(as, ptr + P2SZ(size));
-		}
-
-		ival = used_space_next(ival);
+	list_foreach(area->used_space.leaf_list, leaf_link, btree_node_t,
+	    node) {
+		btree_key_t i;
+
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t ptr = node->key[i];
+			size_t size;
+
+			for (size = 0; size < (size_t) node->value[i]; size++) {
+				pte_t pte;
+				bool found = page_mapping_find(as,
+				    ptr + P2SZ(size), false, &pte);
+
+				(void) found;
+				assert(found);
+				assert(PTE_VALID(&pte));
+				assert(PTE_PRESENT(&pte));
+
+				old_frame[frame_idx++] = PTE_GET_FRAME(&pte);
+
+				/* Remove old mapping */
+				page_mapping_remove(as, ptr + P2SZ(size));
+			}
+		}
 	}
 
@@ -1465,20 +1344,22 @@
 	frame_idx = 0;
 
-	ival = used_space_first(&area->used_space);
-	while (ival != NULL) {
-		uintptr_t ptr = ival->page;
-		size_t size;
-
-		for (size = 0; size < ival->count; size++) {
-			page_table_lock(as, false);
-
-			/* Insert the new mapping */
-			page_mapping_insert(as, ptr + P2SZ(size),
-			    old_frame[frame_idx++], page_flags);
-
-			page_table_unlock(as, false);
-		}
-
-		ival = used_space_next(ival);
+	list_foreach(area->used_space.leaf_list, leaf_link, btree_node_t,
+	    node) {
+		btree_key_t i;
+
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t ptr = node->key[i];
+			size_t size;
+
+			for (size = 0; size < (size_t) node->value[i]; size++) {
+				page_table_lock(as, false);
+
+				/* Insert the new mapping */
+				page_mapping_insert(as, ptr + P2SZ(size),
+				    old_frame[frame_idx++], page_flags);
+
+				page_table_unlock(as, false);
+			}
+		}
 	}
 
@@ -1844,180 +1725,10 @@
 }
 
-/** Initialize used space map.
- *
- * @param used_space Used space map
- */
-static void used_space_initialize(used_space_t *used_space)
-{
-	odict_initialize(&used_space->ivals, used_space_getkey, used_space_cmp);
-	used_space->pages = 0;
-}
-
-/** Finalize used space map.
- *
- * @param used_space Used space map
- */
-static void used_space_finalize(used_space_t *used_space)
-{
-	assert(odict_empty(&used_space->ivals));
-	odict_finalize(&used_space->ivals);
-}
-
-/** Get first interval of used space.
- *
- * @param used_space Used space map
- * @return First interval or @c NULL if there are none
- */
-used_space_ival_t *used_space_first(used_space_t *used_space)
-{
-	odlink_t *odlink = odict_first(&used_space->ivals);
-
-	if (odlink == NULL)
-		return NULL;
-
-	return odict_get_instance(odlink, used_space_ival_t, lused_space);
-}
-
-/** Get next interval of used space.
- *
- * @param cur Current interval
- * @return Next interval or @c NULL if there are none
- */
-used_space_ival_t *used_space_next(used_space_ival_t *cur)
-{
-	odlink_t *odlink = odict_next(&cur->lused_space,
-	    &cur->used_space->ivals);
-
-	if (odlink == NULL)
-		return NULL;
-
-	return odict_get_instance(odlink, used_space_ival_t, lused_space);
-}
-
-/** Get last interval of used space.
- *
- * @param used_space Used space map
- * @return First interval or @c NULL if there are none
- */
-static used_space_ival_t *used_space_last(used_space_t *used_space)
-{
-	odlink_t *odlink = odict_last(&used_space->ivals);
-
-	if (odlink == NULL)
-		return NULL;
-
-	return odict_get_instance(odlink, used_space_ival_t, lused_space);
-}
-
-/** Find the first interval that contains addresses greater than or equal to
- * @a ptr.
- *
- * @param used_space Used space map
- * @param ptr Virtual address
- *
- * @return Used space interval or @c NULL if none matches
- */
-used_space_ival_t *used_space_find_gteq(used_space_t *used_space, uintptr_t ptr)
-{
-	odlink_t *odlink;
-	used_space_ival_t *ival;
-
-	/* Find last interval to start at address less than @a ptr */
-	odlink = odict_find_lt(&used_space->ivals, &ptr, NULL);
-	if (odlink != NULL) {
-		ival = odict_get_instance(odlink, used_space_ival_t,
-		    lused_space);
-
-		/* If the interval extends above @a ptr, return it */
-		if (ival->page + P2SZ(ival->count) > ptr)
-			return ival;
-
-		/*
-		 * Otherwise, if a next interval exists, it must match
-		 * the criteria.
-		 */
-		odlink = odict_next(&ival->lused_space, &used_space->ivals);
-	} else {
-		/*
-		 * No interval with lower base address, so if there is any
-		 * interval at all, it must match the criteria
-		 */
-		odlink = odict_first(&used_space->ivals);
-	}
-
-	if (odlink != NULL) {
-		ival = odict_get_instance(odlink, used_space_ival_t,
-		    lused_space);
-		return ival;
-	}
-
-	return NULL;
-}
-
-/** Get key function for used space ordered dictionary.
- *
- * The key is the virtual address of the first page
- *
- * @param odlink Ordered dictionary link (used_space_ival_t.lused_space)
- * @return Pointer to virtual address of first page cast as @c void *.
- */
-static void *used_space_getkey(odlink_t *odlink)
-{
-	used_space_ival_t *ival = odict_get_instance(odlink, used_space_ival_t,
-	    lused_space);
-	return (void *) &ival->page;
-}
-
-/** Compare function for used space ordered dictionary.
- *
- * @param a Pointer to virtual address of first page cast as @c void *
- * @param b Pointer to virtual address of first page cast as @c void *
- * @return Less than zero, zero, greater than zero if virtual address @a a
- *         is less than, equal to, greater than virtual address b, respectively.
- */
-static int used_space_cmp(void *a, void *b)
-{
-	uintptr_t va = *(uintptr_t *) a;
-	uintptr_t vb = *(uintptr_t *) b;
-
-	if (va < vb)
-		return -1;
-	else if (va == vb)
-		return 0;
-	else
-		return +1;
-}
-
-/** Remove used space interval.
- *
- * @param ival Used space interval
- */
-static void used_space_remove_ival(used_space_ival_t *ival)
-{
-	ival->used_space->pages -= ival->count;
-	odict_remove(&ival->lused_space);
-	slab_free(used_space_ival_cache, ival);
-}
-
-/** Shorten used space interval.
- *
- * @param ival Used space interval
- * @param count New number of pages in the interval
- */
-static void used_space_shorten_ival(used_space_ival_t *ival, size_t count)
-{
-	assert(count > 0);
-	assert(count < ival->count);
-
-	ival->used_space->pages -= ival->count - count;
-	ival->count = count;
-}
-
 /** Mark portion of address space area as used.
  *
  * The address space area must be already locked.
  *
- * @param used_space Used space map
- * @param page First page to be marked.
+ * @param area  Address space area.
+ * @param page  First page to be marked.
  * @param count Number of page to be marked.
  *
@@ -2025,63 +1736,459 @@
  *
  */
-bool used_space_insert(used_space_t *used_space, uintptr_t page, size_t count)
-{
-	used_space_ival_t *a;
-	used_space_ival_t *b;
-	bool adj_a;
-	bool adj_b;
-	odlink_t *odlink;
-	used_space_ival_t *ival;
-
+bool used_space_insert(as_area_t *area, uintptr_t page, size_t count)
+{
+	assert(mutex_locked(&area->lock));
 	assert(IS_ALIGNED(page, PAGE_SIZE));
 	assert(count);
 
-	/* Interval to the left */
-	odlink = odict_find_lt(&used_space->ivals, &page, NULL);
-	a = (odlink != NULL) ?
-	    odict_get_instance(odlink, used_space_ival_t, lused_space) :
-	    NULL;
-
-	/* Interval to the right */
-	b = (a != NULL) ? used_space_next(a) :
-	    used_space_first(used_space);
-
-	/* Check for conflict with left interval */
-	if (a != NULL && overlaps(a->page, P2SZ(a->count), page, P2SZ(count)))
+	btree_node_t *leaf = NULL;
+	size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
+	if (pages) {
+		/*
+		 * We hit the beginning of some used space.
+		 */
 		return false;
-
-	/* Check for conflict with right interval */
-	if (b != NULL && overlaps(page, P2SZ(count), b->page, P2SZ(b->count)))
+	}
+
+	assert(leaf != NULL);
+
+	if (!leaf->keys) {
+		btree_insert(&area->used_space, page, (void *) count, leaf);
+		goto success;
+	}
+
+	btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
+	if (node) {
+		uintptr_t left_pg = node->key[node->keys - 1];
+		uintptr_t right_pg = leaf->key[0];
+		size_t left_cnt = (size_t) node->value[node->keys - 1];
+		size_t right_cnt = (size_t) leaf->value[0];
+
+		/*
+		 * Examine the possibility that the interval fits
+		 * somewhere between the rightmost interval of
+		 * the left neigbour and the first interval of the leaf.
+		 */
+
+		if (page >= right_pg) {
+			/* Do nothing. */
+		} else if (overlaps(page, P2SZ(count), left_pg,
+		    P2SZ(left_cnt))) {
+			/* The interval intersects with the left interval. */
+			return false;
+		} else if (overlaps(page, P2SZ(count), right_pg,
+		    P2SZ(right_cnt))) {
+			/* The interval intersects with the right interval. */
+			return false;
+		} else if ((page == left_pg + P2SZ(left_cnt)) &&
+		    (page + P2SZ(count) == right_pg)) {
+			/*
+			 * The interval can be added by merging the two already
+			 * present intervals.
+			 */
+			node->value[node->keys - 1] += count + right_cnt;
+			btree_remove(&area->used_space, right_pg, leaf);
+			goto success;
+		} else if (page == left_pg + P2SZ(left_cnt)) {
+			/*
+			 * The interval can be added by simply growing the left
+			 * interval.
+			 */
+			node->value[node->keys - 1] += count;
+			goto success;
+		} else if (page + P2SZ(count) == right_pg) {
+			/*
+			 * The interval can be addded by simply moving base of
+			 * the right interval down and increasing its size
+			 * accordingly.
+			 */
+			leaf->value[0] += count;
+			leaf->key[0] = page;
+			goto success;
+		} else {
+			/*
+			 * The interval is between both neigbouring intervals,
+			 * but cannot be merged with any of them.
+			 */
+			btree_insert(&area->used_space, page, (void *) count,
+			    leaf);
+			goto success;
+		}
+	} else if (page < leaf->key[0]) {
+		uintptr_t right_pg = leaf->key[0];
+		size_t right_cnt = (size_t) leaf->value[0];
+
+		/*
+		 * Investigate the border case in which the left neighbour does
+		 * not exist but the interval fits from the left.
+		 */
+
+		if (overlaps(page, P2SZ(count), right_pg, P2SZ(right_cnt))) {
+			/* The interval intersects with the right interval. */
+			return false;
+		} else if (page + P2SZ(count) == right_pg) {
+			/*
+			 * The interval can be added by moving the base of the
+			 * right interval down and increasing its size
+			 * accordingly.
+			 */
+			leaf->key[0] = page;
+			leaf->value[0] += count;
+			goto success;
+		} else {
+			/*
+			 * The interval doesn't adjoin with the right interval.
+			 * It must be added individually.
+			 */
+			btree_insert(&area->used_space, page, (void *) count,
+			    leaf);
+			goto success;
+		}
+	}
+
+	node = btree_leaf_node_right_neighbour(&area->used_space, leaf);
+	if (node) {
+		uintptr_t left_pg = leaf->key[leaf->keys - 1];
+		uintptr_t right_pg = node->key[0];
+		size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
+		size_t right_cnt = (size_t) node->value[0];
+
+		/*
+		 * Examine the possibility that the interval fits
+		 * somewhere between the leftmost interval of
+		 * the right neigbour and the last interval of the leaf.
+		 */
+
+		if (page < left_pg) {
+			/* Do nothing. */
+		} else if (overlaps(page, P2SZ(count), left_pg,
+		    P2SZ(left_cnt))) {
+			/* The interval intersects with the left interval. */
+			return false;
+		} else if (overlaps(page, P2SZ(count), right_pg,
+		    P2SZ(right_cnt))) {
+			/* The interval intersects with the right interval. */
+			return false;
+		} else if ((page == left_pg + P2SZ(left_cnt)) &&
+		    (page + P2SZ(count) == right_pg)) {
+			/*
+			 * The interval can be added by merging the two already
+			 * present intervals.
+			 */
+			leaf->value[leaf->keys - 1] += count + right_cnt;
+			btree_remove(&area->used_space, right_pg, node);
+			goto success;
+		} else if (page == left_pg + P2SZ(left_cnt)) {
+			/*
+			 * The interval can be added by simply growing the left
+			 * interval.
+			 */
+			leaf->value[leaf->keys - 1] += count;
+			goto success;
+		} else if (page + P2SZ(count) == right_pg) {
+			/*
+			 * The interval can be addded by simply moving base of
+			 * the right interval down and increasing its size
+			 * accordingly.
+			 */
+			node->value[0] += count;
+			node->key[0] = page;
+			goto success;
+		} else {
+			/*
+			 * The interval is between both neigbouring intervals,
+			 * but cannot be merged with any of them.
+			 */
+			btree_insert(&area->used_space, page, (void *) count,
+			    leaf);
+			goto success;
+		}
+	} else if (page >= leaf->key[leaf->keys - 1]) {
+		uintptr_t left_pg = leaf->key[leaf->keys - 1];
+		size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
+
+		/*
+		 * Investigate the border case in which the right neighbour
+		 * does not exist but the interval fits from the right.
+		 */
+
+		if (overlaps(page, P2SZ(count), left_pg, P2SZ(left_cnt))) {
+			/* The interval intersects with the left interval. */
+			return false;
+		} else if (left_pg + P2SZ(left_cnt) == page) {
+			/*
+			 * The interval can be added by growing the left
+			 * interval.
+			 */
+			leaf->value[leaf->keys - 1] += count;
+			goto success;
+		} else {
+			/*
+			 * The interval doesn't adjoin with the left interval.
+			 * It must be added individually.
+			 */
+			btree_insert(&area->used_space, page, (void *) count,
+			    leaf);
+			goto success;
+		}
+	}
+
+	/*
+	 * Note that if the algorithm made it thus far, the interval can fit
+	 * only between two other intervals of the leaf. The two border cases
+	 * were already resolved.
+	 */
+	btree_key_t i;
+	for (i = 1; i < leaf->keys; i++) {
+		if (page < leaf->key[i]) {
+			uintptr_t left_pg = leaf->key[i - 1];
+			uintptr_t right_pg = leaf->key[i];
+			size_t left_cnt = (size_t) leaf->value[i - 1];
+			size_t right_cnt = (size_t) leaf->value[i];
+
+			/*
+			 * The interval fits between left_pg and right_pg.
+			 */
+
+			if (overlaps(page, P2SZ(count), left_pg,
+			    P2SZ(left_cnt))) {
+				/*
+				 * The interval intersects with the left
+				 * interval.
+				 */
+				return false;
+			} else if (overlaps(page, P2SZ(count), right_pg,
+			    P2SZ(right_cnt))) {
+				/*
+				 * The interval intersects with the right
+				 * interval.
+				 */
+				return false;
+			} else if ((page == left_pg + P2SZ(left_cnt)) &&
+			    (page + P2SZ(count) == right_pg)) {
+				/*
+				 * The interval can be added by merging the two
+				 * already present intervals.
+				 */
+				leaf->value[i - 1] += count + right_cnt;
+				btree_remove(&area->used_space, right_pg, leaf);
+				goto success;
+			} else if (page == left_pg + P2SZ(left_cnt)) {
+				/*
+				 * The interval can be added by simply growing
+				 * the left interval.
+				 */
+				leaf->value[i - 1] += count;
+				goto success;
+			} else if (page + P2SZ(count) == right_pg) {
+				/*
+				 * The interval can be addded by simply moving
+				 * base of the right interval down and
+				 * increasing its size accordingly.
+				 */
+				leaf->value[i] += count;
+				leaf->key[i] = page;
+				goto success;
+			} else {
+				/*
+				 * The interval is between both neigbouring
+				 * intervals, but cannot be merged with any of
+				 * them.
+				 */
+				btree_insert(&area->used_space, page,
+				    (void *) count, leaf);
+				goto success;
+			}
+		}
+	}
+
+	panic("Inconsistency detected while adding %zu pages of used "
+	    "space at %p.", count, (void *) page);
+
+success:
+	area->resident += count;
+	return true;
+}
+
+/** Mark portion of address space area as unused.
+ *
+ * The address space area must be already locked.
+ *
+ * @param area  Address space area.
+ * @param page  First page to be marked.
+ * @param count Number of page to be marked.
+ *
+ * @return False on failure or true on success.
+ *
+ */
+bool used_space_remove(as_area_t *area, uintptr_t page, size_t count)
+{
+	assert(mutex_locked(&area->lock));
+	assert(IS_ALIGNED(page, PAGE_SIZE));
+	assert(count);
+
+	btree_node_t *leaf;
+	size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
+	if (pages) {
+		/*
+		 * We are lucky, page is the beginning of some interval.
+		 */
+		if (count > pages) {
+			return false;
+		} else if (count == pages) {
+			btree_remove(&area->used_space, page, leaf);
+			goto success;
+		} else {
+			/*
+			 * Find the respective interval.
+			 * Decrease its size and relocate its start address.
+			 */
+			btree_key_t i;
+			for (i = 0; i < leaf->keys; i++) {
+				if (leaf->key[i] == page) {
+					leaf->key[i] += P2SZ(count);
+					leaf->value[i] -= count;
+					goto success;
+				}
+			}
+
+			goto error;
+		}
+	}
+
+	btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space,
+	    leaf);
+	if ((node) && (page < leaf->key[0])) {
+		uintptr_t left_pg = node->key[node->keys - 1];
+		size_t left_cnt = (size_t) node->value[node->keys - 1];
+
+		if (overlaps(left_pg, P2SZ(left_cnt), page, P2SZ(count))) {
+			if (page + P2SZ(count) == left_pg + P2SZ(left_cnt)) {
+				/*
+				 * The interval is contained in the rightmost
+				 * interval of the left neighbour and can be
+				 * removed by updating the size of the bigger
+				 * interval.
+				 */
+				node->value[node->keys - 1] -= count;
+				goto success;
+			} else if (page + P2SZ(count) <
+			    left_pg + P2SZ(left_cnt)) {
+				size_t new_cnt;
+
+				/*
+				 * The interval is contained in the rightmost
+				 * interval of the left neighbour but its
+				 * removal requires both updating the size of
+				 * the original interval and also inserting a
+				 * new interval.
+				 */
+				new_cnt = ((left_pg + P2SZ(left_cnt)) -
+				    (page + P2SZ(count))) >> PAGE_WIDTH;
+				node->value[node->keys - 1] -= count + new_cnt;
+				btree_insert(&area->used_space, page +
+				    P2SZ(count), (void *) new_cnt, leaf);
+				goto success;
+			}
+		}
+
 		return false;
-
-	/* Check if A is adjacent to the new interval */
-	adj_a = (a != NULL) && (a->page + P2SZ(a->count) == page);
-	/* Check if the new interval is adjacent to B*/
-	adj_b = (b != NULL) && page + P2SZ(count) == b->page;
-
-	if (adj_a && adj_b) {
-		/* Fuse into a single interval */
-		a->count += count + b->count;
-		used_space_remove_ival(b);
-	} else if (adj_a) {
-		/* Append to A */
-		a->count += count;
-	} else if (adj_b) {
-		/* Prepend to B */
-		b->page = page;
-		b->count += count;
-	} else {
-		/* Create new interval */
-		ival = slab_alloc(used_space_ival_cache, 0);
-		ival->used_space = used_space;
-		odlink_initialize(&ival->lused_space);
-		ival->page = page;
-		ival->count = count;
-
-		odict_insert(&ival->lused_space, &used_space->ivals,
-		    NULL);
-	}
-
-	used_space->pages += count;
+	} else if (page < leaf->key[0])
+		return false;
+
+	if (page > leaf->key[leaf->keys - 1]) {
+		uintptr_t left_pg = leaf->key[leaf->keys - 1];
+		size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
+
+		if (overlaps(left_pg, P2SZ(left_cnt), page, P2SZ(count))) {
+			if (page + P2SZ(count) == left_pg + P2SZ(left_cnt)) {
+				/*
+				 * The interval is contained in the rightmost
+				 * interval of the leaf and can be removed by
+				 * updating the size of the bigger interval.
+				 */
+				leaf->value[leaf->keys - 1] -= count;
+				goto success;
+			} else if (page + P2SZ(count) < left_pg +
+			    P2SZ(left_cnt)) {
+				size_t new_cnt;
+
+				/*
+				 * The interval is contained in the rightmost
+				 * interval of the leaf but its removal
+				 * requires both updating the size of the
+				 * original interval and also inserting a new
+				 * interval.
+				 */
+				new_cnt = ((left_pg + P2SZ(left_cnt)) -
+				    (page + P2SZ(count))) >> PAGE_WIDTH;
+				leaf->value[leaf->keys - 1] -= count + new_cnt;
+				btree_insert(&area->used_space, page +
+				    P2SZ(count), (void *) new_cnt, leaf);
+				goto success;
+			}
+		}
+
+		return false;
+	}
+
+	/*
+	 * The border cases have been already resolved.
+	 * Now the interval can be only between intervals of the leaf.
+	 */
+	btree_key_t i;
+	for (i = 1; i < leaf->keys - 1; i++) {
+		if (page < leaf->key[i]) {
+			uintptr_t left_pg = leaf->key[i - 1];
+			size_t left_cnt = (size_t) leaf->value[i - 1];
+
+			/*
+			 * Now the interval is between intervals corresponding
+			 * to (i - 1) and i.
+			 */
+			if (overlaps(left_pg, P2SZ(left_cnt), page,
+			    P2SZ(count))) {
+				if (page + P2SZ(count) ==
+				    left_pg + P2SZ(left_cnt)) {
+					/*
+					 * The interval is contained in the
+					 * interval (i - 1) of the leaf and can
+					 * be removed by updating the size of
+					 * the bigger interval.
+					 */
+					leaf->value[i - 1] -= count;
+					goto success;
+				} else if (page + P2SZ(count) <
+				    left_pg + P2SZ(left_cnt)) {
+					size_t new_cnt;
+
+					/*
+					 * The interval is contained in the
+					 * interval (i - 1) of the leaf but its
+					 * removal requires both updating the
+					 * size of the original interval and
+					 * also inserting a new interval.
+					 */
+					new_cnt = ((left_pg + P2SZ(left_cnt)) -
+					    (page + P2SZ(count))) >>
+					    PAGE_WIDTH;
+					leaf->value[i - 1] -= count + new_cnt;
+					btree_insert(&area->used_space, page +
+					    P2SZ(count), (void *) new_cnt,
+					    leaf);
+					goto success;
+				}
+			}
+
+			return false;
+		}
+	}
+
+error:
+	panic("Inconsistency detected while removing %zu pages of used "
+	    "space from %p.", count, (void *) page);
+
+success:
+	area->resident -= count;
 	return true;
 }
Index: kernel/generic/src/mm/backend_anon.c
===================================================================
--- kernel/generic/src/mm/backend_anon.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/mm/backend_anon.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -48,4 +48,5 @@
 #include <synch/mutex.h>
 #include <adt/list.h>
+#include <adt/btree.h>
 #include <errno.h>
 #include <typedefs.h>
@@ -121,32 +122,36 @@
 	 */
 	mutex_lock(&area->sh_info->lock);
-	used_space_ival_t *ival = used_space_first(&area->used_space);
-	while (ival != NULL) {
-		uintptr_t base = ival->page;
-		size_t count = ival->count;
-		unsigned int j;
-
-		for (j = 0; j < count; j++) {
-			pte_t pte;
-			bool found;
-
-			page_table_lock(area->as, false);
-			found = page_mapping_find(area->as, base + P2SZ(j),
-			    false, &pte);
-
-			(void)found;
-			assert(found);
-			assert(PTE_VALID(&pte));
-			assert(PTE_PRESENT(&pte));
-
-			as_pagemap_insert(&area->sh_info->pagemap,
-			    (base + P2SZ(j)) - area->base, PTE_GET_FRAME(&pte));
-			page_table_unlock(area->as, false);
-
-			pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(&pte));
-			frame_reference_add(pfn);
+	list_foreach(area->used_space.leaf_list, leaf_link, btree_node_t,
+	    node) {
+		unsigned int i;
+
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t base = node->key[i];
+			size_t count = (size_t) node->value[i];
+			unsigned int j;
+
+			for (j = 0; j < count; j++) {
+				pte_t pte;
+				bool found;
+
+				page_table_lock(area->as, false);
+				found = page_mapping_find(area->as,
+				    base + P2SZ(j), false, &pte);
+
+				(void)found;
+				assert(found);
+				assert(PTE_VALID(&pte));
+				assert(PTE_PRESENT(&pte));
+
+				btree_insert(&area->sh_info->pagemap,
+				    (base + P2SZ(j)) - area->base,
+				    (void *) PTE_GET_FRAME(&pte), NULL);
+				page_table_unlock(area->as, false);
+
+				pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(&pte));
+				frame_reference_add(pfn);
+			}
+
 		}
-
-		ival = used_space_next(ival);
 	}
 	mutex_unlock(&area->sh_info->lock);
@@ -196,4 +201,6 @@
 	mutex_lock(&area->sh_info->lock);
 	if (area->sh_info->shared) {
+		btree_node_t *leaf;
+
 		/*
 		 * The area is shared, chances are that the mapping can be found
@@ -203,19 +210,33 @@
 		 * mapping, a new frame is allocated and the mapping is created.
 		 */
-		errno_t rc = as_pagemap_find(&area->sh_info->pagemap,
-		    upage - area->base, &frame);
-		if (rc != EOK) {
-			/* Need to allocate the frame */
-			kpage = km_temporary_page_get(&frame,
-			    FRAME_NO_RESERVE);
-			memsetb((void *) kpage, PAGE_SIZE, 0);
-			km_temporary_page_put(kpage);
+		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
+		    upage - area->base, &leaf);
+		if (!frame) {
+			bool allocate = true;
+			unsigned int i;
 
 			/*
-			 * Insert the address of the newly allocated
-			 * frame to the pagemap.
+			 * Zero can be returned as a valid frame address.
+			 * Just a small workaround.
 			 */
-			as_pagemap_insert(&area->sh_info->pagemap,
-			    upage - area->base, frame);
+			for (i = 0; i < leaf->keys; i++) {
+				if (leaf->key[i] == upage - area->base) {
+					allocate = false;
+					break;
+				}
+			}
+			if (allocate) {
+				kpage = km_temporary_page_get(&frame,
+				    FRAME_NO_RESERVE);
+				memsetb((void *) kpage, PAGE_SIZE, 0);
+				km_temporary_page_put(kpage);
+
+				/*
+				 * Insert the address of the newly allocated
+				 * frame to the pagemap.
+				 */
+				btree_insert(&area->sh_info->pagemap,
+				    upage - area->base, (void *) frame, leaf);
+			}
 		}
 		frame_reference_add(ADDR2PFN(frame));
@@ -259,5 +280,5 @@
 	 */
 	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
-	if (!used_space_insert(&area->used_space, upage, 1))
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 
Index: kernel/generic/src/mm/backend_elf.c
===================================================================
--- kernel/generic/src/mm/backend_elf.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/mm/backend_elf.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -153,6 +153,6 @@
 {
 	elf_segment_header_t *entry = area->backend_data.segment;
-	used_space_ival_t *start;
-	used_space_ival_t *cur;
+	link_t *cur;
+	btree_node_t *leaf, *node;
 	uintptr_t start_anon = entry->p_vaddr + entry->p_filesz;
 
@@ -164,8 +164,11 @@
 	 */
 	if (area->flags & AS_AREA_WRITE) {
-		start = used_space_first(&area->used_space);
+		node = list_get_instance(list_first(&area->used_space.leaf_list),
+		    btree_node_t, leaf_link);
 	} else {
-		/* Find first interval containing addresses >= start_anon */
-		start = used_space_find_gteq(&area->used_space, start_anon);
+		(void) btree_search(&area->used_space, start_anon, &leaf);
+		node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
+		if (!node)
+			node = leaf;
 	}
 
@@ -174,53 +177,57 @@
 	 */
 	mutex_lock(&area->sh_info->lock);
-	cur = start;
-	while (cur != NULL) {
-		uintptr_t base = cur->page;
-		size_t count = cur->count;
+	for (cur = &node->leaf_link; cur != &area->used_space.leaf_list.head;
+	    cur = cur->next) {
 		unsigned int i;
 
-		/*
-		 * Skip read-only areas of used space that are backed
-		 * by the ELF image.
-		 */
-		if (!(area->flags & AS_AREA_WRITE))
-			if (base >= entry->p_vaddr &&
-			    base + P2SZ(count) <= start_anon)
-				continue;
-
-		for (i = 0; i < count; i++) {
-			pte_t pte;
-			bool found;
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+
+		for (i = 0; i < node->keys; i++) {
+			uintptr_t base = node->key[i];
+			size_t count = (size_t) node->value[i];
+			unsigned int j;
 
 			/*
-			 * Skip read-only pages that are backed by the
-			 * ELF image.
+			 * Skip read-only areas of used space that are backed
+			 * by the ELF image.
 			 */
 			if (!(area->flags & AS_AREA_WRITE))
 				if (base >= entry->p_vaddr &&
-				    base + P2SZ(i + 1) <= start_anon)
+				    base + P2SZ(count) <= start_anon)
 					continue;
 
-			page_table_lock(area->as, false);
-			found = page_mapping_find(area->as,
-			    base + P2SZ(i), false, &pte);
-
-			(void) found;
-			assert(found);
-			assert(PTE_VALID(&pte));
-			assert(PTE_PRESENT(&pte));
-
-			as_pagemap_insert(&area->sh_info->pagemap,
-			    (base + P2SZ(i)) - area->base,
-			    PTE_GET_FRAME(&pte));
-			page_table_unlock(area->as, false);
-
-			pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(&pte));
-			frame_reference_add(pfn);
-		}
-
-		cur = used_space_next(cur);
-	}
-
+			for (j = 0; j < count; j++) {
+				pte_t pte;
+				bool found;
+
+				/*
+				 * Skip read-only pages that are backed by the
+				 * ELF image.
+				 */
+				if (!(area->flags & AS_AREA_WRITE))
+					if (base >= entry->p_vaddr &&
+					    base + P2SZ(j + 1) <= start_anon)
+						continue;
+
+				page_table_lock(area->as, false);
+				found = page_mapping_find(area->as,
+				    base + P2SZ(j), false, &pte);
+
+				(void) found;
+				assert(found);
+				assert(PTE_VALID(&pte));
+				assert(PTE_PRESENT(&pte));
+
+				btree_insert(&area->sh_info->pagemap,
+				    (base + P2SZ(j)) - area->base,
+				    (void *) PTE_GET_FRAME(&pte), NULL);
+				page_table_unlock(area->as, false);
+
+				pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(&pte));
+				frame_reference_add(pfn);
+			}
+
+		}
+	}
 	mutex_unlock(&area->sh_info->lock);
 }
@@ -260,4 +267,5 @@
 	elf_header_t *elf = area->backend_data.elf;
 	elf_segment_header_t *entry = area->backend_data.segment;
+	btree_node_t *leaf;
 	uintptr_t base;
 	uintptr_t frame;
@@ -293,15 +301,31 @@
 	mutex_lock(&area->sh_info->lock);
 	if (area->sh_info->shared) {
+		bool found = false;
+
 		/*
 		 * The address space area is shared.
 		 */
 
-		errno_t rc = as_pagemap_find(&area->sh_info->pagemap,
-		    upage - area->base, &frame);
-		if (rc == EOK) {
+		frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
+		    upage - area->base, &leaf);
+		if (!frame) {
+			unsigned int i;
+
+			/*
+			 * Workaround for valid NULL address.
+			 */
+
+			for (i = 0; i < leaf->keys; i++) {
+				if (leaf->key[i] == upage - area->base) {
+					found = true;
+					break;
+				}
+			}
+		}
+		if (frame || found) {
 			frame_reference_add(ADDR2PFN(frame));
 			page_mapping_insert(AS, upage, frame,
 			    as_area_get_flags(area));
-			if (!used_space_insert(&area->used_space, upage, 1))
+			if (!used_space_insert(area, upage, 1))
 				panic("Cannot insert used space.");
 			mutex_unlock(&area->sh_info->lock);
@@ -391,6 +415,6 @@
 	if (dirty && area->sh_info->shared) {
 		frame_reference_add(ADDR2PFN(frame));
-		as_pagemap_insert(&area->sh_info->pagemap, upage - area->base,
-		    frame);
+		btree_insert(&area->sh_info->pagemap, upage - area->base,
+		    (void *) frame, leaf);
 	}
 
@@ -398,5 +422,5 @@
 
 	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
-	if (!used_space_insert(&area->used_space, upage, 1))
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 
Index: kernel/generic/src/mm/backend_phys.c
===================================================================
--- kernel/generic/src/mm/backend_phys.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/mm/backend_phys.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -143,5 +143,5 @@
 	    as_area_get_flags(area));
 
-	if (!used_space_insert(&area->used_space, upage, 1))
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 
Index: kernel/generic/src/mm/backend_user.c
===================================================================
--- kernel/generic/src/mm/backend_user.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/mm/backend_user.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -147,5 +147,5 @@
 	uintptr_t frame = IPC_GET_ARG1(data);
 	page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
-	if (!used_space_insert(&area->used_space, upage, 1))
+	if (!used_space_insert(area, upage, 1))
 		panic("Cannot insert used space.");
 
Index: kernel/generic/src/proc/task.c
===================================================================
--- kernel/generic/src/proc/task.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/proc/task.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -269,5 +269,5 @@
 {
 	/*
-	 * Remove the task from the task odict.
+	 * Remove the task from the task B+tree.
 	 */
 	irq_spinlock_lock(&tasks_lock, true);
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/generic/src/sysinfo/stats.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -189,5 +189,5 @@
 			continue;
 
-		pages += area->used_space.pages;
+		pages += area->resident;
 		mutex_unlock(&area->lock);
 		area = as_area_next(area);
Index: kernel/test/btree/btree1.c
===================================================================
--- kernel/test/btree/btree1.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
+++ kernel/test/btree/btree1.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <test.h>
+#include <adt/btree.h>
+
+static void *data = (void *) 0xdeadbeef;
+
+const char *test_btree1(void)
+{
+	btree_t t;
+	int i;
+
+	btree_create(&t);
+
+	TPRINTF("Inserting keys.\n");
+	btree_insert(&t, 19, data, NULL);
+	btree_insert(&t, 20, data, NULL);
+	btree_insert(&t, 21, data, NULL);
+	btree_insert(&t, 0, data, NULL);
+	btree_insert(&t, 25, data, NULL);
+	btree_insert(&t, 22, data, NULL);
+	btree_insert(&t, 26, data, NULL);
+	btree_insert(&t, 23, data, NULL);
+	btree_insert(&t, 24, data, NULL);
+	btree_insert(&t, 5, data, NULL);
+	btree_insert(&t, 1, data, NULL);
+	btree_insert(&t, 4, data, NULL);
+	btree_insert(&t, 28, data, NULL);
+	btree_insert(&t, 29, data, NULL);
+	btree_insert(&t, 7, data, NULL);
+	btree_insert(&t, 8, data, NULL);
+	btree_insert(&t, 9, data, NULL);
+	btree_insert(&t, 17, data, NULL);
+	btree_insert(&t, 18, data, NULL);
+	btree_insert(&t, 2, data, NULL);
+	btree_insert(&t, 3, data, NULL);
+	btree_insert(&t, 6, data, NULL);
+	btree_insert(&t, 10, data, NULL);
+	btree_insert(&t, 11, data, NULL);
+	btree_insert(&t, 12, data, NULL);
+	btree_insert(&t, 13, data, NULL);
+	btree_insert(&t, 14, data, NULL);
+	btree_insert(&t, 15, data, NULL);
+	btree_insert(&t, 16, data, NULL);
+	btree_insert(&t, 27, data, NULL);
+
+	for (i = 30; i < 50; i++)
+		btree_insert(&t, i, data, NULL);
+	for (i = 100; i >= 50; i--)
+		btree_insert(&t, i, data, NULL);
+
+	if (!test_quiet)
+		btree_print(&t);
+
+	TPRINTF("Removing keys.\n");
+	btree_remove(&t, 50, NULL);
+	btree_remove(&t, 49, NULL);
+	btree_remove(&t, 51, NULL);
+	btree_remove(&t, 46, NULL);
+	btree_remove(&t, 45, NULL);
+	btree_remove(&t, 48, NULL);
+	btree_remove(&t, 53, NULL);
+	btree_remove(&t, 47, NULL);
+	btree_remove(&t, 52, NULL);
+	btree_remove(&t, 54, NULL);
+	btree_remove(&t, 65, NULL);
+	btree_remove(&t, 60, NULL);
+	btree_remove(&t, 99, NULL);
+	btree_remove(&t, 97, NULL);
+	btree_remove(&t, 57, NULL);
+	btree_remove(&t, 58, NULL);
+	btree_remove(&t, 61, NULL);
+	btree_remove(&t, 64, NULL);
+	btree_remove(&t, 56, NULL);
+	btree_remove(&t, 41, NULL);
+
+	for (i = 5; i < 20; i++)
+		btree_remove(&t, i, NULL);
+
+	btree_remove(&t, 2, NULL);
+	btree_remove(&t, 43, NULL);
+	btree_remove(&t, 22, NULL);
+	btree_remove(&t, 100, NULL);
+	btree_remove(&t, 98, NULL);
+	btree_remove(&t, 96, NULL);
+	btree_remove(&t, 66, NULL);
+	btree_remove(&t, 1, NULL);
+
+	for (i = 70; i < 90; i++)
+		btree_remove(&t, i, NULL);
+
+	btree_remove(&t, 20, NULL);
+	btree_remove(&t, 0, NULL);
+	btree_remove(&t, 40, NULL);
+	btree_remove(&t, 3, NULL);
+	btree_remove(&t, 4, NULL);
+	btree_remove(&t, 21, NULL);
+	btree_remove(&t, 44, NULL);
+	btree_remove(&t, 55, NULL);
+	btree_remove(&t, 62, NULL);
+	btree_remove(&t, 26, NULL);
+	btree_remove(&t, 27, NULL);
+	btree_remove(&t, 28, NULL);
+	btree_remove(&t, 29, NULL);
+	btree_remove(&t, 30, NULL);
+	btree_remove(&t, 31, NULL);
+	btree_remove(&t, 32, NULL);
+	btree_remove(&t, 33, NULL);
+	btree_remove(&t, 93, NULL);
+	btree_remove(&t, 95, NULL);
+	btree_remove(&t, 94, NULL);
+	btree_remove(&t, 69, NULL);
+	btree_remove(&t, 68, NULL);
+	btree_remove(&t, 92, NULL);
+	btree_remove(&t, 91, NULL);
+	btree_remove(&t, 67, NULL);
+	btree_remove(&t, 63, NULL);
+	btree_remove(&t, 90, NULL);
+	btree_remove(&t, 59, NULL);
+	btree_remove(&t, 23, NULL);
+	btree_remove(&t, 24, NULL);
+	btree_remove(&t, 25, NULL);
+	btree_remove(&t, 37, NULL);
+	btree_remove(&t, 38, NULL);
+	btree_remove(&t, 42, NULL);
+	btree_remove(&t, 39, NULL);
+	btree_remove(&t, 34, NULL);
+	btree_remove(&t, 35, NULL);
+	btree_remove(&t, 36, NULL);
+
+	if (!test_quiet)
+		btree_print(&t);
+
+	return NULL;
+}
Index: kernel/test/btree/btree1.def
===================================================================
--- kernel/test/btree/btree1.def	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
+++ kernel/test/btree/btree1.def	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -0,0 +1,6 @@
+{
+	"btree1",
+	"Test B-tree operations",
+	&test_btree1,
+	true
+},
Index: kernel/test/test.c
===================================================================
--- kernel/test/test.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/test/test.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -41,4 +41,5 @@
 test_t tests[] = {
 #include <atomic/atomic1.def>
+#include <btree/btree1.def>
 #include <debug/mips1.def>
 #include <fault/fault1.def>
Index: kernel/test/test.h
===================================================================
--- kernel/test/test.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ kernel/test/test.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -58,4 +58,5 @@
 
 extern const char *test_atomic1(void);
+extern const char *test_btree1(void);
 extern const char *test_mips1(void);
 extern const char *test_fault1(void);
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/Makefile	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -58,5 +58,4 @@
 	app/loc \
 	app/logset \
-	app/lprint \
 	app/mixerctl \
 	app/mkfat \
@@ -167,5 +166,4 @@
 	drv/char/msim-con \
 	drv/char/ns8250 \
-	drv/char/pc-lpt \
 	drv/char/pl050 \
 	drv/char/ski-con \
@@ -276,5 +274,4 @@
 
 export: $(BUILDS)
-	mkdir -p $(EXPORT_DIR)
 	$(MAKE) -r -C lib/posix export EXPORT_DIR=$(EXPORT_DIR)
 
Index: pace/app/lprint/Makefile
===================================================================
--- uspace/app/lprint/Makefile	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,35 +1,0 @@
-#
-# Copyright (c) 2018 Jiri Svoboda
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../..
-BINARY = lprint
-
-SOURCES = \
-	lprint.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/app/lprint/doc/doxygroups.h
===================================================================
--- uspace/app/lprint/doc/doxygroups.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,4 +1,0 @@
-/** @addtogroup lprint lprint
- * @brief Print on a printer
- * @ingroup apps
- */
Index: pace/app/lprint/lprint.c
===================================================================
--- uspace/app/lprint/lprint.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,309 +1,0 @@
-/*
- * Copyright (c) 2018 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lprint
- * @{
- */
-
-/**
- * @file
- * @brief Print on a printer
- *
- */
-
-#include <errno.h>
-#include <io/chardev.h>
-#include <loc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-
-#define NAME	"lprint"
-
-#define BUF_SIZE 1024
-
-static void syntax_print(void);
-
-/** Get default printer port.
- *
- * @param sid Place to store service ID of the printer port
- * @return EOK on success or error code
- */
-static errno_t lprint_get_def_printer_port(service_id_t *sid)
-{
-	category_id_t cid;
-	service_id_t *sids;
-	size_t nsids;
-	errno_t rc;
-
-	rc = loc_category_get_id("printer-port", &cid, 0);
-	if (rc != EOK)
-		return EIO;
-
-	rc = loc_category_get_svcs(cid, &sids, &nsids);
-	if (rc != EOK)
-		return EIO;
-
-	if (nsids < 1) {
-		free(sids);
-		return EIO;
-	}
-
-	*sid = sids[0];
-	free(sids);
-	return EOK;
-}
-
-/** Print a message.
- *
- * @param chardev Character device
- * @param argc Number of arguments
- * @param argv Arguments - strings to print
- *
- * @return EOK on success or error code
- */
-static errno_t lprint_msg(chardev_t *chardev, int argc, char *argv[])
-{
-	const char *msg;
-	size_t nbytes;
-	const char *sep;
-	errno_t rc;
-
-	while (argc > 0) {
-		msg = *argv;
-		--argc;
-		++argv;
-
-		rc = chardev_write(chardev, msg, str_size(msg), &nbytes);
-		if (rc != EOK) {
-			printf(NAME ": Failed sending data.\n");
-			return EIO;
-		}
-
-		sep = argc > 0 ? " " : "\n";
-
-		rc = chardev_write(chardev, sep, str_size(sep), &nbytes);
-		if (rc != EOK) {
-			printf(NAME ": Failed sending data.\n");
-			return EIO;
-		}
-	}
-
-	return EOK;
-}
-
-/** Print a file.
- *
- * @param chardev Character device
- * @param fname File name
- *
- * @return EOK on success or error code
- */
-static errno_t lprint_file(chardev_t *chardev, const char *fname)
-{
-	void *buf;
-	size_t nread, nwritten;
-	FILE *f = NULL;
-	errno_t rc;
-
-	buf = malloc(BUF_SIZE);
-	if (buf == NULL) {
-		printf(NAME ": Out of memory.\n");
-		rc = ENOMEM;
-		goto error;
-	}
-
-	f = fopen(fname, "rb");
-	if (f == NULL) {
-		printf(NAME ": Cannot open '%s'.\n", fname);
-		rc = EIO;
-		goto error;
-	}
-
-	while (true) {
-		nread = fread(buf, 1, BUF_SIZE, f);
-		if (ferror(f)) {
-			printf(NAME ": Error reading file.\n");
-			rc = EIO;
-			goto error;
-		}
-
-		if (nread == 0)
-			break;
-
-		rc = chardev_write(chardev, buf, nread, &nwritten);
-		if (rc != EOK) {
-			printf(NAME ": Failed sending data.\n");
-			rc = EIO;
-			goto error;
-		}
-
-	}
-
-	fclose(f);
-	return EOK;
-error:
-	if (buf != NULL)
-		free(buf);
-	if (f != NULL)
-		fclose(f);
-	return rc;
-}
-
-int main(int argc, char **argv)
-{
-	chardev_t *chardev;
-	errno_t rc;
-	async_sess_t *sess;
-	service_id_t sid;
-	const char *svc_name = NULL;
-	bool msg_mode = false;
-
-	if (argc < 2) {
-		printf(NAME ": Error, argument missing.\n");
-		syntax_print();
-		return 1;
-	}
-
-	--argc;
-	++argv;
-
-	while (*argv != NULL && *argv[0] == '-') {
-		if (str_cmp(*argv, "-d") == 0) {
-			--argc;
-			++argv;
-
-			if (*argv == NULL) {
-				printf(NAME ": Error, argument missing.\n");
-				syntax_print();
-				return 1;
-			}
-
-			svc_name = *argv;
-			--argc;
-			++argv;
-			continue;
-		}
-
-		if (str_cmp(*argv, "-m") == 0) {
-			msg_mode = true;
-			--argc;
-			++argv;
-			continue;
-		}
-
-		if (str_cmp(*argv, "--help") == 0) {
-			--argc;
-			++argv;
-
-			if (*argv != NULL) {
-				printf(NAME ": Error, unexpected argument.\n");
-				syntax_print();
-				return 1;
-			}
-
-			syntax_print();
-			return 0;
-		}
-
-		printf(NAME ": Error, invalid argument.\n");
-		syntax_print();
-		return 1;
-	}
-
-	if (argc < 1) {
-		printf(NAME ": Error, argument missing.\n");
-		syntax_print();
-		return 1;
-	}
-
-	if (!msg_mode && argc > 1) {
-		printf(NAME ": Error, too many arguments.\n");
-		syntax_print();
-		return 1;
-	}
-
-	if (svc_name != NULL) {
-		rc = loc_service_get_id(svc_name, &sid, 0);
-		if (rc != EOK) {
-			printf(NAME ": Failed resolving printer port service "
-			    "'%s'.\n", svc_name);
-			return 1;
-		}
-	} else {
-		rc = lprint_get_def_printer_port(&sid);
-		if (rc != EOK) {
-			printf(NAME ": No printer found.\n");
-			return 1;
-		}
-	}
-
-	sess = loc_service_connect(sid, INTERFACE_DDF, 0);
-	if (sess == NULL) {
-		printf(NAME ": Failed connecting printer port service.\n");
-		return 1;
-	}
-
-	rc = chardev_open(sess, &chardev);
-	if (rc != EOK) {
-		async_hangup(sess);
-		printf(NAME ": Failed opening printer port device.\n");
-		return 1;
-	}
-
-	if (msg_mode) {
-		rc = lprint_msg(chardev, argc, argv);
-		if (rc != EOK) {
-			chardev_close(chardev);
-			return 1;
-		}
-	} else {
-		rc = lprint_file(chardev, argv[0]);
-		if (rc != EOK) {
-			chardev_close(chardev);
-			return 1;
-		}
-	}
-
-	chardev_close(chardev);
-	return 0;
-}
-
-/** Print syntax help. */
-static void syntax_print(void)
-{
-	printf("syntax:\n"
-	    "\tlprint [<options>] <file>\n"
-	    "\tlprint [<options>] -m <message...>\n"
-	    "options:\n"
-	    "\t-d <device>Print to the specified device\n");
-}
-
-/**
- * @}
- */
Index: uspace/app/mkext4/mkext4.c
===================================================================
--- uspace/app/mkext4/mkext4.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/app/mkext4/mkext4.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -56,5 +56,4 @@
 	aoff64_t nblocks;
 	const char *label = "";
-	unsigned int bsize = 4096;
 
 	cfg.version = ext4_def_fs_version;
@@ -69,5 +68,5 @@
 	++argv;
 
-	while (*argv && *argv[0] == '-') {
+	while (*argv[0] == '-') {
 		if (str_cmp(*argv, "--size") == 0) {
 			--argc;
@@ -88,26 +87,4 @@
 			--argc;
 			++argv;
-			continue;
-		}
-
-		if (str_cmp(*argv, "--bsize") == 0) {
-			--argc;
-			++argv;
-			if (*argv == NULL) {
-				printf(NAME ": Error, argument missing.\n");
-				syntax_print();
-				return 1;
-			}
-
-			bsize = strtol(*argv, &endptr, 10);
-			if (*endptr != '\0') {
-				printf(NAME ": Error, invalid argument.\n");
-				syntax_print();
-				return 1;
-			}
-
-			--argc;
-			++argv;
-			continue;
 		}
 
@@ -130,5 +107,4 @@
 			--argc;
 			++argv;
-			continue;
 		}
 
@@ -146,10 +122,4 @@
 			--argc;
 			++argv;
-			continue;
-		}
-
-		if (str_cmp(*argv, "--help") == 0) {
-			syntax_print();
-			return 0;
 		}
 
@@ -158,8 +128,4 @@
 			++argv;
 			break;
-		} else {
-			printf(NAME ": Invalid argument: %s\n", *argv);
-			syntax_print();
-			return 1;
 		}
 	}
@@ -181,5 +147,4 @@
 
 	cfg.volume_name = label;
-	cfg.bsize = bsize;
 	(void) nblocks;
 
@@ -201,6 +166,5 @@
 	    "\t--size <sectors> Filesystem size, overrides device size\n"
 	    "\t--label <label>  Volume label\n"
-	    "\t--type <fstype>  Filesystem type (ext2, ext2old)\n"
-	    "\t--bsize <bytes>  Filesystem block size in bytes (default = 4096)\n");
+	    "\t--type <fstype>  Filesystem type (ext2, ext2old)\n");
 }
 
Index: uspace/app/modplay/modplay.c
===================================================================
--- uspace/app/modplay/modplay.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/app/modplay/modplay.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -39,5 +39,4 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <str.h>
 #include <str_error.h>
 #include <trackmod.h>
@@ -68,11 +67,4 @@
 }
 
-static void print_syntax(void)
-{
-	printf("syntax: modplay [<options>] <filename.mod>\n");
-	printf("options:\n");
-	printf("\t-t <target>\tOutput to specified audio target.\n");
-}
-
 int main(int argc, char *argv[])
 {
@@ -86,33 +78,8 @@
 	void *buffer;
 	size_t buffer_size;
-	const char *target = HOUND_DEFAULT_TARGET;
 	errno_t rc;
 
-	++argv;
-	--argc;
-
-	while (argc > 0 && (*argv)[0] == '-') {
-		if (str_cmp(*argv, "-t") == 0) {
-			++argv;
-			--argc;
-
-			if (argc < 1) {
-				printf("Option '-t' requires an argument.\n");
-				print_syntax();
-				return 1;
-			}
-
-			target = *argv++;
-			--argc;
-			continue;
-		}
-
-		printf("Invalid option '%s'\n", *argv);
-		print_syntax();
-		return 1;
-	}
-
-	if (argc != 1) {
-		print_syntax();
+	if (argc != 2) {
+		printf("syntax: modplay <filename.mod>\n");
 		return 1;
 	}
@@ -120,7 +87,7 @@
 	con = console_init(stdin, stdout);
 
-	rc = trackmod_module_load(argv[0], &mod);
+	rc = trackmod_module_load(argv[1], &mod);
 	if (rc != EOK) {
-		printf("Error loading %s.\n", argv[0]);
+		printf("Error loading %s.\n", argv[1]);
 		return 1;
 	}
@@ -147,18 +114,7 @@
 	}
 
-	rc = hound_context_connect_target(hound, target);
+	rc = hound_context_connect_target(hound, HOUND_DEFAULT_TARGET);
 	if (rc != EOK) {
-		printf("Error connecting audio target '%s': %s.\n",
-		    target, str_error(rc));
-
-		char **names = NULL;
-		size_t count = 0;
-		rc = hound_context_get_available_targets(hound, &names, &count);
-		if (rc == EOK) {
-			printf("Available targets:\n");
-			for (size_t i = 0; i < count; i++)
-				printf(" - %s\n", names[i]);
-		}
-
+		printf("Error connecting default audio target: %s.\n", str_error(rc));
 		return 1;
 	}
Index: uspace/app/sysinst/sysinst.c
===================================================================
--- uspace/app/sysinst/sysinst.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/app/sysinst/sysinst.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -62,5 +62,5 @@
  * in Grub notation).
  */
-#define DEFAULT_DEV "devices/\\hw\\sys\\00:01.0\\ata-c1\\d0"
+#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c1\\d0"
 //#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
 /** Volume label for the new file system */
Index: uspace/app/wavplay/main.c
===================================================================
--- uspace/app/wavplay/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/app/wavplay/main.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -119,5 +119,5 @@
  * @return Error code
  */
-static errno_t hplay(const char *filename, const char *target)
+static errno_t hplay(const char *filename)
 {
 	printf("Hound playback: %s\n", filename);
@@ -158,18 +158,8 @@
 	}
 
-	ret = hound_context_connect_target(hound, target);
+	ret = hound_context_connect_target(hound, HOUND_DEFAULT_TARGET);
 	if (ret != EOK) {
-		printf("Failed to connect to target '%s': %s\n", target,
+		printf("Failed to connect to default target: %s\n",
 		    str_error(ret));
-
-		char **names = NULL;
-		size_t count = 0;
-		ret = hound_context_get_available_targets(hound, &names, &count);
-		if (ret == EOK) {
-			printf("Available targets:\n");
-			for (size_t i = 0; i < count; i++)
-				printf(" - %s\n", names[i]);
-		}
-
 		hound_context_destroy(hound);
 		fclose(source);
@@ -225,5 +215,4 @@
 	{ "parallel", no_argument, 0, 'p' },
 	{ "record", no_argument, 0, 'r' },
-	{ "target", required_argument, 0, 't' },
 	{ "help", no_argument, 0, 'h' },
 	{ 0, 0, 0, 0 }
@@ -241,7 +230,6 @@
 	printf("\t -r, --record\t Start recording instead of playback. "
 	    "(Not implemented)\n");
-	printf("\t -d, --device\t Direct output to specified device instead of "
-	    "the sound service. Use location path or a special device `default'\n");
-	printf("\t -t, --target\t Output to the specified audio target.\n");
+	printf("\t -d, --device\t Use specified device instead of the sound "
+	    "service. Use location path or a special device `default'\n");
 	printf("\t -p, --parallel\t Play given files in parallel instead of "
 	    "sequentially (does not work with -d).\n");
@@ -251,5 +239,4 @@
 {
 	const char *device = "default";
-	const char *target = HOUND_DEFAULT_TARGET;
 	int idx = 0;
 	bool direct = false, record = false, parallel = false;
@@ -259,5 +246,5 @@
 	/* Parse command line options */
 	while (ret != -1) {
-		ret = getopt_long(argc, argv, "d:prt:h", opts, &idx);
+		ret = getopt_long(argc, argv, "d:prh", opts, &idx);
 		switch (ret) {
 		case 'd':
@@ -270,7 +257,4 @@
 		case 'p':
 			parallel = true;
-			break;
-		case 't':
-			target = optarg;
 			break;
 		case 'h':
@@ -350,5 +334,5 @@
 				fibril_add_ready(fid);
 			} else {
-				hplay(file, target);
+				hplay(file);
 			}
 		}
Index: uspace/doc/main_page.h
===================================================================
--- uspace/doc/main_page.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
+++ uspace/doc/main_page.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -0,0 +1,12 @@
+/**
+ * @mainpage HelenOS Operating System Source Code Reference
+ *
+ * HelenOS is a portable microkernel-based multiserver operating system designed and implemented from scratch. It decomposes key operating system functionality such as file systems, networking, device drivers and graphical user interface into a collection of fine-grained user space components that interact with each other via message passing. A failure or crash of one component does not directly harm others. HelenOS is therefore flexible, modular, extensible, fault tolerant and easy to understand.
+ *
+ * HelenOS does not aim to be a clone of any existing operating system and trades compatibility with legacy APIs for cleaner design. Most of HelenOS components have been made to order specifically for HelenOS so that its essential parts can stay free of adaptation layers, glue code, franken-components and the maintenance burden incurred by them.
+ *
+ * HelenOS runs on seven different processor architectures and machines ranging from embedded ARM devices and single-board computers through multicore 32-bit and 64-bit desktop PCs to 64-bit Itanium and SPARC rack-mount servers.
+ *
+ * HelenOS is open source, free software. Its source code is available under the BSD license. Some third-party components are licensed under GPL.
+ *
+ */
Index: uspace/drv/audio/hdaudio/hdaudio.c
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/audio/hdaudio/hdaudio.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -151,5 +151,4 @@
 {
 	ddf_fun_t *fun_pcm = NULL;
-	bool bound = false;
 	hda_t *hda = NULL;
 	hw_res_list_parsed_t res;
@@ -300,17 +299,9 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun_pcm, "audio-pcm");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding function to audio-pcm category.");
-		goto error;
-	}
+	ddf_fun_add_to_category(fun_pcm, "audio-pcm");
 
 	hw_res_list_parsed_clean(&res);
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun_pcm);
 	if (fun_pcm != NULL)
 		ddf_fun_destroy(fun_pcm);
Index: uspace/drv/audio/hdaudio/hdaudio.ma
===================================================================
--- uspace/drv/audio/hdaudio/hdaudio.ma	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/audio/hdaudio/hdaudio.ma	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -1,4 +1,3 @@
 10 pci/ven=1002&dev=4383
-10 pci/ven=8086&dev=160c
 10 pci/ven=8086&dev=1e20
 10 pci/ven=8086&dev=2668
@@ -6,3 +5,2 @@
 10 pci/ven=8086&dev=1c20
 10 pci/ven=8086&dev=293e
-10 pci/ven=8086&dev=9ca0
Index: uspace/drv/block/ata_bd/main.c
===================================================================
--- uspace/drv/block/ata_bd/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/block/ata_bd/main.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -162,5 +162,4 @@
 	ddf_fun_t *fun = NULL;
 	ata_fun_t *afun = NULL;
-	bool bound = false;
 
 	fun_name = ata_fun_name(disk);
@@ -203,12 +202,5 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "disk");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding function %s to "
-		    "category 'disk': %s", fun_name, str_error(rc));
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "disk");
 
 	free(fun_name);
@@ -216,6 +208,4 @@
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
Index: uspace/drv/block/ddisk/ddisk.c
===================================================================
--- uspace/drv/block/ddisk/ddisk.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/block/ddisk/ddisk.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -319,5 +319,4 @@
 	errno_t rc;
 	ddf_fun_t *fun = NULL;
-	bool bound = false;
 
 	fun = ddf_fun_create(ddisk->dev, fun_exposed, DDISK_FUN_NAME);
@@ -338,18 +337,9 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "disk");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding function %s to category "
-		    "'disk': %s.\n", DDISK_FUN_NAME, str_error(rc));
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "disk");
 	ddisk->fun = fun;
 
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
Index: uspace/drv/block/usbmast/main.c
===================================================================
--- uspace/drv/block/usbmast/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/block/usbmast/main.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -223,5 +223,4 @@
 	ddf_fun_t *fun = NULL;
 	usbmast_fun_t *mfun = NULL;
-	bool bound = false;
 
 	if (asprintf(&fun_name, "l%u", lun) < 0) {
@@ -300,12 +299,5 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "disk");
-	if (rc != EOK) {
-		usb_log_error("Failed to add function %s to category 'disk': %s.",
-		    fun_name, str_error(rc));
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "disk");
 
 	free(fun_name);
@@ -316,6 +308,4 @@
 	/* Error cleanup */
 error:
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
Index: uspace/drv/bus/isa/isa.dev
===================================================================
--- uspace/drv/bus/isa/isa.dev	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/bus/isa/isa.dev	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -17,14 +17,4 @@
 	irq 3
 	io_range 2f8 8
-
-lpt1:
-	match 100 isa/lpt
-	io_range 378 8
-	irq 7
-
-lpt2:
-	match 100 isa/lpt
-	io_range 278 8
-	irq 5
 
 i8042:
Index: uspace/drv/char/msim-con/msim-con.c
===================================================================
--- uspace/drv/char/msim-con/msim-con.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/char/msim-con/msim-con.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -85,5 +85,4 @@
 	irq_cmd_t *msim_cmds = NULL;
 	errno_t rc;
-	bool bound = false;
 
 	circ_buf_init(&con->cbuf, con->buf, msim_con_buf_size, 1);
@@ -144,12 +143,5 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "console");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error adding function 'a' to category "
-		    "'console'.");
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "console");
 
 	return EOK;
@@ -157,6 +149,4 @@
 	if (CAP_HANDLE_VALID(con->irq_handle))
 		async_irq_unsubscribe(con->irq_handle);
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
Index: uspace/drv/char/ns8250/ns8250.c
===================================================================
--- uspace/drv/char/ns8250/ns8250.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/char/ns8250/ns8250.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -829,5 +829,4 @@
 	bool need_cleanup = false;
 	bool need_unreg_intr_handler = false;
-	bool bound = false;
 	errno_t rc;
 
@@ -910,12 +909,7 @@
 	}
 
-	bound = true;
 	ns->fun = fun;
 
-	rc = ddf_fun_add_to_category(fun, "serial");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error adding function to category 'serial'.");
-		goto fail;
-	}
+	ddf_fun_add_to_category(fun, "serial");
 
 	ddf_msg(LVL_NOTE, "Device %s successfully initialized.",
@@ -924,6 +918,4 @@
 	return EOK;
 fail:
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun != NULL)
 		ddf_fun_destroy(fun);
Index: pace/drv/char/pc-lpt/Makefile
===================================================================
--- uspace/drv/char/pc-lpt/Makefile	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2018 Jiri Svoboda
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-USPACE_PREFIX = ../../..
-LIBS = drv
-BINARY = pc-lpt
-
-SOURCES = \
-	main.c \
-	pc-lpt.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: pace/drv/char/pc-lpt/doc/doxygroups.h
===================================================================
--- uspace/drv/char/pc-lpt/doc/doxygroups.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,4 +1,0 @@
-/** @addtogroup uspace_drv_pc_lpt pc-lpt
- * @brief PC parallel port driver
- * @ingroup drvs
- */
Index: pace/drv/char/pc-lpt/main.c
===================================================================
--- uspace/drv/char/pc-lpt/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,162 +1,0 @@
-/*
- * Copyright (c) 2018 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup uspace_drv_pc_lpt
- * @{
- */
-/** @file PC parallel port driver
- */
-
-#include <ddf/driver.h>
-#include <ddf/log.h>
-#include <device/hw_res_parsed.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "pc-lpt.h"
-
-#define NAME  "pc-lpt"
-
-static errno_t pc_lpt_dev_add(ddf_dev_t *dev);
-static errno_t pc_lpt_dev_remove(ddf_dev_t *dev);
-static errno_t pc_lpt_dev_gone(ddf_dev_t *dev);
-static errno_t pc_lpt_fun_online(ddf_fun_t *fun);
-static errno_t pc_lpt_fun_offline(ddf_fun_t *fun);
-
-static driver_ops_t driver_ops = {
-	.dev_add = pc_lpt_dev_add,
-	.dev_remove = pc_lpt_dev_remove,
-	.dev_gone = pc_lpt_dev_gone,
-	.fun_online = pc_lpt_fun_online,
-	.fun_offline = pc_lpt_fun_offline
-};
-
-static driver_t pc_lpt_driver = {
-	.name = NAME,
-	.driver_ops = &driver_ops
-};
-
-static errno_t pc_lpt_get_res(ddf_dev_t *dev, pc_lpt_res_t *res)
-{
-	async_sess_t *parent_sess;
-	hw_res_list_parsed_t hw_res;
-	errno_t rc;
-
-	parent_sess = ddf_dev_parent_sess_get(dev);
-	if (parent_sess == NULL)
-		return ENOMEM;
-
-	hw_res_list_parsed_init(&hw_res);
-	rc = hw_res_get_list_parsed(parent_sess, &hw_res, 0);
-	if (rc != EOK)
-		return rc;
-
-	if (hw_res.io_ranges.count != 1) {
-		rc = EINVAL;
-		goto error;
-	}
-
-	res->base = RNGABS(hw_res.io_ranges.ranges[0]);
-
-	if (hw_res.irqs.count != 1) {
-		rc = EINVAL;
-		goto error;
-	}
-
-	res->irq = hw_res.irqs.irqs[0];
-
-	return EOK;
-error:
-	hw_res_list_parsed_clean(&hw_res);
-	return rc;
-}
-
-static errno_t pc_lpt_dev_add(ddf_dev_t *dev)
-{
-	pc_lpt_t *pc_lpt;
-	pc_lpt_res_t res;
-	errno_t rc;
-
-	ddf_msg(LVL_DEBUG, "pc_lpt_dev_add(%p)", dev);
-
-	pc_lpt = ddf_dev_data_alloc(dev, sizeof(pc_lpt_t));
-	if (pc_lpt == NULL) {
-		ddf_msg(LVL_ERROR, "Failed allocating soft state.");
-		return ENOMEM;
-	}
-
-	pc_lpt->dev = dev;
-
-	rc = pc_lpt_get_res(dev, &res);
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed getting hardware resource list.");
-		return EIO;
-	}
-
-	return pc_lpt_add(pc_lpt, &res);
-}
-
-static errno_t pc_lpt_dev_remove(ddf_dev_t *dev)
-{
-	pc_lpt_t *pc_lpt = (pc_lpt_t *)ddf_dev_data_get(dev);
-
-	ddf_msg(LVL_DEBUG, "pc_lpt_dev_remove(%p)", dev);
-
-	return pc_lpt_remove(pc_lpt);
-}
-
-static errno_t pc_lpt_dev_gone(ddf_dev_t *dev)
-{
-	pc_lpt_t *pc_lpt = (pc_lpt_t *)ddf_dev_data_get(dev);
-
-	ddf_msg(LVL_DEBUG, "pc_lpt_dev_gone(%p)", dev);
-
-	return pc_lpt_gone(pc_lpt);
-}
-
-static errno_t pc_lpt_fun_online(ddf_fun_t *fun)
-{
-	ddf_msg(LVL_DEBUG, "pc_lpt_fun_online()");
-	return ddf_fun_online(fun);
-}
-
-static errno_t pc_lpt_fun_offline(ddf_fun_t *fun)
-{
-	ddf_msg(LVL_DEBUG, "pc_lpt_fun_offline()");
-	return ddf_fun_offline(fun);
-}
-
-int main(int argc, char *argv[])
-{
-	printf(NAME ": PC parallel port driver\n");
-	ddf_log_init(NAME);
-	return ddf_driver_main(&pc_lpt_driver);
-}
-
-/** @}
- */
Index: pace/drv/char/pc-lpt/pc-lpt.c
===================================================================
--- uspace/drv/char/pc-lpt/pc-lpt.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,262 +1,0 @@
-/*
- * Copyright (c) 2018 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @file
- * @brief PC parallel port driver.
- */
-
-#include <async.h>
-#include <bitops.h>
-#include <ddf/driver.h>
-#include <ddf/log.h>
-#include <ddi.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <io/chardev_srv.h>
-
-#include "pc-lpt.h"
-#include "pc-lpt_hw.h"
-
-static void pc_lpt_connection(ipc_call_t *, void *);
-
-static errno_t pc_lpt_read(chardev_srv_t *, void *, size_t, size_t *);
-static errno_t pc_lpt_write(chardev_srv_t *, const void *, size_t, size_t *);
-
-static chardev_ops_t pc_lpt_chardev_ops = {
-	.read = pc_lpt_read,
-	.write = pc_lpt_write
-};
-
-static irq_cmd_t pc_lpt_cmds_proto[] = {
-	{
-		.cmd = CMD_DECLINE
-	}
-};
-
-/** PC LPT IRQ handler.
- *
- * Note that while the standard PC parallel port supports IRQ, it seems
- * drivers tend to avoid using them (for a reason?) These IRQs tend
- * to be used by other HW as well (Sound Blaster) so caution is in order.
- * Also not sure, if/how the IRQ needs to be cleared.
- *
- * Currently we don't enable IRQ and don't handle it in any way.
- */
-static void pc_lpt_irq_handler(ipc_call_t *call, void *arg)
-{
-	pc_lpt_t *lpt = (pc_lpt_t *) arg;
-
-	(void) lpt;
-}
-
-/** Add pc-lpt device. */
-errno_t pc_lpt_add(pc_lpt_t *lpt, pc_lpt_res_t *res)
-{
-	ddf_fun_t *fun = NULL;
-	bool bound = false;
-	irq_cmd_t *pc_lpt_cmds = NULL;
-	uint8_t control;
-	uint8_t r;
-	errno_t rc;
-
-	lpt->irq_handle = CAP_NIL;
-	fibril_mutex_initialize(&lpt->hw_lock);
-
-	pc_lpt_cmds = malloc(sizeof(pc_lpt_cmds_proto));
-	if (pc_lpt_cmds == NULL) {
-		rc = ENOMEM;
-		goto error;
-	}
-
-	lpt->res = *res;
-
-	fun = ddf_fun_create(lpt->dev, fun_exposed, "a");
-	if (fun == NULL) {
-		ddf_msg(LVL_ERROR, "Error creating function 'a'.");
-		rc = ENOMEM;
-		goto error;
-	}
-
-	rc = pio_enable((void *)res->base, sizeof(pc_lpt_regs_t),
-	    (void **) &lpt->regs);
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error enabling I/O");
-		goto error;
-	}
-
-	ddf_fun_set_conn_handler(fun, pc_lpt_connection);
-
-	lpt->irq_range[0].base = res->base;
-	lpt->irq_range[0].size = 1;
-
-	memcpy(pc_lpt_cmds, pc_lpt_cmds_proto, sizeof(pc_lpt_cmds_proto));
-	pc_lpt_cmds[0].addr = (void *) res->base;
-
-	lpt->irq_code.rangecount = 1;
-	lpt->irq_code.ranges = lpt->irq_range;
-	lpt->irq_code.cmdcount = sizeof(pc_lpt_cmds_proto) / sizeof(irq_cmd_t);
-	lpt->irq_code.cmds = pc_lpt_cmds;
-
-	rc = async_irq_subscribe(res->irq, pc_lpt_irq_handler, lpt,
-	    &lpt->irq_code, &lpt->irq_handle);
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error registering IRQ code.");
-		goto error;
-	}
-
-	control = BIT_V(uint8_t, ctl_select) | BIT_V(uint8_t, ctl_ninit);
-	pio_write_8(&lpt->regs->control, control);
-	r = pio_read_8(&lpt->regs->control);
-	if ((r & 0xf) != control) {
-		/* Device not present */
-		rc = EIO;
-		goto error;
-	}
-
-	control |= BIT_V(uint8_t, ctl_autofd);
-	pio_write_8(&lpt->regs->control, control);
-	r = pio_read_8(&lpt->regs->control);
-	if ((r & 0xf) != control) {
-		/* Device not present */
-		rc = EIO;
-		goto error;
-	}
-
-	control &= ~BIT_V(uint8_t, ctl_autofd);
-	pio_write_8(&lpt->regs->control, control);
-
-	chardev_srvs_init(&lpt->cds);
-	lpt->cds.ops = &pc_lpt_chardev_ops;
-	lpt->cds.sarg = lpt;
-
-	rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error binding function 'a'.");
-		goto error;
-	}
-
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "printer-port");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error adding function 'a' to category "
-		    "'printer-port'.");
-		goto error;
-	}
-
-	return EOK;
-error:
-	if (CAP_HANDLE_VALID(lpt->irq_handle))
-		async_irq_unsubscribe(lpt->irq_handle);
-	if (bound)
-		ddf_fun_unbind(fun);
-	if (fun != NULL)
-		ddf_fun_destroy(fun);
-	free(pc_lpt_cmds);
-
-	return rc;
-}
-
-/** Remove pc-lpt device */
-errno_t pc_lpt_remove(pc_lpt_t *lpt)
-{
-	return ENOTSUP;
-}
-
-/** Pc-lpt device gone */
-errno_t pc_lpt_gone(pc_lpt_t *lpt)
-{
-	return ENOTSUP;
-}
-
-/** Write a single byte to the parallel port.
- *
- * @param lpt Parallel port (locked)
- * @param ch Byte
- */
-static void pc_lpt_putchar(pc_lpt_t *lpt, uint8_t ch)
-{
-	uint8_t status;
-	uint8_t control;
-
-	assert(fibril_mutex_is_locked(&lpt->hw_lock));
-
-	/* Write data */
-	pio_write_8(&lpt->regs->data, ch);
-
-	/* Wait for S7/nbusy to become 1 */
-	do {
-		status = pio_read_8(&lpt->regs->status);
-		// FIXME Need to time out with an error after a while
-	} while ((status & BIT_V(uint8_t, sts_nbusy)) == 0);
-
-	control = pio_read_8(&lpt->regs->control);
-	pio_write_8(&lpt->regs->control, control | BIT_V(uint8_t, ctl_strobe));
-	fibril_usleep(5);
-	pio_write_8(&lpt->regs->control, control & ~BIT_V(uint8_t, ctl_strobe));
-}
-
-/** Read from pc-lpt device */
-static errno_t pc_lpt_read(chardev_srv_t *srv, void *buf, size_t size,
-    size_t *nread)
-{
-	pc_lpt_t *lpt = (pc_lpt_t *) srv->srvs->sarg;
-	(void) lpt;
-	return ENOTSUP;
-}
-
-/** Write to pc-lpt device */
-static errno_t pc_lpt_write(chardev_srv_t *srv, const void *data, size_t size,
-    size_t *nwr)
-{
-	pc_lpt_t *lpt = (pc_lpt_t *) srv->srvs->sarg;
-	size_t i;
-	uint8_t *dp = (uint8_t *) data;
-
-	fibril_mutex_lock(&lpt->hw_lock);
-
-	for (i = 0; i < size; i++)
-		pc_lpt_putchar(lpt, dp[i]);
-
-	fibril_mutex_unlock(&lpt->hw_lock);
-
-	*nwr = size;
-	return EOK;
-}
-
-/** Character device connection handler. */
-static void pc_lpt_connection(ipc_call_t *icall, void *arg)
-{
-	pc_lpt_t *lpt = (pc_lpt_t *) ddf_dev_data_get(
-	    ddf_fun_get_dev((ddf_fun_t *) arg));
-
-	chardev_conn(icall, &lpt->cds);
-}
-
-/** @}
- */
Index: pace/drv/char/pc-lpt/pc-lpt.h
===================================================================
--- uspace/drv/char/pc-lpt/pc-lpt.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,80 +1,0 @@
-/*
- * Copyright (c) 2018 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup uspace_drv_pc_lpt
- * @{
- */
-/** @file
- */
-
-#ifndef PC_LPT_H
-#define PC_LPT_H
-
-#include <async.h>
-#include <ddf/driver.h>
-#include <ddi.h>
-#include <fibril_synch.h>
-#include <io/chardev_srv.h>
-#include <stdint.h>
-
-#include "pc-lpt_hw.h"
-
-/** PC parallel port resources */
-typedef struct {
-	uintptr_t base;
-	int irq;
-} pc_lpt_res_t;
-
-/** PC parallel port */
-typedef struct {
-	/** DDF device */
-	ddf_dev_t *dev;
-	/** Character device service structure */
-	chardev_srvs_t cds;
-	/** Hardware resources */
-	pc_lpt_res_t res;
-	/** PIO range */
-	irq_pio_range_t irq_range[1];
-	/** IRQ code */
-	irq_code_t irq_code;
-	/** Hardware access lock */
-	fibril_mutex_t hw_lock;
-	/** Hardware registers */
-	pc_lpt_regs_t *regs;
-	/** IRQ handle */
-	cap_irq_handle_t irq_handle;
-} pc_lpt_t;
-
-extern errno_t pc_lpt_add(pc_lpt_t *, pc_lpt_res_t *);
-extern errno_t pc_lpt_remove(pc_lpt_t *);
-extern errno_t pc_lpt_gone(pc_lpt_t *);
-
-#endif
-
-/** @}
- */
Index: pace/drv/char/pc-lpt/pc-lpt.ma
===================================================================
--- uspace/drv/char/pc-lpt/pc-lpt.ma	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,1 +1,0 @@
-10 isa/lpt
Index: pace/drv/char/pc-lpt/pc-lpt_hw.h
===================================================================
--- uspace/drv/char/pc-lpt/pc-lpt_hw.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ 	(revision )
@@ -1,81 +1,0 @@
-/*
- * Copyright (c) 2018 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup uspace_drv_pc_lpt
- * @{
- */
-/** @file
- */
-
-#ifndef PC_LPT_HW_H
-#define PC_LPT_HW_H
-
-#include <ddi.h>
-
-/** PC parallel port registers */
-typedef struct {
-	/** Data out register */
-	ioport8_t data;
-	/** Status register */
-	ioport8_t status;
-	/** Control register */
-	ioport8_t control;
-} pc_lpt_regs_t;
-
-/** Printer control register bits */
-typedef enum {
-	/** Strobe */
-	ctl_strobe = 0,
-	/** Auto linefeed */
-	ctl_autofd = 1,
-	/** -Init */
-	ctl_ninit = 2,
-	/** Select */
-	ctl_select = 3,
-	/** IRQ Enable */
-	ctl_irq_enable = 4
-} pc_lpt_ctl_bits_t;
-
-/** Printer status register bits */
-typedef enum {
-	/** -Error */
-	sts_nerror = 3,
-	/** Select */
-	sts_select = 4,
-	/** Init */
-	sts_paper_end = 5,
-	/** -Ack */
-	sts_nack = 6,
-	/** -Busy */
-	sts_nbusy = 7
-} pc_lpt_sts_bits_t;
-
-#endif
-
-/** @}
- */
Index: uspace/drv/char/ski-con/ski-con.c
===================================================================
--- uspace/drv/char/ski-con/ski-con.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/char/ski-con/ski-con.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -112,12 +112,7 @@
 	}
 
+	ddf_fun_add_to_category(fun, "console");
+
 	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "console");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error adding function 'a' to category "
-		    "'console'.");
-		goto error;
-	}
 
 	fid = fibril_create(ski_con_fibril, con);
Index: uspace/drv/char/sun4v-con/sun4v-con.c
===================================================================
--- uspace/drv/char/sun4v-con/sun4v-con.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/char/sun4v-con/sun4v-con.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -74,5 +74,4 @@
 	ddf_fun_t *fun = NULL;
 	errno_t rc;
-	bool bound = false;
 
 	con->res = *res;
@@ -114,12 +113,5 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, "console");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Error adding function 'a' to category "
-		    "'console'.");
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "console");
 
 	return EOK;
@@ -130,7 +122,4 @@
 	if (con->output_buffer != (niagara_output_buffer_t *) AS_AREA_ANY)
 		physmem_unmap((void *) con->output_buffer);
-
-	if (bound)
-		ddf_fun_unbind(fun);
 
 	if (fun != NULL)
Index: uspace/drv/fb/amdm37x_dispc/main.c
===================================================================
--- uspace/drv/fb/amdm37x_dispc/main.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/fb/amdm37x_dispc/main.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -60,5 +60,5 @@
 	ddf_fun_t *fun = ddf_fun_create(dev, fun_exposed, "viz");
 	if (!fun) {
-		ddf_log_error("Failed to create visualizer function.");
+		ddf_log_error("Failed to create visualizer function\n");
 		return ENOMEM;
 	}
@@ -66,5 +66,5 @@
 	visualizer_t *vis = ddf_fun_data_alloc(fun, sizeof(visualizer_t));
 	if (!vis) {
-		ddf_log_error("Failed to allocate visualizer structure.");
+		ddf_log_error("Failed to allocate visualizer structure\n");
 		ddf_fun_destroy(fun);
 		return ENOMEM;
@@ -79,36 +79,27 @@
 	    ddf_dev_data_alloc(dev, sizeof(amdm37x_dispc_t));
 	if (!dispc) {
-		ddf_log_error("Failed to allocate dispc structure.");
+		ddf_log_error("Failed to allocate dispc structure\n");
 		ddf_fun_destroy(fun);
 		return ENOMEM;
 	}
 
-	errno_t rc = amdm37x_dispc_init(dispc, vis);
-	if (rc != EOK) {
-		ddf_log_error("Failed to init dispc: %s.", str_error(rc));
+	errno_t ret = amdm37x_dispc_init(dispc, vis);
+	if (ret != EOK) {
+		ddf_log_error("Failed to init dispc: %s\n", str_error(ret));
 		ddf_fun_destroy(fun);
-		return rc;
+		return ret;
 	}
 
 	/* Bind function */
-	rc = ddf_fun_bind(fun);
-	if (rc != EOK) {
-		ddf_log_error("Failed to bind function: %s.", str_error(rc));
+	ret = ddf_fun_bind(fun);
+	if (ret != EOK) {
+		ddf_log_error("Failed to bind function: %s\n", str_error(ret));
 		amdm37x_dispc_fini(dispc);
 		ddf_fun_destroy(fun);
-		return rc;
+		return ret;
 	}
+	ddf_fun_add_to_category(fun, "visualizer");
 
-	rc = ddf_fun_add_to_category(fun, "visualizer");
-	if (rc != EOK) {
-		ddf_log_error("Failed to add function: %s to visualizer "
-		    "category.", str_error(rc));
-		amdm37x_dispc_fini(dispc);
-		ddf_fun_unbind(fun);
-		ddf_fun_destroy(fun);
-		return rc;
-	}
-
-	ddf_log_note("Added device `%s'", ddf_dev_get_name(dev));
+	ddf_log_note("Added device `%s'\n", ddf_dev_get_name(dev));
 	return EOK;
 }
Index: uspace/drv/fb/kfb/port.c
===================================================================
--- uspace/drv/fb/kfb/port.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/fb/kfb/port.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -348,12 +348,5 @@
 
 	vs->reg_svc_handle = ddf_fun_get_handle(fun_vs);
-	rc = ddf_fun_add_to_category(fun_vs, "visualizer");
-	if (rc != EOK) {
-		list_remove(&pixel_mode.link);
-		ddf_fun_unbind(fun_vs);
-		ddf_fun_destroy(fun_vs);
-		as_area_destroy(kfb.addr);
-		return rc;
-	}
+	ddf_fun_add_to_category(fun_vs, "visualizer");
 
 	return EOK;
Index: uspace/drv/intctl/apic/apic.c
===================================================================
--- uspace/drv/intctl/apic/apic.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/intctl/apic/apic.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -212,5 +212,4 @@
 	void *regs;
 	errno_t rc;
-	bool bound = false;
 
 	if ((sysinfo_get_value("apic", &have_apic) != EOK) || (!have_apic)) {
@@ -242,6 +241,4 @@
 	}
 
-	bound = true;
-
 	rc = ddf_fun_add_to_category(fun_a, "irc");
 	if (rc != EOK)
@@ -250,6 +247,4 @@
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun_a);
 	if (fun_a != NULL)
 		ddf_fun_destroy(fun_a);
Index: uspace/drv/intctl/i8259/i8259.c
===================================================================
--- uspace/drv/intctl/i8259/i8259.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/intctl/i8259/i8259.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -142,5 +142,4 @@
 	ddf_fun_t *fun_a = NULL;
 	errno_t rc;
-	bool bound = false;
 
 	if ((sysinfo_get_value("i8259", &have_i8259) != EOK) || (!have_i8259)) {
@@ -175,6 +174,4 @@
 	}
 
-	bound = true;
-
 	rc = ddf_fun_add_to_category(fun_a, "irc");
 	if (rc != EOK)
@@ -183,6 +180,4 @@
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun_a);
 	if (fun_a != NULL)
 		ddf_fun_destroy(fun_a);
Index: uspace/drv/intctl/icp-ic/icp-ic.c
===================================================================
--- uspace/drv/intctl/icp-ic/icp-ic.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/intctl/icp-ic/icp-ic.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -116,5 +116,4 @@
 	void *regs;
 	errno_t rc;
-	bool bound = false;
 
 	rc = pio_enable((void *)res->base, sizeof(icpic_regs_t), &regs);
@@ -147,6 +146,4 @@
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun_a);
 	if (fun_a != NULL)
 		ddf_fun_destroy(fun_a);
Index: uspace/drv/intctl/obio/obio.c
===================================================================
--- uspace/drv/intctl/obio/obio.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/intctl/obio/obio.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -118,5 +118,4 @@
 	ddf_fun_t *fun_a = NULL;
 	errno_t rc;
-	bool bound = false;
 
 	rc = pio_enable((void *)res->base, OBIO_SIZE, (void **) &obio->regs);
@@ -150,6 +149,4 @@
 	return EOK;
 error:
-	if (bound)
-		ddf_fun_unbind(fun_a);
 	if (fun_a != NULL)
 		ddf_fun_destroy(fun_a);
Index: uspace/drv/test/test1/test1.c
===================================================================
--- uspace/drv/test/test1/test1.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/test/test1/test1.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -176,12 +176,5 @@
 	}
 
-	rc = ddf_fun_add_to_category(fun_a, "virtual");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding function 'a' to category "
-		    "'virtual'.");
-		ddf_fun_unbind(fun_a);
-		ddf_fun_destroy(fun_a);
-		goto error;
-	}
+	ddf_fun_add_to_category(fun_a, "virtual");
 
 	if (str_cmp(dev_name, "test1") == 0) {
Index: uspace/drv/test/test2/test2.c
===================================================================
--- uspace/drv/test/test2/test2.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/test/test2/test2.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -140,18 +140,9 @@
 	rc = ddf_fun_bind(fun_a);
 	if (rc != EOK) {
-		ddf_fun_destroy(fun_a);
 		ddf_msg(LVL_ERROR, "Failed binding function 'a'.");
 		return rc;
 	}
 
-	rc = ddf_fun_add_to_category(fun_a, "virtual");
-	if (rc != EOK) {
-		ddf_fun_unbind(fun_a);
-		ddf_fun_destroy(fun_a);
-		ddf_msg(LVL_ERROR, "Failed adding function 'a' to category "
-		    "'virtual'.");
-		return rc;
-	}
-
+	ddf_fun_add_to_category(fun_a, "virtual");
 	test2->fun_a = fun_a;
 
Index: uspace/drv/test/test3/test3.c
===================================================================
--- uspace/drv/test/test3/test3.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/test/test3/test3.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -70,5 +70,4 @@
 	errno_t rc;
 	char *fun_name = NULL;
-	bool bound = false;
 
 	if (asprintf(&fun_name, "%s%zu", base_name, index) < 0) {
@@ -92,12 +91,5 @@
 	}
 
-	bound = true;
-
-	rc = ddf_fun_add_to_category(fun, class_name);
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed addning function %s to category %s: "
-		    "%s", fun_name, class_name, str_error(rc));
-		goto leave;
-	}
+	ddf_fun_add_to_category(fun, class_name);
 
 	ddf_msg(LVL_NOTE, "Registered exposed function `%s'.", fun_name);
@@ -106,6 +98,4 @@
 	free(fun_name);
 
-	if (bound)
-		ddf_fun_unbind(fun);
 	if ((rc != EOK) && (fun != NULL)) {
 		ddf_fun_destroy(fun);
Index: uspace/drv/time/cmos-rtc/cmos-rtc.c
===================================================================
--- uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/drv/time/cmos-rtc/cmos-rtc.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -588,5 +588,4 @@
 	errno_t rc;
 	bool need_cleanup = false;
-	bool bound = false;
 
 	ddf_msg(LVL_DEBUG, "rtc_dev_add %s (handle = %d)",
@@ -625,12 +624,7 @@
 	}
 
-	bound = true;
 	rtc->fun = fun;
 
-	rc = ddf_fun_add_to_category(fun, "clock");
-	if (rc != EOK) {
-		ddf_msg(LVL_ERROR, "Failed adding service to clock category.");
-		goto error;
-	}
+	ddf_fun_add_to_category(fun, "clock");
 
 	ddf_msg(LVL_NOTE, "Device %s successfully initialized",
@@ -640,6 +634,4 @@
 
 error:
-	if (bound)
-		ddf_fun_unbind(fun);
 	if (fun)
 		ddf_fun_destroy(fun);
@@ -762,8 +754,6 @@
 
 	rc = ddf_fun_online(fun);
-	if (rc == EOK) {
-		// XXX This should be probably handled by the framework
-		rc = ddf_fun_add_to_category(fun, "clock");
-	}
+	if (rc == EOK)
+		ddf_fun_add_to_category(fun, "clock");
 
 	return rc;
Index: uspace/lib/c/generic/async/server.c
===================================================================
--- uspace/lib/c/generic/async/server.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/c/generic/async/server.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -871,6 +871,4 @@
 
 		memset(call, 0, sizeof(ipc_call_t));
-		IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP);
-		call->cap_handle = CAP_NIL;
 	}
 
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/drv/generic/driver.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -526,6 +526,4 @@
 		return NULL;
 
-	refcount_init(&dev->refcnt);
-
 	return dev;
 }
@@ -543,5 +541,4 @@
 		return NULL;
 
-	refcount_init(&fun->refcnt);
 	init_match_ids(&fun->match_ids);
 	link_initialize(&fun->link);
Index: uspace/lib/drv/generic/remote_audio_pcm.c
===================================================================
--- uspace/lib/drv/generic/remote_audio_pcm.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/drv/generic/remote_audio_pcm.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -142,9 +142,9 @@
 audio_pcm_sess_t *audio_pcm_open(const char *name)
 {
-	service_id_t sid;
-	const errno_t ret = loc_service_get_id(name, &sid, 0);
+	devman_handle_t device_handle = 0;
+	const errno_t ret = devman_fun_get_handle(name, &device_handle, 0);
 	if (ret != EOK)
 		return NULL;
-	return loc_service_connect(sid, INTERFACE_DDF, 0);
+	return devman_device_connect(device_handle, IPC_FLAG_BLOCKING);
 }
 
Index: uspace/lib/ext4/include/ext4/cfg.h
===================================================================
--- uspace/lib/ext4/include/ext4/cfg.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/include/ext4/cfg.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -53,6 +53,4 @@
 	/** Volume name encoded as UTF-8 string */
 	const char *volume_name;
-	/** Filesystem block size */
-	size_t bsize;
 } ext4_cfg_t;
 
Index: uspace/lib/ext4/include/ext4/superblock.h
===================================================================
--- uspace/lib/ext4/include/ext4/superblock.h	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/include/ext4/superblock.h	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -147,5 +147,4 @@
 extern void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
     uint32_t n);
-extern uint32_t ext4_superblock_get_flex_group_size(ext4_superblock_t *sb);
 
 /* More complex superblock functions */
Index: uspace/lib/ext4/src/balloc.c
===================================================================
--- uspace/lib/ext4/src/balloc.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/src/balloc.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -261,28 +261,32 @@
 		 * is always after the inode table.
 		 */
-		return itable + itable_sz;
-	}
-
-	uint32_t flex_group_size = ext4_superblock_get_flex_group_size(sb);
-	if ((bg_ref->index % flex_group_size) == 0) {
-		/* This is the base group */
-		uint32_t i;
-
 		r = itable + itable_sz;
-
-		uint32_t total_groups = ext4_superblock_get_block_group_count(sb);
-		for (i = bg_ref->index + 1;
-		    i < min(total_groups, bg_ref->index + flex_group_size); ++i) {
-			r += ext4_filesystem_bg_get_itable_size(sb, i);
-		}
-
-		return r;
-	}
-
-	uint64_t base_addr = ext4_filesystem_index_in_group2blockaddr(sb, 0,
-	    bg_ref->index);
-	uint32_t reserved = ext4_filesystem_bg_get_backup_blocks(bg_ref);
-
-	return base_addr + reserved;
+		return ext4_filesystem_blockaddr2_index_in_group(sb, r);
+	}
+
+	uint64_t bbmap = ext4_block_group_get_block_bitmap(bg_ref->block_group,
+	    sb);
+	uint64_t ibmap = ext4_block_group_get_inode_bitmap(bg_ref->block_group,
+	    sb);
+
+	r = ext4_filesystem_index_in_group2blockaddr(sb, 0, bg_ref->index);
+	r += ext4_filesystem_bg_get_backup_blocks(bg_ref);
+
+	if (ext4_filesystem_blockaddr2group(sb, bbmap) != bg_ref->index)
+		bbmap = -1; /* Invalid */
+
+	if (ext4_filesystem_blockaddr2group(sb, ibmap) != bg_ref->index)
+		ibmap = -1;
+
+	while (true) {
+		if (r == bbmap || r == ibmap)
+			r++;
+		else if (r >= itable && r < (itable + itable_sz))
+			r = itable + itable_sz;
+		else
+			break;
+	}
+
+	return r;
 }
 
Index: uspace/lib/ext4/src/filesystem.c
===================================================================
--- uspace/lib/ext4/src/filesystem.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/src/filesystem.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -421,5 +421,4 @@
     enum cache_mode cmode, aoff64_t *size, ext4_filesystem_t **rfs)
 {
-	int fs_inited = 0;
 	ext4_filesystem_t *fs = NULL;
 	fs_node_t *root_node = NULL;
@@ -438,6 +437,4 @@
 	if (rc != EOK)
 		goto error;
-
-	fs_inited = 1;
 
 	/* Read root node */
@@ -466,7 +463,9 @@
 		ext4_node_put(root_node);
 
-	if (fs_inited)
+	if (fs != NULL) {
 		ext4_filesystem_fini(fs);
-	free(fs);
+		free(fs);
+	}
+
 	return rc;
 }
@@ -715,4 +714,6 @@
 		/* One for block bitmap one for inode bitmap */
 		free_blocks = free_blocks - reserved - 2 - inode_table_blocks;
+		if (bg_index == 0)
+			++free_blocks; /* XXX Why? */
 
 		ext4_block_group_set_free_blocks_count(bg_ref->block_group,
Index: uspace/lib/ext4/src/ialloc.c
===================================================================
--- uspace/lib/ext4/src/ialloc.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/src/ialloc.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -176,16 +176,10 @@
 errno_t ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir)
 {
-	int pick_first_free = 0;
 	ext4_superblock_t *sb = fs->superblock;
-	uint32_t bgid;
-	uint32_t sb_free_inodes;
-	uint32_t avg_free_inodes;
-	uint32_t const bg_count = ext4_superblock_get_block_group_count(sb);
-
-retry:
-
-	bgid = 0;
-	sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
-	avg_free_inodes = sb_free_inodes / bg_count;
+
+	uint32_t bgid = 0;
+	uint32_t bg_count = ext4_superblock_get_block_group_count(sb);
+	uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb);
+	uint32_t avg_free_inodes = sb_free_inodes / bg_count;
 
 	/* Try to find free i-node in all block groups */
@@ -216,6 +210,6 @@
 		 * blocks.
 		 */
-		if (((free_inodes >= avg_free_inodes) ||
-		    (bgid == bg_count - 1) || pick_first_free) && (free_blocks > 0)) {
+		if (((free_inodes >= avg_free_inodes) || (bgid == bg_count - 1)) &&
+		    (free_blocks > 0)) {
 			/* Load block with bitmap */
 			uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(
@@ -313,10 +307,4 @@
 	}
 
-	/* Try again with less strict conditions */
-	if (pick_first_free == 0) {
-		pick_first_free = 1;
-		goto retry;
-	}
-
 	return ENOSPC;
 }
Index: uspace/lib/ext4/src/superblock.c
===================================================================
--- uspace/lib/ext4/src/superblock.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ext4/src/superblock.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -1315,12 +1315,10 @@
 	    ext4_superblock_get_blocks_per_group(sb);
 	uint64_t total_blocks =
-	    ext4_superblock_get_blocks_count(sb);
-	uint32_t first_block =
-	    ext4_superblock_get_first_data_block(sb);
+	    ext4_superblock_get_blocks_count(sb) - 1;
 
 	if (bgid < block_group_count - 1)
 		return blocks_per_group;
 	else
-		return (total_blocks - ((block_group_count - 1) * blocks_per_group)) - first_block;
+		return (total_blocks - ((block_group_count - 1) * blocks_per_group));
 }
 
@@ -1394,15 +1392,4 @@
 {
 	sb->reserved_gdt_blocks = host2uint32_t_le(n);
-}
-
-/** Get the size of the flex groups
- *
- * @param sb	Pointer to the superblock
- *
- * @return	Size of the flex groups
- */
-uint32_t ext4_superblock_get_flex_group_size(ext4_superblock_t *sb)
-{
-	return 2 << sb->log_groups_per_flex;
 }
 
@@ -1478,4 +1465,12 @@
 		 */
 
+		if (idx == 0 && block_size == 1024) {
+			/*
+			 * Special case for first group were the boot block
+			 * resides
+			 */
+			r++;
+		}
+
 		/* This accounts for the superblock */
 		r++;
@@ -1510,5 +1505,5 @@
 	uuid_t uuid;
 	uint32_t cur_ts;
-	uint64_t first_block = 0;
+	uint64_t first_block;
 	uint64_t fs_blocks;
 	uint32_t blocks_count;
@@ -1523,5 +1518,4 @@
 	uint32_t idx;
 	size_t fs_bsize;
-	size_t fs_bsize_log;
 	errno_t rc;
 	struct timespec ts;
@@ -1539,22 +1533,6 @@
 	cur_ts = ts.tv_sec;
 
-	fs_bsize = cfg->bsize;
-	switch (fs_bsize) {
-	case 1024:
-		first_block = 1;
-		fs_bsize_log = 0;
-		blocks_group = 8192;
-		break;
-	case 2048:
-		fs_bsize_log = 1;
-		blocks_group = 8192 * 2;
-		break;
-	case 4096:
-		fs_bsize_log = 2;
-		blocks_group = 8192 * 4;
-		break;
-	default:
-		return ENOTSUP;
-	}
+	fs_bsize = 1024;
+	first_block = 1; /* 1 for 1k block size, 0 otherwise */
 
 	if (fs_bsize % dev_bsize == 0) {
@@ -1565,4 +1543,7 @@
 		fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
 	}
+
+	/* FS blocks per group */
+	blocks_group = 8 * fs_bsize;
 
 	/* Inodes per group */
@@ -1600,7 +1581,8 @@
 	ext4_superblock_set_free_inodes_count(sb, inodes_count);
 	ext4_superblock_set_first_data_block(sb, first_block);
-	ext4_superblock_set_log_block_size(sb, fs_bsize_log);
+	/* Block size will be 1024 bytes */
+	ext4_superblock_set_log_block_size(sb, 0);
 	/* Fragment size should be equal to block size */
-	ext4_superblock_set_log_frag_size(sb, fs_bsize_log);
+	ext4_superblock_set_log_frag_size(sb, 0);
 	ext4_superblock_set_blocks_per_group(sb, blocks_group);
 	/* Should be the same as blocks per group. */
@@ -1652,4 +1634,5 @@
 	/* Compute free blocks */
 	free_blocks = blocks_count;
+	++free_blocks; // XXX Why?
 	for (idx = 0; idx < ngroups; idx++) {
 		free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
Index: uspace/lib/ieee80211/src/ieee80211.c
===================================================================
--- uspace/lib/ieee80211/src/ieee80211.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/lib/ieee80211/src/ieee80211.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -803,5 +803,4 @@
 	if (rc != EOK) {
 		ddf_fun_unbind(fun);
-		ddf_fun_destroy(fun);
 		return rc;
 	}
@@ -810,5 +809,4 @@
 	if (rc != EOK) {
 		ddf_fun_unbind(fun);
-		ddf_fun_destroy(fun);
 		return rc;
 	}
Index: uspace/srv/audio/hound/hound.c
===================================================================
--- uspace/srv/audio/hound/hound.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/srv/audio/hound/hound.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -146,5 +146,4 @@
 static void hound_remove_source_internal(hound_t *hound, audio_source_t *source)
 {
-	assert(fibril_mutex_is_locked(&hound->list_guard));
 	log_verbose("Removing source '%s'.", source->name);
 	if (!list_empty(&source->connections))
Index: uspace/srv/hid/compositor/compositor.c
===================================================================
--- uspace/srv/hid/compositor/compositor.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/srv/hid/compositor/compositor.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -224,5 +224,4 @@
 
 	link_initialize(&win->link);
-	/* One initial reference will be for being in the window list */
 	refcount_init(&win->ref_cnt);
 	prodcons_initialize(&win->queue);
@@ -242,8 +241,5 @@
 static void window_destroy(window_t *win)
 {
-	if (win == NULL)
-		return;
-
-	if (!refcount_down(&win->ref_cnt))
+	if (!win || !refcount_down(&win->ref_cnt))
 		return;
 
@@ -895,7 +891,4 @@
 		    0, 0, width, height, win->transform, &x, &y, &width, &height);
 	}
-
-	/* Down refcount for removing from the window list */
-	window_destroy(win);
 
 	comp_damage(x, y, width, height);
Index: uspace/srv/locsrv/locsrv.c
===================================================================
--- uspace/srv/locsrv/locsrv.c	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ uspace/srv/locsrv/locsrv.c	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -1387,7 +1387,4 @@
 	categ_dir_add_cat(&cdir, cat);
 
-	cat = category_new("printer-port");
-	categ_dir_add_cat(&cdir, cat);
-
 	return true;
 }
Index: version
===================================================================
--- version	(revision 59564e6d329e6a3146eea28acf2e3f71d2272a65)
+++ version	(revision cb15b49c1b1435f2f8f4b04d58fe1e1e8c4d65dd)
@@ -36,6 +36,6 @@
 
 VERSION = 0
-PATCHLEVEL = 8
-SUBLEVEL = 0
+PATCHLEVEL = 7
+SUBLEVEL = 2
 
 ifdef EXTRAVERSION
@@ -45,4 +45,4 @@
 endif
 
-NAME = Speranza
+NAME = Boosted Effort
 COPYRIGHT = Copyright (c) 2001-2018 HelenOS project
