Index: uspace/srv/devman/devman.c
===================================================================
--- uspace/srv/devman/devman.c	(revision 5f6e25e31dad65ed596bf61da69a51ec21c54ec7)
+++ uspace/srv/devman/devman.c	(revision 58cbb0c86e6e40ca0b0b443214cf46d039d9e648)
@@ -30,4 +30,23 @@
  * @{
  */
+/** @file Device Manager
+ *
+ * Locking order:
+ *   (1) driver_t.driver_mutex
+ *   (2) dev_tree_t.rwlock
+ *
+ * Synchronization:
+ *    - device_tree.rwlock protects:
+ *        - tree root, complete tree topology
+ *        - complete contents of device and function nodes
+ *    - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from
+ *      being deallocated
+ *    - find_xxx() functions increase reference count of returned object
+ *    - find_xxx_no_lock() do not increase reference count
+ *
+ * TODO
+ *    - Track all steady and transient device/function states
+ *    - Check states, wait for steady state on certain operations
+ */
 
 #include <errno.h>
@@ -43,5 +62,5 @@
 #include "devman.h"
 
-fun_node_t *find_node_child(fun_node_t *parent, const char *name);
+static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *);
 
 /* hash table operations */
@@ -406,5 +425,7 @@
 	}
 	
+	fun_add_ref(fun);
 	insert_fun_node(tree, fun, str_dup(""), NULL);
+	
 	match_id_t *id = create_match_id();
 	id->id = str_dup("root");
@@ -422,4 +443,5 @@
 	}
 	
+	dev_add_ref(dev);
 	insert_dev_node(tree, dev, fun);
 	
@@ -467,8 +489,9 @@
 /** Assign a driver to a device.
  *
+ * @param tree		Device tree
  * @param node		The device's node in the device tree.
  * @param drv		The driver.
  */
-void attach_driver(dev_node_t *dev, driver_t *drv)
+void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
 {
 	log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
@@ -476,8 +499,10 @@
 	
 	fibril_mutex_lock(&drv->driver_mutex);
+	fibril_rwlock_write_lock(&tree->rwlock);
 	
 	dev->drv = drv;
 	list_append(&dev->driver_devices, &drv->devices);
 	
+	fibril_rwlock_write_unlock(&tree->rwlock);
 	fibril_mutex_unlock(&drv->driver_mutex);
 }
@@ -485,21 +510,24 @@
 /** Detach driver from device.
  *
+ * @param tree		Device tree
  * @param node		The device's node in the device tree.
  * @param drv		The driver.
  */
-void detach_driver(dev_node_t *dev)
-{
-	/* XXX need lock on dev */
+void detach_driver(dev_tree_t *tree, dev_node_t *dev)
+{
 	driver_t *drv = dev->drv;
 	
 	assert(drv != NULL);
+	
 	log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
 	    dev->pfun->pathname, drv->name);
 	
 	fibril_mutex_lock(&drv->driver_mutex);
+	fibril_rwlock_write_lock(&tree->rwlock);
 	
 	dev->drv = NULL;
 	list_remove(&dev->driver_devices);
 	
+	fibril_rwlock_write_unlock(&tree->rwlock);
 	fibril_mutex_unlock(&drv->driver_mutex);
 }
@@ -578,14 +606,15 @@
 	while (link != &driver->devices.head) {
 		dev = list_get_instance(link, dev_node_t, driver_devices);
+		fibril_rwlock_write_lock(&tree->rwlock);
+		
 		if (dev->passed_to_driver) {
+			fibril_rwlock_write_unlock(&tree->rwlock);
 			link = link->next;
 			continue;
 		}
 
-		/*
-		 * We remove the device from the list to allow safe adding
-		 * of new devices (no one will touch our item this way).
-		 */
-		list_remove(link);
+		log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
+		    (int)atomic_get(&dev->refcnt));
+		dev_add_ref(dev);
 
 		/*
@@ -594,6 +623,9 @@
 		 */
 		fibril_mutex_unlock(&driver->driver_mutex);
+		fibril_rwlock_write_unlock(&tree->rwlock);
 
 		add_device(driver, dev, tree);
+
+		dev_del_ref(dev);
 
 		/*
@@ -602,11 +634,4 @@
 		 */
 		fibril_mutex_lock(&driver->driver_mutex);
