Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -66,5 +66,6 @@
 #include "ata_bd.h"
 
-#define NAME "ata_bd"
+#define NAME       "ata_bd"
+#define NAMESPACE  "bd"
 
 /** Physical block size. Should be always 512. */
@@ -135,11 +136,10 @@
 		if (disk[i].present == false)
 			continue;
-
-		snprintf(name, 16, "disk%d", i);
+		
+		snprintf(name, 16, "%s/disk%d", NAMESPACE, i);
 		rc = devmap_device_register(name, &disk[i].dev_handle);
 		if (rc != EOK) {
 			devmap_hangup_phone(DEVMAP_DRIVER);
-			printf(NAME ": Unable to register device %s.\n",
-				name);
+			printf(NAME ": Unable to register device %s.\n", name);
 			return rc;
 		}
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -50,5 +50,6 @@
 #include <task.h>
 
-#define NAME "gxe_bd"
+#define NAME       "gxe_bd"
+#define NAMESPACE  "bd"
 
 enum {
@@ -141,10 +142,9 @@
 
 	for (i = 0; i < MAX_DISKS; i++) {
-		snprintf(name, 16, "disk%d", i);
+		snprintf(name, 16, "%s/disk%d", NAMESPACE, i);
 		rc = devmap_device_register(name, &dev_handle[i]);
 		if (rc != EOK) {
 			devmap_hangup_phone(DEVMAP_DRIVER);
-			printf(NAME ": Unable to register device %s.\n",
-				name);
+			printf(NAME ": Unable to register device %s.\n", name);
 			return rc;
 		}
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/bd/rd/rd.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -228,5 +228,5 @@
 	
 	dev_handle_t dev_handle;
-	if (devmap_device_register("initrd", &dev_handle) != EOK) {
+	if (devmap_device_register("bd/initrd", &dev_handle) != EOK) {
 		devmap_hangup_phone(DEVMAP_DRIVER);
 		printf(NAME ": Unable to register device\n");
Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/console/console.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -57,7 +57,6 @@
 #include "screenbuffer.h"
 
-#define NAME  "console"
-
-#define MAX_DEVICE_NAME  32
+#define NAME       "console"
+#define NAMESPACE  "term"
 
 /** Phone to the keyboard driver. */
@@ -69,5 +68,5 @@
 	ipcarg_t cols;  /**< Framebuffer columns */
 	ipcarg_t rows;  /**< Framebuffer rows */
-	int color_cap;	/**< Color capabilities (FB_CCAP_xxx) */
+	int color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
 } fb_info;
 
@@ -740,6 +739,6 @@
 			consoles[i].refcount = 0;
 			
-			char vc[MAX_DEVICE_NAME];
-			snprintf(vc, MAX_DEVICE_NAME, "vc%u", i);
+			char vc[DEVMAP_NAME_MAXLEN + 1];
+			snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%u", NAMESPACE, i);
 			
 			if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/devmap/devmap.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -68,4 +68,18 @@
 } devmap_driver_t;
 
+/** Info about registered namespaces
+ *
+ */
+typedef struct {
+	/** Pointer to the previous and next device in the list of all namespaces */
+	link_t namespaces;
+	/** Unique namespace identifier */
+	dev_handle_t handle;
+	/** Namespace name */
+	char *name;
+	/** Reference count */
+	size_t refcnt;
+} devmap_namespace_t;
+
 /** Info about registered device
  *
@@ -77,6 +91,8 @@
 	    owned by one driver */
 	link_t driver_devices;
-	/** Unique device identifier  */
+	/** Unique device identifier */
 	dev_handle_t handle;
+	/** Device namespace */
+	devmap_namespace_t *namespace;
 	/** Device name */
 	char *name;
@@ -86,4 +102,5 @@
 
 LIST_INITIALIZE(devices_list);
+LIST_INITIALIZE(namespaces_list);
 LIST_INITIALIZE(drivers_list);
 
@@ -117,70 +134,240 @@
 }
 
+/** Convert fully qualified device name to namespace and device name.
+ *
+ * A fully qualified device name can be either a plain device name
+ * (then the namespace is considered to be an empty string) or consist
+ * of two components separated by a slash. No more than one slash
+ * is allowed.
+ *
+ */
+static bool devmap_fqdn_split(const char *fqdn, char **ns_name, char **name)
+{
+	size_t cnt = 0;
+	size_t slash_offset = 0;
+	size_t slash_after = 0;
+	
+	size_t offset = 0;
+	size_t offset_prev = 0;
+	wchar_t c;
+	
+	while ((c = str_decode(fqdn, &offset, STR_NO_LIMIT)) != 0) {
+		if (c == '/') {
+			cnt++;
+			slash_offset = offset_prev;
+			slash_after = offset;
+		}
+		offset_prev = offset;
+	}
+	
+	/* More than one slash */
+	if (cnt > 1)
+		return false;
+	
+	/* No slash -> namespace is empty */
+	if (cnt == 0) {
+		*ns_name = str_dup("");
+		if (*ns_name == NULL)
+			return false;
+		
+		*name = str_dup(fqdn);
+		if ((*name == NULL) || (str_cmp(*name, "") == 0)) {
+			free(*ns_name);
+			return false;
+		}
+		
+		return true;
+	}
+	
+	/* Exactly one slash */
+	*ns_name = str_ndup(fqdn, slash_offset);
+	if (*ns_name == NULL)
+		return false;
+	
+	*name = str_dup(fqdn + slash_after);
+	if ((*name == NULL) || (str_cmp(*name, "") == 0)) {
+		free(*ns_name);
+		return false;
+	}
+	
+	return true;
+}
+
+/** Find namespace with given name.
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static devmap_namespace_t *devmap_namespace_find_name(const char *name)
+{
+	link_t *item = namespaces_list.next;
+	
+	while (item != &namespaces_list) {
+		devmap_namespace_t *namespace = list_get_instance(item, devmap_namespace_t, namespaces);
+		if (str_cmp(namespace->name, name) == 0)
+			return namespace;
+		item = item->next;
+	}
+	
+	return NULL;
+}
+
+/** Find namespace with given handle.
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ * @todo: use hash table
+ *
+ */
+static devmap_namespace_t *devmap_namespace_find_handle(dev_handle_t handle)
+{
+	link_t *item = namespaces_list.next;
+	
+	while (item != &namespaces_list) {
+		devmap_namespace_t *namespace = list_get_instance(item, devmap_namespace_t, namespaces);
+		if (namespace->handle == handle)
+			return namespace;
+		
+		item = item->next;
+	}
+	
+	return NULL;
+}
+
 /** Find device with given name.
  *
- */
-static devmap_device_t *devmap_device_find_name(const char *name)
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static devmap_device_t *devmap_device_find_name(const char *ns_name,
+    const char *name)
 {
 	link_t *item = devices_list.next;
-	devmap_device_t *device = NULL;
 	
 	while (item != &devices_list) {
-		device = list_get_instance(item, devmap_device_t, devices);
-		if (str_cmp(device->name, name) == 0)
-			break;
+		devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
+		if ((str_cmp(device->namespace->name, ns_name) == 0) && (str_cmp(device->name, name) == 0))
+			return device;
 		item = item->next;
 	}
 	
-	if (item == &devices_list)
+	return NULL;
+}
+
+/** Find device with given handle.
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ * @todo: use hash table
+ *
+ */
+static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
+{
+	link_t *item = devices_list.next;
+	
+	while (item != &devices_list) {
+		devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
+		if (device->handle == handle)
+			return device;
+		
+		item = item->next;
+	}
+	
+	return NULL;
+}
+
+/** Create a namespace (if not already present)
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static devmap_namespace_t *devmap_namespace_create(const char *ns_name)
+{
+	devmap_namespace_t *namespace = devmap_namespace_find_name(ns_name);
+	if (namespace != NULL)
+		return namespace;
+	
+	namespace = (devmap_namespace_t *) malloc(sizeof(devmap_namespace_t));
+	if (namespace == NULL)
 		return NULL;
 	
-	device = list_get_instance(item, devmap_device_t, devices);
-	return device;
-}
-
-/** Find device with given handle.
- *
- * @todo: use hash table
- *
- */
-static devmap_device_t *devmap_device_find_handle(dev_handle_t handle)
-{
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	link_t *item = (&devices_list)->next;
-	devmap_device_t *device = NULL;
-	
-	while (item != &devices_list) {
-		device = list_get_instance(item, devmap_device_t, devices);
-		if (device->handle == handle)
-			break;
-		item = item->next;
-	}
-	
-	if (item == &devices_list) {
-		fibril_mutex_unlock(&devices_list_mutex);
+	namespace->name = str_dup(ns_name);
+	if (namespace->name == NULL) {
+		free(namespace);
 		return NULL;
 	}
 	
-	device = list_get_instance(item, devmap_device_t, devices);
-	
-	fibril_mutex_unlock(&devices_list_mutex);
-	
-	return device;
-}
-
-/**
- * Unregister device and free it. It's assumed that driver's device list is
- * already locked.
- */
-static int devmap_device_unregister_core(devmap_device_t *device)
-{
+	namespace->handle = devmap_create_handle();
+	namespace->refcnt = 0;
+	
+	/*
+	 * Insert new namespace into list of registered namespaces
+	 */
+	list_append(&(namespace->namespaces), &namespaces_list);
+	
+	return namespace;
+}
+
+/** Destroy a namespace (if it is no longer needed)
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static void devmap_namespace_destroy(devmap_namespace_t *namespace)
+{
+	if (namespace->refcnt == 0) {
+		list_remove(&(namespace->namespaces));
+		
+		free(namespace->name);
+		free(namespace);
+	}
+}
+
+/** Increase namespace reference count by including device
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static void devmap_namespace_addref(devmap_namespace_t *namespace,
+    devmap_device_t *device)
+{
+	device->namespace = namespace;
+	namespace->refcnt++;
+}
+
+/** Decrease namespace reference count
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static void devmap_namespace_delref(devmap_namespace_t *namespace)
+{
+	namespace->refcnt--;
+	devmap_namespace_destroy(namespace);
+}
+
+/** Unregister device and free it
+ *
+ * The devices_list_mutex should be already held when
+ * calling this function.
+ *
+ */
+static void devmap_device_unregister_core(devmap_device_t *device)
+{
+	devmap_namespace_delref(device->namespace);
 	list_remove(&(device->devices));
 	list_remove(&(device->driver_devices));
 	
+	free(device->namespace);
 	free(device->name);
 	free(device);
-	
-	return EOK;
 }
 
@@ -189,8 +376,6 @@
  * drivers.
  */
-static void devmap_driver_register(devmap_driver_t **odriver)
-{
-	*odriver = NULL;
-	
+static devmap_driver_t *devmap_driver_register(void)
+{
 	ipc_call_t icall;
 	ipc_callid_t iid = async_get_call(&icall);
@@ -198,5 +383,5 @@
 	if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
 		ipc_answer_0(iid, EREFUSED);
-		return;
+		return NULL;
 	}
 	
@@ -205,5 +390,5 @@
 	if (driver == NULL) {
 		ipc_answer_0(iid, ENOMEM);
-		return;
+		return NULL;
 	}
 	
@@ -211,42 +396,10 @@
 	 * Get driver name
 	 */
-	ipc_callid_t callid;
-	size_t name_size;
-	if (!async_data_write_receive(&callid, &name_size)) {
+	int rc = async_data_string_receive(&driver->name, DEVMAP_NAME_MAXLEN);
+	if (rc != EOK) {
 		free(driver);
-		ipc_answer_0(callid, EREFUSED);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (name_size > DEVMAP_NAME_MAXLEN) {
-		free(driver);
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/*
-	 * Allocate buffer for device name.
-	 */
-	driver->name = (char *) malloc(name_size + 1);
-	if (driver->name == NULL) {
-		free(driver);
-		ipc_answer_0(callid, ENOMEM);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/*
-	 * Send confirmation to sender and get data into buffer.
-	 */
-	if (async_data_write_finalize(callid, driver->name, name_size) != EOK) {
-		free(driver->name);
-		free(driver);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	driver->name[name_size] = 0;
+		ipc_answer_0(iid, rc);
+		return NULL;
+	}
 	
 	/* Initialize mutex for list of devices owned by this driver */
@@ -262,5 +415,5 @@
 	 */
 	ipc_call_t call;
-	callid = async_get_call(&call);
+	ipc_callid_t callid = async_get_call(&call);
 	
 	if (IPC_GET_METHOD(call) != IPC_M_CONNECT_TO_ME) {
@@ -270,5 +423,5 @@
 		free(driver);
 		ipc_answer_0(iid, ENOTSUP);
-		return;
+		return NULL;
 	}
 	
@@ -293,5 +446,5 @@
 	ipc_answer_0(iid, EOK);
 	
-	*odriver = driver;
+	return driver;
 }
 
@@ -355,42 +508,43 @@
 	}
 	
-	/* Get device name */
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
+	/* Get fqdn */
+	char *fqdn;
+	int rc = async_data_string_receive(&fqdn, DEVMAP_NAME_MAXLEN);
+	if (rc != EOK) {
 		free(device);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if (size > DEVMAP_NAME_MAXLEN) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	char *ns_name;
+	if (!devmap_fqdn_split(fqdn, &ns_name, &device->name)) {
+		free(fqdn);
 		free(device);
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/* +1 for terminating \0 */
-	device->name = (char *) malloc(size + 1);
-	
-	if (device->name == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	free(fqdn);
+	
+	fibril_mutex_lock(&devices_list_mutex);
+	
+	devmap_namespace_t *namespace = devmap_namespace_create(ns_name);
+	free(ns_name);
+	if (!namespace) {
+		fibril_mutex_unlock(&devices_list_mutex);
 		free(device);
-		ipc_answer_0(callid, ENOMEM);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	async_data_write_finalize(callid, device->name, size);
-	device->name[size] = 0;
+		ipc_answer_0(iid, ENOMEM);
+		return;
+	}
 	
 	list_initialize(&(device->devices));
 	list_initialize(&(device->driver_devices));
 	
-	fibril_mutex_lock(&devices_list_mutex);
-	
-	/* Check that device with such name is not already registered */
-	if (NULL != devmap_device_find_name(device->name)) {
-		printf(NAME ": Device '%s' already registered\n", device->name);
+	/* Check that device is not already registered */
+	if (devmap_device_find_name(namespace->name, device->name) != NULL) {
+		printf(NAME ": Device '%s/%s' already registered\n", device->namespace, device->name);
+		devmap_namespace_destroy(namespace);
 		fibril_mutex_unlock(&devices_list_mutex);
+		free(device->namespace);
 		free(device->name);
 		free(device);
@@ -402,4 +556,5 @@
 	device->handle = devmap_create_handle();
 	
+	devmap_namespace_addref(namespace, device);
 	device->driver = driver;
 	
@@ -437,4 +592,6 @@
 static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
 {
+	fibril_mutex_lock(&devices_list_mutex);
+	
 	/*
 	 * Get handle from request
@@ -450,4 +607,6 @@
 	ipc_forward_fast(callid, dev->driver->phone, dev->handle,
 	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
+	
+	fibril_mutex_unlock(&devices_list_mutex);
 }
 
@@ -458,53 +617,34 @@
  *
  */
-static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/*
-	 * Wait for incoming message with device name (but do not
-	 * read the name itself until the buffer is allocated).
-	 */
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
-		ipc_answer_0(callid, EREFUSED);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	if ((size < 1) || (size > DEVMAP_NAME_MAXLEN)) {
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/*
-	 * Allocate buffer for device name.
-	 */
-	char *name = (char *) malloc(size + 1);
-	if (name == NULL) {
-		ipc_answer_0(callid, ENOMEM);
-		ipc_answer_0(iid, EREFUSED);
-		return;
-	}
-	
-	/*
-	 * Send confirmation to sender and get data into buffer.
-	 */
-	ipcarg_t retval = async_data_write_finalize(callid, name, size);
-	if (retval != EOK) {
-		ipc_answer_0(iid, EREFUSED);
-		free(name);
-		return;
-	}
-	name[size] = '\0';
+static void devmap_device_get_handle(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *fqdn;
+	
+	/* Get fqdn */
+	int rc = async_data_string_receive(&fqdn, DEVMAP_NAME_MAXLEN);
+	if (rc != EOK) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	char *ns_name;
+	char *name;
+	if (!devmap_fqdn_split(fqdn, &ns_name, &name)) {
+		free(fqdn);
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	free(fqdn);
 	
 	fibril_mutex_lock(&devices_list_mutex);
 	const devmap_device_t *dev;
+	
 recheck:
-
+	
 	/*
 	 * Find device name in the list of known devices.
 	 */
-	dev = devmap_device_find_name(name);
+	dev = devmap_device_find_name(ns_name, name);
 	
 	/*
@@ -520,4 +660,5 @@
 		
 		ipc_answer_0(iid, ENOENT);
+		free(ns_name);
 		free(name);
 		fibril_mutex_unlock(&devices_list_mutex);
@@ -527,51 +668,96 @@
 	
 	ipc_answer_1(iid, EOK, dev->handle);
+	free(ns_name);
 	free(name);
 }
 
-/** Find name of device identified by id and send it to caller.
- *
- */
-static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
-{
-	const devmap_device_t *device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
+/** Find handle for namespace identified by name.
+ *
+ * In answer will be send EOK and device handle in arg1 or a error
+ * code from errno.h.
+ *
+ */
+static void devmap_namespace_get_handle(ipc_callid_t iid, ipc_call_t *icall)
+{
+	char *name;
+	
+	/* Get device name */
+	int rc = async_data_string_receive(&name, DEVMAP_NAME_MAXLEN);
+	if (rc != EOK) {
+		ipc_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_lock(&devices_list_mutex);
+	const devmap_namespace_t *namespace;
+	
+recheck:
 	
 	/*
-	 * Device not found.
+	 * Find namespace name in the list of known namespaces.
 	 */
-	if (device == NULL) {
+	namespace = devmap_namespace_find_name(name);
+	
+	/*
+	 * Namespace was not found.
+	 */
+	if (namespace == NULL) {
+		if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
+			/* Blocking lookup */
+			fibril_condvar_wait(&devices_list_cv,
+			    &devices_list_mutex);
+			goto recheck;
+		}
+		
 		ipc_answer_0(iid, ENOENT);
-		return;
-	}
-	
-	ipc_answer_0(iid, EOK);
-	
-	/* FIXME:
-	 * We have no channel from DEVMAP to client, therefore
-	 * sending must be initiated by client.
-	 *
-	 * size_t name_size = str_size(device->name);
-	 *
-	 * int rc = async_data_write_send(phone, device->name, name_size);
-	 * if (rc != EOK) {
-	 *     async_wait_for(req, NULL);
-	 *     return rc;
-	 * }
-	 */
-	
-	/* TODO: send name in response */
-}
-
-static void devmap_get_count(ipc_callid_t iid, ipc_call_t *icall)
+		free(name);
+		fibril_mutex_unlock(&devices_list_mutex);
+		return;
+	}
+	fibril_mutex_unlock(&devices_list_mutex);
+	
+	ipc_answer_1(iid, EOK, namespace->handle);
+	free(name);
+}
+
+static void devmap_handle_probe(ipc_callid_t iid, ipc_call_t *icall)
 {
 	fibril_mutex_lock(&devices_list_mutex);
-	ipc_answer_1(iid, EOK, list_count(&devices_list));
+	
+	devmap_namespace_t *namespace = devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
+	if (namespace == NULL) {
+		devmap_device_t *dev = devmap_device_find_handle(IPC_GET_ARG1(*icall));
+		if (dev == NULL)
+			ipc_answer_1(iid, EOK, DEV_HANDLE_NONE);
+		else
+			ipc_answer_1(iid, EOK, DEV_HANDLE_DEVICE);
+	} else
+		ipc_answer_1(iid, EOK, DEV_HANDLE_NAMESPACE);
+	
 	fibril_mutex_unlock(&devices_list_mutex);
 }
 
-static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
+static void devmap_get_namespace_count(ipc_callid_t iid, ipc_call_t *icall)
 {
 	fibril_mutex_lock(&devices_list_mutex);
-	
+	ipc_answer_1(iid, EOK, list_count(&namespaces_list));
+	fibril_mutex_unlock(&devices_list_mutex);
+}
+
+static void devmap_get_device_count(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&devices_list_mutex);
+	
+	devmap_namespace_t *namespace = devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
+	if (namespace == NULL)
+		ipc_answer_0(iid, EEXISTS);
+	else
+		ipc_answer_1(iid, EOK, namespace->refcnt);
+	
+	fibril_mutex_unlock(&devices_list_mutex);
+}
+
+static void devmap_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
+{
 	ipc_callid_t callid;
 	size_t size;
@@ -584,9 +770,80 @@
 	if ((size % sizeof(dev_desc_t)) != 0) {
 		ipc_answer_0(callid, EINVAL);
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	fibril_mutex_lock(&devices_list_mutex);
+	
+	size_t count = size / sizeof(dev_desc_t);
+	if (count != list_count(&namespaces_list)) {
+		ipc_answer_0(callid, EOVERFLOW);
+		ipc_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
+	dev_desc_t *desc = (dev_desc_t *) malloc(size);
+	if (desc == NULL) {
+		ipc_answer_0(callid, ENOMEM);
+		ipc_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	link_t *item = namespaces_list.next;
+	size_t pos = 0;
+	while (item != &namespaces_list) {
+		devmap_namespace_t *namespace = list_get_instance(item, devmap_namespace_t, namespaces);
+		
+		desc[pos].handle = namespace->handle;
+		str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, namespace->name);
+		pos++;
+		
+		item = item->next;
+	}
+	
+	ipcarg_t retval = async_data_read_finalize(callid, desc, size);
+	
+	free(desc);
+	fibril_mutex_unlock(&devices_list_mutex);
+	
+	ipc_answer_0(iid, retval);
+}
+
+static void devmap_get_devices(ipc_callid_t iid, ipc_call_t *icall)
+{
+	/* FIXME: Use faster algorithm which can make better use
+	   of namespaces */
+	
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		ipc_answer_0(callid, EREFUSED);
 		ipc_answer_0(iid, EREFUSED);
 		return;
 	}
 	
+	if ((size % sizeof(dev_desc_t)) != 0) {
+		ipc_answer_0(callid, EINVAL);
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+	
+	fibril_mutex_lock(&devices_list_mutex);
+	
+	devmap_namespace_t *namespace = devmap_namespace_find_handle(IPC_GET_ARG1(*icall));
+	if (namespace == NULL) {
+		fibril_mutex_unlock(&devices_list_mutex);
+		ipc_answer_0(callid, ENOENT);
+		ipc_answer_0(iid, ENOENT);
+		return;
+	}
+	
 	size_t count = size / sizeof(dev_desc_t);
+	if (count != namespace->refcnt) {
+		ipc_answer_0(callid, EOVERFLOW);
+		ipc_answer_0(iid, EOVERFLOW);
+		return;
+	}
+	
 	dev_desc_t *desc = (dev_desc_t *) malloc(size);
 	if (desc == NULL) {
@@ -596,28 +853,24 @@
 	}
 	
+	link_t *item = devices_list.next;
 	size_t pos = 0;
-	link_t *item = devices_list.next;
-	
-	while ((item != &devices_list) && (pos < count)) {
+	while (item != &devices_list) {
 		devmap_device_t *device = list_get_instance(item, devmap_device_t, devices);
 		
-		desc[pos].handle = device->handle;
-		str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
-		pos++;
+		if (device->namespace == namespace) {
+			desc[pos].handle = device->handle;
+			str_cpy(desc[pos].name, DEVMAP_NAME_MAXLEN, device->name);
+			pos++;
+		}
+		
 		item = item->next;
 	}
 	
-	ipcarg_t retval = async_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
-	if (retval != EOK) {
-		ipc_answer_0(iid, EREFUSED);
-		free(desc);
-		return;
-	}
+	ipcarg_t retval = async_data_read_finalize(callid, desc, size);
 	
 	free(desc);
-	
 	fibril_mutex_unlock(&devices_list_mutex);
 	
-	ipc_answer_1(iid, EOK, pos);
+	ipc_answer_0(iid, retval);
 }
 
@@ -642,5 +895,14 @@
 	}
 	
-	/* Create NULL device entry */
+	char null[DEVMAP_NAME_MAXLEN];
+	snprintf(null, DEVMAP_NAME_MAXLEN, "%u", i);
+	
+	char *dev_name = str_dup(null);
+	if (dev_name == NULL) {
+		fibril_mutex_unlock(&null_devices_mutex);
+		ipc_answer_0(iid, ENOMEM);
+		return;
+	}
+	
 	devmap_device_t *device = (devmap_device_t *) malloc(sizeof(devmap_device_t));
 	if (device == NULL) {
@@ -650,11 +912,10 @@
 	}
 	
-	char null[DEVMAP_NAME_MAXLEN];
-	snprintf(null, DEVMAP_NAME_MAXLEN, "null%u", i);
-	
-	device->name = str_dup(null);
-	if (device->name == NULL) {
+	fibril_mutex_lock(&devices_list_mutex);
+	
+	devmap_namespace_t *namespace = devmap_namespace_create("null");
+	if (!namespace) {
+		fibril_mutex_lock(&devices_list_mutex);
 		fibril_mutex_unlock(&null_devices_mutex);
-		free(device);
 		ipc_answer_0(iid, ENOMEM);
 		return;
@@ -663,10 +924,11 @@
 	list_initialize(&(device->devices));
 	list_initialize(&(device->driver_devices));
-	
-	fibril_mutex_lock(&devices_list_mutex);
 	
 	/* Get unique device handle */
 	device->handle = devmap_create_handle();
 	device->driver = NULL;
+	
+	devmap_namespace_addref(namespace, device);
+	device->name = dev_name;
 	
 	/* Insert device into list of all devices
@@ -692,5 +954,8 @@
 	}
 	
+	fibril_mutex_lock(&devices_list_mutex);
 	devmap_device_unregister_core(null_devices[i]);
+	fibril_mutex_unlock(&devices_list_mutex);
+	
 	null_devices[i] = NULL;
 	
@@ -725,8 +990,6 @@
 	ipc_answer_0(iid, EOK);
 	
-	devmap_driver_t *driver = NULL;
-	devmap_driver_register(&driver);
-	
-	if (NULL == driver)
+	devmap_driver_t *driver = devmap_driver_register();
+	if (driver == NULL)
 		return;
 	
@@ -755,8 +1018,8 @@
 			break;
 		case DEVMAP_DEVICE_GET_HANDLE:
-			devmap_get_handle(callid, &call);
-			break;
-		case DEVMAP_DEVICE_GET_NAME:
-			devmap_get_name(callid, &call);
+			devmap_device_get_handle(callid, &call);
+			break;
+		case DEVMAP_NAMESPACE_GET_HANDLE:
+			devmap_namespace_get_handle(callid, &call);
 			break;
 		default:
@@ -793,19 +1056,28 @@
 			continue;
 		case DEVMAP_DEVICE_GET_HANDLE:
-			devmap_get_handle(callid, &call);
-			break;
-		case DEVMAP_DEVICE_GET_NAME:
-			devmap_get_name(callid, &call);
-			break;
-		case DEVMAP_DEVICE_NULL_CREATE:
+			devmap_device_get_handle(callid, &call);
+			break;
+		case DEVMAP_NAMESPACE_GET_HANDLE:
+			devmap_namespace_get_handle(callid, &call);
+			break;
+		case DEVMAP_HANDLE_PROBE:
+			devmap_handle_probe(callid, &call);
+			break;
+		case DEVMAP_NULL_CREATE:
 			devmap_null_create(callid, &call);
 			break;
-		case DEVMAP_DEVICE_NULL_DESTROY:
+		case DEVMAP_NULL_DESTROY:
 			devmap_null_destroy(callid, &call);
 			break;
-		case DEVMAP_DEVICE_GET_COUNT:
-			devmap_get_count(callid, &call);
-			break;
-		case DEVMAP_DEVICE_GET_DEVICES:
+		case DEVMAP_GET_NAMESPACE_COUNT:
+			devmap_get_namespace_count(callid, &call);
+			break;
+		case DEVMAP_GET_DEVICE_COUNT:
+			devmap_get_device_count(callid, &call);
+			break;
+		case DEVMAP_GET_NAMESPACES:
+			devmap_get_namespaces(callid, &call);
+			break;
+		case DEVMAP_GET_DEVICES:
 			devmap_get_devices(callid, &call);
 			break;
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -44,9 +44,15 @@
 #include <fibril_synch.h>
 #include <adt/hash_table.h>
+#include <ipc/devmap.h>
 #include <sys/stat.h>
+#include <libfs.h>
+#include <assert.h>
 #include "devfs.h"
 #include "devfs_ops.h"
 
-#define PLB_GET_CHAR(pos)  (devfs_reg.plb_ro[pos % PLB_SIZE])
+typedef struct {
+	devmap_handle_type_t type;
+	dev_handle_t handle;
+} devfs_node_t;
 
 /** Opened devices structure */
@@ -91,4 +97,309 @@
 };
 
+static int devfs_node_get_internal(fs_node_t **rfn, devmap_handle_type_t type,
+    dev_handle_t handle)
+{
+	devfs_node_t *node = (devfs_node_t *) malloc(sizeof(devfs_node_t));
+	if (node == NULL) {
+		*rfn = NULL;
+		return ENOMEM;
+	}
+	
+	*rfn = (fs_node_t *) malloc(sizeof(fs_node_t));
+	if (*rfn == NULL) {
+		free(node);
+		*rfn = NULL;
+		return ENOMEM;
+	}
+	
+	fs_node_initialize(*rfn);
+	node->type = type;
+	node->handle = handle;
+	
+	(*rfn)->data = node;
+	return EOK;
+}
+
+static int devfs_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
+{
+	return devfs_node_get_internal(rfn, DEV_HANDLE_NONE, 0);
+}
+
+static int devfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	devfs_node_t *node = (devfs_node_t *) pfn->data;
+	
+	if (node->handle == 0) {
+		/* Root directory */
+		
+		dev_desc_t *devs;
+		size_t count = devmap_get_namespaces(&devs);
+		
+		if (count > 0) {
+			size_t pos;
+			for (pos = 0; pos < count; pos++) {
+				/* Ignore root namespace */
+				if (str_cmp(devs[pos].name, "") == 0)
+					continue;
+				
+				if (str_cmp(devs[pos].name, component) == 0) {
+					free(devs);
+					return devfs_node_get_internal(rfn, DEV_HANDLE_NAMESPACE, devs[pos].handle);
+				}
+			}
+			
+			free(devs);
+		}
+		
+		/* Search root namespace */
+		dev_handle_t namespace;
+		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
+			count = devmap_get_devices(namespace, &devs);
+			
+			if (count > 0) {
+				size_t pos;
+				for (pos = 0; pos < count; pos++) {
+					if (str_cmp(devs[pos].name, component) == 0) {
+						free(devs);
+						return devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
+					}
+				}
+				
+				free(devs);
+			}
+		}
+		
+		*rfn = NULL;
+		return EOK;
+	}
+	
+	if (node->type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		
+		dev_desc_t *devs;
+		size_t count = devmap_get_devices(node->handle, &devs);
+		if (count > 0) {
+			size_t pos;
+			for (pos = 0; pos < count; pos++) {
+				if (str_cmp(devs[pos].name, component) == 0) {
+					free(devs);
+					return devfs_node_get_internal(rfn, DEV_HANDLE_DEVICE, devs[pos].handle);
+				}
+			}
+			
+			free(devs);
+		}
+		
+		*rfn = NULL;
+		return EOK;
+	}
+	
+	*rfn = NULL;
+	return EOK;
+}
+
+static int devfs_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
+{
+	return devfs_node_get_internal(rfn, devmap_handle_probe(index), index);
+}
+
+static int devfs_node_open(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	if (node->handle == 0) {
+		/* Root directory */
+		return EOK;
+	}
+	
+	devmap_handle_type_t type = devmap_handle_probe(node->handle);
+	
+	if (type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		return EOK;
+	}
+	
+	if (type == DEV_HANDLE_DEVICE) {
+		/* Device node */
+		
+		unsigned long key[] = {
+			[DEVICES_KEY_HANDLE] = (unsigned long) node->handle
+		};
+		
+		fibril_mutex_lock(&devices_mutex);
+		link_t *lnk = hash_table_find(&devices, key);
+		if (lnk == NULL) {
+			device_t *dev = (device_t *) malloc(sizeof(device_t));
+			if (dev == NULL) {
+				fibril_mutex_unlock(&devices_mutex);
+				return ENOMEM;
+			}
+			
+			int phone = devmap_device_connect(node->handle, 0);
+			if (phone < 0) {
+				fibril_mutex_unlock(&devices_mutex);
+				free(dev);
+				return ENOENT;
+			}
+			
+			dev->handle = node->handle;
+			dev->phone = phone;
+			dev->refcount = 1;
+			
+			hash_table_insert(&devices, key, &dev->link);
+		} else {
+			device_t *dev = hash_table_get_instance(lnk, device_t, link);
+			dev->refcount++;
+		}
+		
+		fibril_mutex_unlock(&devices_mutex);
+		
+		return EOK;
+	}
+	
+	return ENOENT;
+}
+
+static int devfs_node_put(fs_node_t *fn)
+{
+	free(fn->data);
+	free(fn);
+	return EOK;
+}
+
+static int devfs_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int lflag)
+{
+	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
+	
+	*rfn = NULL;
+	return ENOTSUP;
+}
+
+static int devfs_destroy_node(fs_node_t *fn)
+{
+	return ENOTSUP;
+}
+
+static int devfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int devfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	return ENOTSUP;
+}
+
+static int devfs_has_children(bool *has_children, fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	if (node->handle == 0) {
+		size_t count = devmap_count_namespaces();
+		if (count > 0) {
+			*has_children = true;
+			return EOK;
+		}
+		
+		/* Root namespace */
+		dev_handle_t namespace;
+		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
+			count = devmap_count_devices(namespace);
+			if (count > 0) {
+				*has_children = true;
+				return EOK;
+			}
+		}
+		
+		*has_children = false;
+		return EOK;
+	}
+	
+	if (node->type == DEV_HANDLE_NAMESPACE) {
+		size_t count = devmap_count_devices(node->handle);
+		if (count > 0) {
+			*has_children = true;
+			return EOK;
+		}
+		
+		*has_children = false;
+		return EOK;
+	}
+	
+	*has_children = false;
+	return EOK;
+}
+
+static fs_index_t devfs_index_get(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	return node->handle;
+}
+
+static size_t devfs_size_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+static unsigned int devfs_lnkcnt_get(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	if (node->handle == 0)
+		return 0;
+	
+	return 1;
+}
+
+static char devfs_plb_get_char(unsigned pos)
+{
+	return devfs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+static bool devfs_is_directory(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	return ((node->type == DEV_HANDLE_NONE) || (node->type == DEV_HANDLE_NAMESPACE));
+}
+
+static bool devfs_is_file(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	return (node->type == DEV_HANDLE_DEVICE);
+}
+
+static dev_handle_t devfs_device_get(fs_node_t *fn)
+{
+	devfs_node_t *node = (devfs_node_t *) fn->data;
+	
+	if (node->type == DEV_HANDLE_DEVICE)
+		return node->handle;
+	
+	return 0;
+}
+
+/** libfs operations */
+libfs_ops_t devfs_libfs_ops = {
+	.root_get = devfs_root_get,
+	.match = devfs_match,
+	.node_get = devfs_node_get,
+	.node_open = devfs_node_open,
+	.node_put = devfs_node_put,
+	.create = devfs_create_node,
+	.destroy = devfs_destroy_node,
+	.link = devfs_link_node,
+	.unlink = devfs_unlink_node,
+	.has_children = devfs_has_children,
+	.index_get = devfs_index_get,
+	.size_get = devfs_size_get,
+	.lnkcnt_get = devfs_lnkcnt_get,
+	.plb_get_char = devfs_plb_get_char,
+	.is_directory = devfs_is_directory,
+	.is_file = devfs_is_file,
+	.device_get = devfs_device_get
+};
+
 bool devfs_init(void)
 {
@@ -105,29 +416,14 @@
 void devfs_mounted(ipc_callid_t rid, ipc_call_t *request)
 {
+	char *opts;
+	
 	/* Accept the mount options */
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_write_receive(&callid, &size)) {
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(rid, EINVAL);
-		return;
-	}
-	
-	char *opts = malloc(size + 1);
-	if (!opts) {
-		ipc_answer_0(callid, ENOMEM);
-		ipc_answer_0(rid, ENOMEM);
-		return;
-	}
-	
-	ipcarg_t retval = async_data_write_finalize(callid, opts, size);
+	ipcarg_t retval = async_data_string_receive(&opts, 0);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
-		free(opts);
 		return;
 	}
 	
 	free(opts);
-	
 	ipc_answer_3(rid, EOK, 0, 0, 0);
 }
@@ -135,194 +431,111 @@
 void devfs_mount(ipc_callid_t rid, ipc_call_t *request)
 {
-	ipc_answer_0(rid, ENOTSUP);
+	libfs_mount(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
 }
 
 void devfs_lookup(ipc_callid_t rid, ipc_call_t *request)
 {
-	ipcarg_t first = IPC_GET_ARG1(*request);
-	ipcarg_t last = IPC_GET_ARG2(*request);
-	dev_handle_t dev_handle = IPC_GET_ARG3(*request);
-	ipcarg_t lflag = IPC_GET_ARG4(*request);
-	fs_index_t index = IPC_GET_ARG5(*request);
-	
-	/* Hierarchy is flat, no altroot is supported */
-	if (index != 0) {
-		ipc_answer_0(rid, ENOENT);
-		return;
-	}
-	
-	if ((lflag & L_LINK) || (lflag & L_UNLINK)) {
-		ipc_answer_0(rid, ENOTSUP);
-		return;
-	}
-	
-	/* Eat slash */
-	if (PLB_GET_CHAR(first) == '/') {
-		first++;
-		first %= PLB_SIZE;
-	}
-	
-	if (first >= last) {
-		/* Root entry */
-		if (!(lflag & L_FILE))
-			ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, 0, 0, 0);
-		else
-			ipc_answer_0(rid, ENOENT);
-	} else {
-		if (!(lflag & L_DIRECTORY)) {
-			size_t len;
-			if (last >= first)
-				len = last - first + 1;
-			else
-				len = first + PLB_SIZE - last + 1;
+	libfs_lookup(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
+}
+
+void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_open_node(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
+}
+
+void devfs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_stat(&devfs_libfs_ops, devfs_reg.fs_handle, rid, request);
+}
+
+void devfs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	off_t pos = (off_t) IPC_GET_ARG3(*request);
+	
+	if (index == 0) {
+		ipc_callid_t callid;
+		size_t size;
+		if (!async_data_read_receive(&callid, &size)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			return;
+		}
+		
+		dev_desc_t *desc;
+		size_t count = devmap_get_namespaces(&desc);
+		
+		/* Get rid of root namespace */
+		size_t i;
+		for (i = 0; i < count; i++) {
+			if (str_cmp(desc[i].name, "") == 0) {
+				if (pos >= i)
+					pos++;
+				
+				break;
+			}
+		}
+		
+		if (pos < count) {
+			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+			free(desc);
+			ipc_answer_1(rid, EOK, 1);
+			return;
+		}
+		
+		free(desc);
+		pos -= count;
+		
+		/* Search root namespace */
+		dev_handle_t namespace;
+		if (devmap_namespace_get_handle("", &namespace, 0) == EOK) {
+			count = devmap_get_devices(namespace, &desc);
 			
-			char *name = (char *) malloc(len + 1);
-			if (name == NULL) {
-				ipc_answer_0(rid, ENOMEM);
+			if (pos < count) {
+				async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+				free(desc);
+				ipc_answer_1(rid, EOK, 1);
 				return;
 			}
 			
-			size_t i;
-			for (i = 0; i < len; i++)
-				name[i] = PLB_GET_CHAR(first + i);
-			
-			name[len] = 0;
-			
-			dev_handle_t handle;
-			if (devmap_device_get_handle(name, &handle, 0) != EOK) {
-				free(name);
-				ipc_answer_0(rid, ENOENT);
-				return;
-			}
-			
-			if (lflag & L_OPEN) {
-				unsigned long key[] = {
-					[DEVICES_KEY_HANDLE] = (unsigned long) handle
-				};
-				
-				fibril_mutex_lock(&devices_mutex);
-				link_t *lnk = hash_table_find(&devices, key);
-				if (lnk == NULL) {
-					int phone = devmap_device_connect(handle, 0);
-					if (phone < 0) {
-						fibril_mutex_unlock(&devices_mutex);
-						free(name);
-						ipc_answer_0(rid, ENOENT);
-						return;
-					}
-					
-					device_t *dev = (device_t *) malloc(sizeof(device_t));
-					if (dev == NULL) {
-						fibril_mutex_unlock(&devices_mutex);
-						free(name);
-						ipc_answer_0(rid, ENOMEM);
-						return;
-					}
-					
-					dev->handle = handle;
-					dev->phone = phone;
-					dev->refcount = 1;
-					
-					hash_table_insert(&devices, key, &dev->link);
-				} else {
-					device_t *dev = hash_table_get_instance(lnk, device_t, link);
-					dev->refcount++;
-				}
-				fibril_mutex_unlock(&devices_mutex);
-			}
-			
-			free(name);
-			
-			ipc_answer_5(rid, EOK, devfs_reg.fs_handle, dev_handle, handle, 0, 1);
-		} else
-			ipc_answer_0(rid, ENOENT);
-	}
-}
-
-void devfs_open_node(ipc_callid_t rid, ipc_call_t *request)
-{
-	dev_handle_t handle = IPC_GET_ARG2(*request);
-	
-	unsigned long key[] = {
-		[DEVICES_KEY_HANDLE] = (unsigned long) handle
-	};
-	
-	fibril_mutex_lock(&devices_mutex);
-	link_t *lnk = hash_table_find(&devices, key);
-	if (lnk == NULL) {
-		int phone = devmap_device_connect(handle, 0);
-		if (phone < 0) {
-			fibril_mutex_unlock(&devices_mutex);
-			ipc_answer_0(rid, ENOENT);
-			return;
-		}
-		
-		device_t *dev = (device_t *) malloc(sizeof(device_t));
-		if (dev == NULL) {
-			fibril_mutex_unlock(&devices_mutex);
-			ipc_answer_0(rid, ENOMEM);
-			return;
-		}
-		
-		dev->handle = handle;
-		dev->phone = phone;
-		dev->refcount = 1;
-		
-		hash_table_insert(&devices, key, &dev->link);
-	} else {
-		device_t *dev = hash_table_get_instance(lnk, device_t, link);
-		dev->refcount++;
-	}
-	fibril_mutex_unlock(&devices_mutex);
-	
-	ipc_answer_3(rid, EOK, 0, 1, L_FILE);
-}
-
-void devfs_stat(ipc_callid_t rid, ipc_call_t *request)
-{
-	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	
-	ipc_callid_t callid;
-	size_t size;
-	if (!async_data_read_receive(&callid, &size) ||
-	    size != sizeof(struct stat)) {
-		ipc_answer_0(callid, EINVAL);
-		ipc_answer_0(rid, EINVAL);
-		return;
-	}
-
-	struct stat stat;
-	memset(&stat, 0, sizeof(struct stat));
-
-	stat.fs_handle = devfs_reg.fs_handle;
-	stat.dev_handle = dev_handle;
-	stat.index = index;
-	stat.lnkcnt = 1;
-	stat.is_file = (index != 0);
-	stat.size = 0;
-	
-	if (index != 0) {
-		unsigned long key[] = {
-			[DEVICES_KEY_HANDLE] = (unsigned long) index
-		};
-		
-		fibril_mutex_lock(&devices_mutex);
-		link_t *lnk = hash_table_find(&devices, key);
-		if (lnk != NULL) 
-			stat.devfs_stat.device = (dev_handle_t)index;
-		fibril_mutex_unlock(&devices_mutex);
-	}
-
-	async_data_read_finalize(callid, &stat, sizeof(struct stat));
-	ipc_answer_0(rid, EOK);
-}
-
-void devfs_read(ipc_callid_t rid, ipc_call_t *request)
-{
-	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
-	off_t pos = (off_t) IPC_GET_ARG3(*request);
-	
-	if (index != 0) {
+			free(desc);
+		}
+		
+		ipc_answer_0(callid, ENOENT);
+		ipc_answer_1(rid, ENOENT, 0);
+		return;
+	}
+	
+	devmap_handle_type_t type = devmap_handle_probe(index);
+	
+	if (type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		ipc_callid_t callid;
+		size_t size;
+		if (!async_data_read_receive(&callid, &size)) {
+			ipc_answer_0(callid, EINVAL);
+			ipc_answer_0(rid, EINVAL);
+			return;
+		}
+		
+		dev_desc_t *desc;
+		size_t count = devmap_get_devices(index, &desc);
+		
+		if (pos < count) {
+			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+			free(desc);
+			ipc_answer_1(rid, EOK, 1);
+			return;
+		}
+		
+		free(desc);
+		ipc_answer_0(callid, ENOENT);
+		ipc_answer_1(rid, ENOENT, 0);
+		return;
+	}
+	
+	if (type == DEV_HANDLE_DEVICE) {
+		/* Device node */
+		
 		unsigned long key[] = {
 			[DEVICES_KEY_HANDLE] = (unsigned long) index
@@ -364,35 +577,8 @@
 		/* Driver reply is the final result of the whole operation */
 		ipc_answer_1(rid, rc, bytes);
-	} else {
-		ipc_callid_t callid;
-		size_t size;
-		if (!async_data_read_receive(&callid, &size)) {
-			ipc_answer_0(callid, EINVAL);
-			ipc_answer_0(rid, EINVAL);
-			return;
-		}
-		
-		size_t count = devmap_device_get_count();
-		dev_desc_t *desc = malloc(count * sizeof(dev_desc_t));
-		if (desc == NULL) {
-			ipc_answer_0(callid, ENOMEM);
-			ipc_answer_1(rid, ENOMEM, 0);
-			return;
-		}
-		
-		size_t max = devmap_device_get_devices(count, desc);
-		
-		if (pos < max) {
-			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
-		} else {
-			ipc_answer_0(callid, ENOENT);
-			ipc_answer_1(rid, ENOENT, 0);
-			return;
-		}
-		
-		free(desc);
-		
-		ipc_answer_1(rid, EOK, 1);
-	}
+		return;
+	}
+	
+	ipc_answer_0(rid, ENOENT);
 }
 
@@ -402,5 +588,19 @@
 	off_t pos = (off_t) IPC_GET_ARG3(*request);
 	
-	if (index != 0) {
+	if (index == 0) {
+		ipc_answer_0(rid, ENOTSUP);
+		return;
+	}
+	
+	devmap_handle_type_t type = devmap_handle_probe(index);
+	
+	if (type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		ipc_answer_0(rid, ENOTSUP);
+		return;
+	}
+	
+	if (type == DEV_HANDLE_DEVICE) {
+		/* Device node */
 		unsigned long key[] = {
 			[DEVICES_KEY_HANDLE] = (unsigned long) index
@@ -443,8 +643,8 @@
 		/* Driver reply is the final result of the whole operation */
 		ipc_answer_1(rid, rc, bytes);
-	} else {
-		/* Read-only filesystem */
-		ipc_answer_0(rid, ENOTSUP);
-	}
+		return;
+	}
+	
+	ipc_answer_0(rid, ENOENT);
 }
 
@@ -458,5 +658,18 @@
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
 	
-	if (index != 0) {
+	if (index == 0) {
+		ipc_answer_0(rid, EOK);
+		return;
+	}
+	
+	devmap_handle_type_t type = devmap_handle_probe(index);
+	
+	if (type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		ipc_answer_0(rid, EOK);
+		return;
+	}
+	
+	if (type == DEV_HANDLE_DEVICE) {
 		unsigned long key[] = {
 			[DEVICES_KEY_HANDLE] = (unsigned long) index
@@ -482,6 +695,8 @@
 		
 		ipc_answer_0(rid, EOK);
-	} else
-		ipc_answer_0(rid, ENOTSUP);
+		return;
+	}
+	
+	ipc_answer_0(rid, ENOENT);
 }
 
@@ -490,5 +705,18 @@
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
 	
-	if (index != 0) {
+	if (index == 0) {
+		ipc_answer_0(rid, EOK);
+		return;
+	}
+	
+	devmap_handle_type_t type = devmap_handle_probe(index);
+	
+	if (type == DEV_HANDLE_NAMESPACE) {
+		/* Namespace directory */
+		ipc_answer_0(rid, EOK);
+		return;
+	}
+	
+	if (type == DEV_HANDLE_DEVICE) {
 		unsigned long key[] = {
 			[DEVICES_KEY_HANDLE] = (unsigned long) index
@@ -518,6 +746,8 @@
 		/* Driver reply is the final result of the whole operation */
 		ipc_answer_0(rid, rc);
-	} else
-		ipc_answer_0(rid, ENOTSUP);
+		return;
+	}
+	
+	ipc_answer_0(rid, ENOENT);
 }
 
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -71,4 +71,5 @@
 static int fat_match(fs_node_t **, fs_node_t *, const char *);
 static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int fat_node_open(fs_node_t *);
 static int fat_node_put(fs_node_t *);
 static int fat_create_node(fs_node_t **, dev_handle_t, int);
@@ -83,4 +84,5 @@
 static bool fat_is_directory(fs_node_t *);
 static bool fat_is_file(fs_node_t *node);
+static dev_handle_t fat_device_get(fs_node_t *node);
 
 /*
@@ -407,4 +409,13 @@
 }
 
+int fat_node_open(fs_node_t *fn)
+{
+	/*
+	 * Opening a file is stateless, nothing
+	 * to be done here.
+	 */
+	return EOK;
+}
+
 int fat_node_put(fs_node_t *fn)
 {
@@ -867,4 +878,9 @@
 }
 
+dev_handle_t fat_device_get(fs_node_t *node)
+{
+	return 0;
+}
+
 /** libfs operations */
 libfs_ops_t fat_libfs_ops = {
@@ -872,4 +888,5 @@
 	.match = fat_match,
 	.node_get = fat_node_get,
+	.node_open = fat_node_open,
 	.node_put = fat_node_put,
 	.create = fat_create_node,
@@ -881,7 +898,8 @@
 	.size_get = fat_size_get,
 	.lnkcnt_get = fat_lnkcnt_get,
-	.plb_get_char =	fat_plb_get_char,
+	.plb_get_char = fat_plb_get_char,
 	.is_directory = fat_is_directory,
-	.is_file = fat_is_file
+	.is_file = fat_is_file,
+	.device_get = fat_device_get
 };
 
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 531695f6c403efc3d028936cfd0b5d4514838f1e)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -69,4 +69,5 @@
 static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
 static int tmpfs_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int tmpfs_node_open(fs_node_t *);
 static int tmpfs_node_put(fs_node_t *);
 static int tmpfs_create_node(fs_node_t **, dev_handle_t, int);
@@ -117,4 +118,9 @@
 }
 
+static dev_handle_t tmpfs_device_get(fs_node_t *fn)
+{
+	return 0;
+}
+
 /** libfs operations */
 libfs_ops_t tmpfs_libfs_ops = {
@@ -122,4 +128,5 @@
 	.match = tmpfs_match,
 	.node_get = tmpfs_node_get,
+	.node_open = tmpfs_node_open,
 	.node_put = tmpfs_node_put,
 	.create = tmpfs_create_node,
@@ -133,5 +140,6 @@
 	.plb_get_char = tmpfs_plb_get_char,
 	.is_directory = tmpfs_is_directory,
-	.is_file = tmpfs_is_file
+	.is_file = tmpfs_is_file,
+	.device_get = tmpfs_device_get
 };
 
@@ -241,4 +249,10 @@
 	}
 	return EOK;	
+}
+
+int tmpfs_node_open(fs_node_t *fn)
+{
+	/* nothing to do */
+	return EOK;
 }
 
