Index: uspace/srv/devman/main.c
===================================================================
--- uspace/srv/devman/main.c	(revision 1a5b2521ea58a25aa1f13d0850fa06ae93fba965)
+++ 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,