-
-		/*
-		 * Insert the device back.
-		 * The order is not relevant here so no harm is done
-		 * (actually, the order would be preserved in most cases).
-		 */
-		list_append(link, &driver->devices);
 
 		/*
@@ -701,4 +726,6 @@
 	char *loc_name = NULL;
 	
+	assert(fibril_rwlock_is_locked(&tree->rwlock));
+	
 	asprintf(&loc_name, "%s", fun->pathname);
 	if (loc_name == NULL)
@@ -805,5 +832,5 @@
 	
 	/* Attach the driver to the device. */
-	attach_driver(dev, drv);
+	attach_driver(tree, dev, drv);
 	
 	fibril_mutex_lock(&drv->driver_mutex);
@@ -822,16 +849,22 @@
 }
 
-int driver_dev_remove(dev_node_t *dev)
+int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev)
 {
 	async_exch_t *exch;
 	sysarg_t retval;
 	driver_t *drv;
+	devman_handle_t handle;
 	
 	assert(dev != NULL);
+	
 	log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
+	
+	fibril_rwlock_read_lock(&tree->rwlock);
 	drv = dev->drv;
+	handle = dev->handle;
+	fibril_rwlock_read_unlock(&tree->rwlock);
 	
 	exch = async_exchange_begin(drv->sess);
-	retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);
+	retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle);
 	async_exchange_end(exch);
 	
@@ -840,20 +873,27 @@
 }
 
-int driver_fun_online(fun_node_t *fun)
+int driver_fun_online(dev_tree_t *tree, fun_node_t *fun)
 {
 	async_exch_t *exch;
 	sysarg_t retval;
 	driver_t *drv;
+	devman_handle_t handle;
 	
 	log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
+
+	fibril_rwlock_read_lock(&tree->rwlock);
+	
 	if (fun->dev == NULL) {
 		/* XXX root function? */
+		fibril_rwlock_read_unlock(&tree->rwlock);
 		return EINVAL;
 	}
 	
 	drv = fun->dev->drv;
+	handle = fun->handle;
+	fibril_rwlock_read_unlock(&tree->rwlock);
 	
 	exch = async_exchange_begin(drv->sess);
-	retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);
+	retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle);
 	loc_exchange_end(exch);
 	
@@ -861,20 +901,26 @@
 }
 
-int driver_fun_offline(fun_node_t *fun)
+int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun)
 {
 	async_exch_t *exch;
 	sysarg_t retval;
 	driver_t *drv;
+	devman_handle_t handle;
 	
 	log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
+
+	fibril_rwlock_read_lock(&tree->rwlock);
 	if (fun->dev == NULL) {
 		/* XXX root function? */
+		fibril_rwlock_read_unlock(&tree->rwlock);
 		return EINVAL;
 	}
 	
 	drv = fun->dev->drv;
+	handle = fun->handle;
+	fibril_rwlock_read_unlock(&tree->rwlock);
 	
 	exch = async_exchange_begin(drv->sess);
-	retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);
+	retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle);
 	loc_exchange_end(exch);
 	
@@ -909,7 +955,12 @@
 	if (!create_root_nodes(tree))
 		return false;
-
+    
 	/* Find suitable driver and start it. */
-	return assign_driver(tree->root_node->child, drivers_list, tree);
+	dev_node_t *rdev = tree->root_node->child;
+	dev_add_ref(rdev);
+	int rc = assign_driver(rdev, drivers_list, tree);
+	dev_del_ref(rdev);
+	
+	return rc;
 }
 
@@ -922,14 +973,16 @@
 dev_node_t *create_dev_node(void)
 {
-	dev_node_t *res = malloc(sizeof(dev_node_t));
-	
-	if (res != NULL) {
-		memset(res, 0, sizeof(dev_node_t));
-		list_initialize(&res->functions);
-		link_initialize(&res->driver_devices);
-		link_initialize(&res->devman_dev);
-	}
-	
-	return res;
+	dev_node_t *dev;
+	
+	dev = calloc(1, sizeof(dev_node_t));
+	if (dev == NULL)
+		return NULL;
+	
+	atomic_set(&dev->refcnt, 0);
+	list_initialize(&dev->functions);
+	link_initialize(&dev->driver_devices);
+	link_initialize(&dev->devman_dev);
+	
+	return dev;
 }
 
@@ -947,4 +1000,26 @@
 }
 
+/** Increase device node reference count.
+ *
+ * @param dev	Device node
+ */
+void dev_add_ref(dev_node_t *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+
+/** Decrease device node reference count.
+ *
+ * When the count drops to zero the device node is freed.
+ *
+ * @param dev	Device node
+ */
+void dev_del_ref(dev_node_t *dev)
+{
+	if (atomic_predec(&dev->refcnt) == 0)
+		delete_dev_node(dev);
+}
+
+
 /** Find the device node structure of the device witch has the specified handle.
  *
@@ -976,4 +1051,7 @@
 	fibril_rwlock_read_lock(&tree->rwlock);
 	dev = find_dev_node_no_lock(tree, handle);
+	if (dev != NULL)
+		dev_add_ref(dev);
+	
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
@@ -1003,6 +1081,8 @@
 		    list_get_instance(item, fun_node_t, dev_functions);
 
-		if (pos < buf_cnt)
+		if (pos < buf_cnt) {
 			hdl_buf[pos] = fun->handle;
+		}
+
 		pos++;
 	}
@@ -1020,15 +1100,17 @@
 fun_node_t *create_fun_node(void)
 {
-	fun_node_t *res = malloc(sizeof(fun_node_t));
-	
-	if (res != NULL) {
-		memset(res, 0, sizeof(fun_node_t));
-		link_initialize(&res->dev_functions);
-		list_initialize(&res->match_ids.ids);
-		link_initialize(&res->devman_fun);
-		link_initialize(&res->loc_fun);
-	}
-	
-	return res;
+	fun_node_t *fun;
+
+	fun = calloc(1, sizeof(fun_node_t));
+	if (fun == NULL)
+		return NULL;
+	
+	atomic_set(&fun->refcnt, 0);
+	link_initialize(&fun->dev_functions);
+	list_initialize(&fun->match_ids.ids);
+	link_initialize(&fun->devman_fun);
+	link_initialize(&fun->loc_fun);
+	
+	return fun;
 }
 
@@ -1048,4 +1130,25 @@
 }
 
+/** Increase function node reference count.
+ *
+ * @param fun	Function node
+ */
+void fun_add_ref(fun_node_t *fun)
+{
+	atomic_inc(&fun->refcnt);
+}
+
+/** Decrease function node reference count.
+ *
+ * When the count drops to zero the function node is freed.
+ *
+ * @param fun	Function node
+ */
+void fun_del_ref(fun_node_t *fun)
+{
+	if (atomic_predec(&fun->refcnt) == 0)
+		delete_fun_node(fun);
+}
+
 /** Find the function node with the specified handle.
  *
@@ -1058,4 +1161,5 @@
 	unsigned long key = handle;
 	link_t *link;
+	fun_node_t *fun;
 	
 	assert(fibril_rwlock_is_locked(&tree->rwlock));
@@ -1065,5 +1169,7 @@
 		return NULL;
 	
-	return hash_table_get_instance(link, fun_node_t, devman_fun);
+	fun = hash_table_get_instance(link, fun_node_t, devman_fun);
+	
+	return fun;
 }
 
@@ -1079,5 +1185,9 @@
 	
 	fibril_rwlock_read_lock(&tree->rwlock);
+	
 	fun = find_fun_node_no_lock(tree, handle);
+	if (fun != NULL)
+		fun_add_ref(fun);
+	
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
@@ -1087,4 +1197,5 @@
 /** Create and set device's full path in device tree.
  *
+ * @param tree		Device tree
  * @param node		The device's device node.
  * @param parent	The parent device node.
@@ -1092,6 +1203,7 @@
  *			resources etc.).
  */
-static bool set_fun_path(fun_node_t *fun, fun_node_t *parent)
-{
+static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent)
+{
+	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	assert(fun->name != NULL);
 	
@@ -1120,7 +1232,6 @@
  *
  * @param tree		The device tree.
- * @param node		The newly added device node. 
- * @param dev_name	The name of the newly added device.
- * @param parent	The parent device node.
+ * @param dev		The newly added device node.
+ * @param pfun		The parent function node.
  *
  * @return		True on success, false otherwise (insufficient resources
@@ -1129,6 +1240,4 @@
 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
 {
-	assert(dev != NULL);
-	assert(tree != NULL);
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
@@ -1155,6 +1264,4 @@
 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
 {
-	assert(tree != NULL);
-	assert(dev != NULL);
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
@@ -1174,7 +1281,7 @@
  *
  * @param tree		The device tree.
- * @param node		The newly added function node. 
- * @param dev_name	The name of the newly added function.
- * @param parent	Owning device node.
+ * @param fun		The newly added function node. 
+ * @param fun_name	The name of the newly added function.
+ * @param dev		Owning device node.
  *
  * @return		True on success, false otherwise (insufficient resources
@@ -1186,6 +1293,4 @@
 	fun_node_t *pfun;
 	
-	assert(fun != NULL);
-	assert(tree != NULL);
 	assert(fun_name != NULL);
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
@@ -1198,5 +1303,5 @@
 	
 	fun->name = fun_name;
-	if (!set_fun_path(fun, pfun)) {
+	if (!set_fun_path(tree, fun, pfun)) {
 		return false;
 	}
@@ -1222,6 +1327,4 @@
 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
 {
-	assert(tree != NULL);
-	assert(fun != NULL);
 	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
 	
@@ -1256,4 +1359,5 @@
 	
 	fun_node_t *fun = tree->root_node;
+	fun_add_ref(fun);
 	/*
 	 * Relative path to the function from its parent (but with '/' at the
@@ -1273,5 +1377,7 @@
 		}
 		
-		fun = find_node_child(fun, rel_path + 1);
+		fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1);
+		fun_del_ref(fun);
+		fun = cfun;
 		
 		if (cont) {
@@ -1291,4 +1397,5 @@
  * Device tree rwlock should be held at least for reading.
  *
+ * @param tree Device tree
  * @param dev Device the function belongs to.
  * @param name Function name (not path).
@@ -1296,8 +1403,9 @@
  * @retval NULL No function with given name.
  */
-fun_node_t *find_fun_node_in_device(dev_node_t *dev, const char *name)
-{
-	assert(dev != NULL);
+fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev,
+    const char *name)
+{
 	assert(name != NULL);
+	assert(fibril_rwlock_is_locked(&tree->rwlock));
 
 	fun_node_t *fun;
@@ -1306,6 +1414,8 @@
 		fun = list_get_instance(link, fun_node_t, dev_functions);
 
-		if (str_cmp(name, fun->name) == 0)
+		if (str_cmp(name, fun->name) == 0) {
+			fun_add_ref(fun);
 			return fun;
+		}
 	}
 
@@ -1317,11 +1427,13 @@
  * Device tree rwlock should be held at least for reading.
  *
+ * @param tree		Device tree
  * @param parent	The parent function node.
  * @param name		The name of the child function.
  * @return		The child function node.
  */
-fun_node_t *find_node_child(fun_node_t *pfun, const char *name)
-{
-	return find_fun_node_in_device(pfun->child, name);
+static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun,
+    const char *name)
+{
+	return find_fun_node_in_device(tree, pfun->child, name);
 }
 
@@ -1336,6 +1448,8 @@
 	fibril_rwlock_read_lock(&tree->rwlock);
 	link = hash_table_find(&tree->loc_functions, &key);
-	if (link != NULL)
+	if (link != NULL) {
 		fun = hash_table_get_instance(link, fun_node_t, loc_fun);
+		fun_add_ref(fun);
+	}
 	fibril_rwlock_read_unlock(&tree->rwlock);
 	
@@ -1345,8 +1459,8 @@
 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun)
 {
+	assert(fibril_rwlock_is_write_locked(&tree->rwlock));
+	
 	unsigned long key = (unsigned long) fun->service_id;
-	fibril_rwlock_write_lock(&tree->rwlock);
 	hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
-	fibril_rwlock_write_unlock(&tree->rwlock);
 }
 
Index: uspace/srv/devman/devman.h
===================================================================
--- uspace/srv/devman/devman.h	(revision 5f6e25e31dad65ed596bf61da69a51ec21c54ec7)
+++ uspace/srv/devman/devman.h	(revision 58cbb0c86e6e40ca0b0b443214cf46d039d9e648)
@@ -128,4 +128,7 @@
 /** Device node in the device tree. */
 struct dev_node {
+	/** Reference count */
+	atomic_t refcnt;
+	
 	/** The global unique identifier of the device. */
 	devman_handle_t handle;
@@ -156,4 +159,7 @@
 /** Function node in the device tree. */
 struct fun_node {
+	/** Reference count */
+	atomic_t refcnt;
+	
 	/** The global unique identifier of the function */
 	devman_handle_t handle;
@@ -239,11 +245,11 @@
 
 extern void add_driver(driver_list_t *, driver_t *);
-extern void attach_driver(dev_node_t *, driver_t *);
-extern void detach_driver(dev_node_t *);
+extern void attach_driver(dev_tree_t *, dev_node_t *, driver_t *);
+extern void detach_driver(dev_tree_t *, dev_node_t *);
 extern void add_device(driver_t *, dev_node_t *, dev_tree_t *);
 extern bool start_driver(driver_t *);
-extern int driver_dev_remove(dev_node_t *);
-extern int driver_fun_online(fun_node_t *);
-extern int driver_fun_offline(fun_node_t *);
+extern int driver_dev_remove(dev_tree_t *, dev_node_t *);
+extern int driver_fun_online(dev_tree_t *, fun_node_t *);
+extern int driver_fun_offline(dev_tree_t *, fun_node_t *);
 
 extern driver_t *find_driver(driver_list_t *, const char *);
@@ -258,4 +264,6 @@
 extern dev_node_t *create_dev_node(void);
 extern void delete_dev_node(dev_node_t *node);
+extern void dev_add_ref(dev_node_t *);
+extern void dev_del_ref(dev_node_t *);
 extern dev_node_t *find_dev_node_no_lock(dev_tree_t *tree,
     devman_handle_t handle);
@@ -267,9 +275,12 @@
 extern fun_node_t *create_fun_node(void);
 extern void delete_fun_node(fun_node_t *);
+extern void fun_add_ref(fun_node_t *);
+extern void fun_del_ref(fun_node_t *);
 extern fun_node_t *find_fun_node_no_lock(dev_tree_t *tree,
     devman_handle_t handle);
 extern fun_node_t *find_fun_node(dev_tree_t *tree, devman_handle_t handle);
 extern fun_node_t *find_fun_node_by_path(dev_tree_t *, char *);
-extern fun_node_t *find_fun_node_in_device(dev_node_t *, const char *);
+extern fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *,
+    const char *);
 
 /* Device tree */
Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 5f6e25e31dad65ed596bf61da69a51ec21c54ec7)
+++ uspace/srv/devman/main.c	(revision 58cbb0c86e6e40ca0b0b443214cf46d039d9e648)
@@ -242,17 +242,15 @@
 	
 	fibril_rwlock_write_lock(&device_tree.rwlock);
-	
+
 	if (fun->ftype == fun_inner) {
 		dev = create_dev_node();
 		if (dev == NULL) {
 			fibril_rwlock_write_unlock(&device_tree.rwlock);
-			delete_fun_node(fun);
 			return ENOMEM;
 		}
 
 		insert_dev_node(&device_tree, dev, fun);
-	}
-	
-	fibril_rwlock_write_unlock(&device_tree.rwlock);
+		dev_add_ref(dev);
+	}
 	
 	log_msg(LVL_DEBUG, "devman_add_function(fun=\"%s\")", fun->pathname);
@@ -283,4 +281,6 @@
 	}
 	
+	fibril_rwlock_write_unlock(&device_tree.rwlock);
+	
 	return EOK;
 }
@@ -289,4 +289,6 @@
 {
 	int rc;
+	
+	fibril_rwlock_write_lock(&device_tree.rwlock);
 	
 	if (fun->ftype == fun_inner) {
@@ -296,13 +298,22 @@
 			dev_node_t *dev = fun->child;
 			
-			rc = driver_dev_remove(dev);
+			dev_add_ref(dev);
+			fibril_rwlock_write_unlock(&device_tree.rwlock);
+			
+			rc = driver_dev_remove(&device_tree, dev);
 			if (rc != EOK) {
+				dev_del_ref(dev);
 				return ENOTSUP;
 			}
-			detach_driver(dev);
+			
+			detach_driver(&device_tree, dev);
+			
 			fibril_rwlock_write_lock(&device_tree.rwlock);
 			remove_dev_node(&device_tree, dev);
-			fibril_rwlock_write_unlock(&device_tree.rwlock);
-			delete_dev_node(dev);
+			
+			/* Delete ref created when node was inserted */
+			dev_del_ref(dev);
+			/* Delete ref created by dev_add_ref(dev) above */
+			dev_del_ref(dev);
 		}
 	} else {
@@ -310,4 +321,5 @@
 		rc = loc_service_unregister(fun->service_id);
 		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&device_tree.rwlock);
 			log_msg(LVL_ERROR, "Failed unregistering tree service.");
 			return EIO;
@@ -317,4 +329,6 @@
 	}
 	
+	fibril_rwlock_write_unlock(&device_tree.rwlock);
+	
 	return EOK;
 }
@@ -331,10 +345,6 @@
 	dev_tree_t *tree = &device_tree;
 	
-	fibril_rwlock_write_lock(&tree->rwlock);
-
-	dev_node_t *pdev = find_dev_node_no_lock(&device_tree, dev_handle);
-	
+	dev_node_t *pdev = find_dev_node(&device_tree, dev_handle);
 	if (pdev == NULL) {
-		fibril_rwlock_write_unlock(&tree->rwlock);
 		async_answer_0(callid, ENOENT);
 		return;
@@ -347,5 +357,5 @@
 		    (int) ftype);
 
-		fibril_rwlock_write_unlock(&tree->rwlock);
+		dev_del_ref(pdev);
 		async_answer_0(callid, EINVAL);
 		return;
@@ -355,12 +365,15 @@
 	int rc = async_data_write_accept((void **)&fun_name, true, 0, 0, 0, 0);
 	if (rc != EOK) {
+		dev_del_ref(pdev);
+		async_answer_0(callid, rc);
+		return;
+	}
+	
+	fibril_rwlock_write_lock(&tree->rwlock);
+	
+	/* Check that function with same name is not there already. */
+	if (find_fun_node_in_device(tree, pdev, fun_name) != NULL) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
-		async_answer_0(callid, rc);
-		return;
-	}
-	
-	/* Check that function with same name is not there already. */
-	if (find_fun_node_in_device(pdev, fun_name) != NULL) {
-		fibril_rwlock_write_unlock(&tree->rwlock);
+		dev_del_ref(pdev);
 		async_answer_0(callid, EEXISTS);
 		printf(NAME ": Warning, driver tried to register `%s' twice.\n",
@@ -371,8 +384,10 @@
 	
 	fun_node_t *fun = create_fun_node();
+	fun_add_ref(fun);
 	fun->ftype = ftype;
 	
 	if (!insert_fun_node(&device_tree, fun, fun_name, pdev)) {
 		fibril_rwlock_write_unlock(&tree->rwlock);
+		dev_del_ref(pdev);
 		delete_fun_node(fun);
 		async_answer_0(callid, ENOMEM);
@@ -381,4 +396,5 @@
 	
 	fibril_rwlock_write_unlock(&tree->rwlock);
+	dev_del_ref(pdev);
 	
 	devman_receive_match_ids(match_count, &fun->match_ids);
@@ -408,5 +424,5 @@
 		async_answer_0(callid, rc);
 		return;
-	}	
+	}
 	
 	fun_node_t *fun = find_fun_node(&device_tree, handle);
@@ -415,4 +431,6 @@
 		return;
 	}
+	
+	fibril_rwlock_read_lock(&device_tree.rwlock);
 	
 	rc = loc_category_get_id(cat_name, &cat_id, IPC_FLAG_BLOCKING);
@@ -427,4 +445,7 @@
 	    fun->pathname, cat_name);
 
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
+	fun_del_ref(fun);
+
 	async_answer_0(callid, EOK);
 }
@@ -440,19 +461,28 @@
 
 	printf("devman_drv_fun_online()\n");
-	fibril_rwlock_write_lock(&device_tree.rwlock);
-	fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
-	fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
-	
-	if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
-		async_answer_0(iid, ENOENT);
-		return;
-	}
+	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
+	if (fun == NULL) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
+	fibril_rwlock_read_lock(&device_tree.rwlock);
+	if (fun->dev == NULL || fun->dev->drv != drv) {
+		fibril_rwlock_read_unlock(&device_tree.rwlock);
+		fun_del_ref(fun);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
 	
 	rc = online_function(fun);
 	if (rc != EOK) {
 		printf("devman_drv_fun_online() online_fun->ERROR\n");
+		fun_del_ref(fun);
 		async_answer_0(iid, (sysarg_t) rc);
 		return;
 	}
+	
+	fun_del_ref(fun);
 	printf("devman_drv_fun_online() online_fun->OK\n");
 	
@@ -470,19 +500,26 @@
 	int rc;
 
+	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
+	if (fun == NULL) {
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	
 	fibril_rwlock_write_lock(&device_tree.rwlock);
-	fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
-	fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
-	
-	if (fun == NULL || fun->dev == NULL || fun->dev->drv != drv) {
-		async_answer_0(iid, ENOENT);
-		return;
-	}
+	if (fun->dev == NULL || fun->dev->drv != drv) {
+		fun_del_ref(fun);
+		async_answer_0(iid, ENOENT);
+		return;
+	}
+	fibril_rwlock_write_unlock(&device_tree.rwlock);
 	
 	rc = offline_function(fun);
 	if (rc != EOK) {
+		fun_del_ref(fun);
 		async_answer_0(iid, (sysarg_t) rc);
 		return;
 	}
 	
+	fun_del_ref(fun);
 	async_answer_0(iid, (sysarg_t) EOK);
 }
@@ -495,12 +532,12 @@
 	int rc;
 	
+	
+	fun_node_t *fun = find_fun_node(&device_tree, fun_handle);
+	if (fun == NULL) {
+		async_answer_0(callid, ENOENT);
+		return;
+	}
+	
 	fibril_rwlock_write_lock(&tree->rwlock);
-	
-	fun_node_t *fun = find_fun_node_no_lock(&device_tree, fun_handle);
-	if (fun == NULL) {
-		fibril_rwlock_write_unlock(&tree->rwlock);
-		async_answer_0(callid, ENOENT);
-		return;
-	}
 	
 	log_msg(LVL_DEBUG, "devman_remove_function(fun='%s')", fun->pathname);
@@ -508,5 +545,5 @@
 	if (fun->ftype == fun_inner) {
 		/* Handle possible descendants */
-		/* TODO */
+		/* TODO - This is a surprise removal */
 		if (fun->child != NULL) {
 			log_msg(LVL_WARN, "devman_remove_function(): not handling "
@@ -521,4 +558,5 @@
 				    "service.");
 				fibril_rwlock_write_unlock(&tree->rwlock);
+				fun_del_ref(fun);
 				async_answer_0(callid, EIO);
 				return;
@@ -529,5 +567,9 @@
 	remove_fun_node(&device_tree, fun);
 	fibril_rwlock_write_unlock(&tree->rwlock);
-	delete_fun_node(fun);
+	
+	/* Delete ref added when inserting function into tree */
+	fun_del_ref(fun);
+	/* Delete ref added above when looking up function */
+	fun_del_ref(fun);
 	
 	log_msg(LVL_DEBUG, "devman_remove_function() succeeded.");
@@ -621,4 +663,5 @@
 {
 	char *pathname;
+	devman_handle_t handle;
 	
 	int rc = async_data_write_accept((void **) &pathname, true, 0, 0, 0, 0);
@@ -637,5 +680,12 @@
 	}
 
-	async_answer_1(iid, EOK, fun->handle);
+	fibril_rwlock_read_lock(&device_tree.rwlock);
+	handle = fun->handle;
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
+
+	/* Delete reference created above by find_fun_node_by_path() */
+	fun_del_ref(fun);
+
+	async_answer_1(iid, EOK, handle);
 }
 
@@ -655,4 +705,5 @@
 	if (!async_data_read_receive(&data_callid, &data_len)) {
 		async_answer_0(iid, EINVAL);
+		fun_del_ref(fun);
 		return;
 	}
@@ -662,6 +713,9 @@
 		async_answer_0(data_callid, ENOMEM);
 		async_answer_0(iid, ENOMEM);
-		return;
-	}
+		fun_del_ref(fun);
+		return;
+	}
+
+	fibril_rwlock_read_lock(&device_tree.rwlock);
 
 	size_t sent_length = str_size(fun->name);
@@ -673,4 +727,6 @@
 	async_answer_0(iid, EOK);
 
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
+	fun_del_ref(fun);
 	free(buffer);
 }
@@ -692,4 +748,5 @@
 	if (!async_data_read_receive(&data_callid, &data_len)) {
 		async_answer_0(iid, EINVAL);
+		fun_del_ref(fun);
 		return;
 	}
@@ -699,7 +756,10 @@
 		async_answer_0(data_callid, ENOMEM);
 		async_answer_0(iid, ENOMEM);
-		return;
-	}
-
+		fun_del_ref(fun);
+		return;
+	}
+	
+	fibril_rwlock_read_lock(&device_tree.rwlock);
+	
 	size_t sent_length = str_size(fun->pathname);
 	if (sent_length > data_len) {
@@ -710,4 +770,6 @@
 	async_answer_0(iid, EOK);
 
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
+	fun_del_ref(fun);
 	free(buffer);
 }
@@ -777,4 +839,5 @@
 	
 	if (fun->child == NULL) {
+		fun_del_ref(fun);
 		fibril_rwlock_read_unlock(&device_tree.rwlock);
 		async_answer_0(iid, ENOENT);
@@ -784,4 +847,5 @@
 	async_answer_1(iid, EOK, fun->child->handle);
 	
+	fun_del_ref(fun);
 	fibril_rwlock_read_unlock(&device_tree.rwlock);
 }
@@ -798,8 +862,5 @@
 	int rc;
 
-	fibril_rwlock_write_lock(&device_tree.rwlock);
-	fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
-	fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
-	
+	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
 	if (fun == NULL) {
 		async_answer_0(iid, ENOENT);
@@ -807,5 +868,6 @@
 	}
 	
-	rc = driver_fun_online(fun);
+	rc = driver_fun_online(&device_tree, fun);
+	fun_del_ref(fun);
 	
 	async_answer_0(iid, (sysarg_t) rc);
@@ -825,8 +887,5 @@
 	int rc;
 
-	fibril_rwlock_write_lock(&device_tree.rwlock);
-	fun = find_fun_node_no_lock(&device_tree, IPC_GET_ARG1(*icall));
-	fibril_rwlock_write_unlock(&device_tree.rwlock); /* XXX FIXME */
-	
+	fun = find_fun_node(&device_tree, IPC_GET_ARG1(*icall));
 	if (fun == NULL) {
 		async_answer_0(iid, ENOENT);
@@ -834,5 +893,6 @@
 	}
 	
-	rc = driver_fun_offline(fun);
+	rc = driver_fun_offline(&device_tree, fun);
+	fun_del_ref(fun);
 	
 	async_answer_0(iid, (sysarg_t) rc);
@@ -851,5 +911,8 @@
 	}
 
+	fibril_rwlock_read_lock(&device_tree.rwlock);
 	async_answer_1(iid, EOK, fun->handle);
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
+	fun_del_ref(fun);
 }
 
@@ -909,6 +972,11 @@
 	if (fun == NULL)
 		dev = find_dev_node(&device_tree, handle);
-	else
+	else {
+		fibril_rwlock_read_lock(&device_tree.rwlock);
 		dev = fun->dev;
+		if (dev != NULL)
+			dev_add_ref(dev);
+		fibril_rwlock_read_unlock(&device_tree.rwlock);
+	}
 
 	/*
@@ -922,5 +990,5 @@
 		    "function with handle %" PRIun " was found.", handle);
 		async_answer_0(iid, ENOENT);
-		return;
+		goto cleanup;
 	}
 
@@ -930,5 +998,5 @@
 		    handle);
 		async_answer_0(iid, ENOENT);
-		return;
+		goto cleanup;
 	}
 	
@@ -952,5 +1020,5 @@
 		    "the device %" PRIun " is not in usable state.", handle);
 		async_answer_0(iid, ENOENT);
-		return;
+		goto cleanup;
 	}
 	
@@ -965,5 +1033,5 @@
 		    "Could not forward to driver `%s'.", driver->name);
 		async_answer_0(iid, EINVAL);
-		return;
+		goto cleanup;
 	}
 
@@ -981,4 +1049,10 @@
 	async_forward_fast(iid, exch, method, fwd_h, 0, IPC_FF_NONE);
 	async_exchange_end(exch);
+
+cleanup:
+	if (dev != NULL)
+		dev_del_ref(dev);
+	if (fun != NULL)
+		fun_del_ref(fun);
 }
 
@@ -1000,5 +1074,7 @@
 	}
 	
+	fibril_rwlock_read_lock(&device_tree.rwlock);
 	dev = fun->dev;
+	fun_del_ref(fun);
 	
 	async_exch_t *exch = async_exchange_begin(dev->drv->sess);
@@ -1006,4 +1082,6 @@
 	    IPC_FF_NONE);
 	async_exchange_end(exch);
+	
+	fibril_rwlock_read_unlock(&device_tree.rwlock);
 	
 	log_msg(LVL_DEBUG,
