Index: uspace/app/bdsh/cmds/modules/ls/ls.c
===================================================================
--- uspace/app/bdsh/cmds/modules/ls/ls.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/app/bdsh/cmds/modules/ls/ls.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -100,4 +100,6 @@
 	if (s.is_file)
 		printf("%-40s\t%llu\n", name, (long long) s.size);
+	else if (s.is_directory)
+		printf("%-40s\t<dir>\n", name);
 	else
 		printf("%-40s\n", name);
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/app/init/init.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -58,5 +58,5 @@
 {
 	char *opts = "";
-	const char *root_dev = "initrd";
+	const char *root_dev = "bd/initrd";
 	
 	if (str_cmp(fstype, "tmpfs") == 0)
@@ -97,5 +97,5 @@
 	}
 	
-	snprintf(null, MAX_DEVICE_NAME, "null%d", null_id);
+	snprintf(null, MAX_DEVICE_NAME, "null/%d", null_id);
 	int rc = mount("devfs", "/dev", null, "", IPC_FLAG_BLOCKING);
 	
@@ -170,5 +170,5 @@
 	}
 
-	if (texit != TASK_EXIT_NORMAL || retval != 0) {
+	if ((texit != TASK_EXIT_NORMAL) || (retval != 0)) {
 		printf(NAME ": Server %s failed to start (returned %d)\n",
 			fname, retval);
@@ -206,8 +206,8 @@
 	int rc;
 
-	printf("Trying to mount disk0 on /data... ");
+	printf("Trying to mount bd/disk0 on /data... ");
 	fflush(stdout);
 
-	rc = mount("fat", "/data", "disk0", "wtcache", 0);
+	rc = mount("fat", "/data", "bd/disk0", "wtcache", 0);
 	if (rc == EOK)
 		printf("OK\n");
@@ -256,11 +256,11 @@
 #endif
 
-	getvc("vc0", "/app/bdsh");
-	getvc("vc1", "/app/bdsh");
-	getvc("vc2", "/app/bdsh");
-	getvc("vc3", "/app/bdsh");
-	getvc("vc4", "/app/bdsh");
-	getvc("vc5", "/app/bdsh");
-	getvc("vc6", "/app/klog");
+	getvc("term/vc0", "/app/bdsh");
+	getvc("term/vc1", "/app/bdsh");
+	getvc("term/vc2", "/app/bdsh");
+	getvc("term/vc3", "/app/bdsh");
+	getvc("term/vc4", "/app/bdsh");
+	getvc("term/vc5", "/app/bdsh");
+	getvc("term/vc6", "/app/klog");
 	
 	return 0;
Index: uspace/app/tester/vfs/vfs1.c
===================================================================
--- uspace/app/tester/vfs/vfs1.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/app/tester/vfs/vfs1.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -85,5 +85,5 @@
 		return "Unable to create null device";
 	
-	snprintf(null, MAX_DEVICE_NAME, "null%d", null_id);
+	snprintf(null, MAX_DEVICE_NAME, "null/%d", null_id);
 	int rc = mount(FS_TYPE, MOUNT_POINT, null, OPTIONS, FLAGS);
 	switch (rc) {
Index: uspace/lib/libc/generic/devmap.c
===================================================================
--- uspace/lib/libc/generic/devmap.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libc/generic/devmap.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -35,4 +35,6 @@
 #include <async.h>
 #include <errno.h>
+#include <malloc.h>
+#include <bool.h>
 
 static int devmap_phone_driver = -1;
@@ -105,6 +107,5 @@
 	aid_t req = async_send_2(phone, DEVMAP_DRIVER_REGISTER, 0, 0, &answer);
 	
-	ipcarg_t retval = async_data_write_start(phone, name, str_size(name) + 1);
-	
+	ipcarg_t retval = async_data_write_start(phone, name, str_size(name));
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
@@ -126,9 +127,10 @@
 /** Register new device.
  *
- * @param name   Device name.
- * @param handle Output: Handle to the created instance of device.
+ * @param namespace Namespace name.
+ * @param fqdn      Fully qualified device name.
+ * @param handle    Output: Handle to the created instance of device.
  *
  */
-int devmap_device_register(const char *name, dev_handle_t *handle)
+int devmap_device_register(const char *fqdn, dev_handle_t *handle)
 {
 	int phone = devmap_get_phone(DEVMAP_DRIVER, IPC_FLAG_BLOCKING);
@@ -143,6 +145,5 @@
 	    &answer);
 	
-	ipcarg_t retval = async_data_write_start(phone, name, str_size(name) + 1);
-	
+	ipcarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
@@ -167,5 +168,5 @@
 }
 
-int devmap_device_get_handle(const char *name, dev_handle_t *handle, unsigned int flags)
+int devmap_device_get_handle(const char *fqdn, dev_handle_t *handle, unsigned int flags)
 {
 	int phone = devmap_get_phone(DEVMAP_CLIENT, flags);
@@ -180,6 +181,5 @@
 	    &answer);
 	
-	ipcarg_t retval = async_data_write_start(phone, name, str_size(name) + 1);
-	
+	ipcarg_t retval = async_data_write_start(phone, fqdn, str_size(fqdn));
 	if (retval != EOK) {
 		async_wait_for(req, NULL);
@@ -202,4 +202,55 @@
 	
 	return retval;
+}
+
+int devmap_namespace_get_handle(const char *name, dev_handle_t *handle, unsigned int flags)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, flags);
+	
+	if (phone < 0)
+		return phone;
+	
+	async_serialize_start();
+	
+	ipc_call_t answer;
+	aid_t req = async_send_2(phone, DEVMAP_NAMESPACE_GET_HANDLE, flags, 0,
+	    &answer);
+	
+	ipcarg_t retval = async_data_write_start(phone, name, str_size(name));
+	if (retval != EOK) {
+		async_wait_for(req, NULL);
+		async_serialize_end();
+		return retval;
+	}
+	
+	async_wait_for(req, &retval);
+	
+	async_serialize_end();
+	
+	if (retval != EOK) {
+		if (handle != NULL)
+			*handle = (dev_handle_t) -1;
+		return retval;
+	}
+	
+	if (handle != NULL)
+		*handle = (dev_handle_t) IPC_GET_ARG1(answer);
+	
+	return retval;
+}
+
+devmap_handle_type_t devmap_handle_probe(dev_handle_t handle)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return phone;
+	
+	ipcarg_t type;
+	int retval = async_req_1_1(phone, DEVMAP_HANDLE_PROBE, handle, &type);
+	if (retval != EOK)
+		return DEV_HANDLE_NONE;
+	
+	return (devmap_handle_type_t) type;
 }
 
@@ -227,5 +278,5 @@
 	
 	ipcarg_t null_id;
-	int retval = async_req_0_1(phone, DEVMAP_DEVICE_NULL_CREATE, &null_id);
+	int retval = async_req_0_1(phone, DEVMAP_NULL_CREATE, &null_id);
 	if (retval != EOK)
 		return -1;
@@ -241,16 +292,11 @@
 		return;
 	
-	async_req_1_0(phone, DEVMAP_DEVICE_NULL_DESTROY, (ipcarg_t) null_id);
-}
-
-ipcarg_t devmap_device_get_count(void)
-{
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
+	async_req_1_0(phone, DEVMAP_NULL_DESTROY, (ipcarg_t) null_id);
+}
+
+static size_t devmap_count_namespaces_internal(int phone)
+{
 	ipcarg_t count;
-	int retval = async_req_0_1(phone, DEVMAP_DEVICE_GET_COUNT, &count);
+	int retval = async_req_0_1(phone, DEVMAP_GET_NAMESPACE_COUNT, &count);
 	if (retval != EOK)
 		return 0;
@@ -259,31 +305,135 @@
 }
 
-ipcarg_t devmap_device_get_devices(ipcarg_t count, dev_desc_t *data)
-{
-	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
-	
-	if (phone < 0)
-		return 0;
-	
-	async_serialize_start();
-	
-	ipc_call_t answer;
-	aid_t req = async_send_0(phone, DEVMAP_DEVICE_GET_DEVICES, &answer);
-	
-	ipcarg_t retval = async_data_read_start(phone, data, count * sizeof(dev_desc_t));
-	
-	if (retval != EOK) {
-		async_wait_for(req, NULL);
-		async_serialize_end();
-		return 0;
-	}
-	
-	async_wait_for(req, &retval);
-	
-	async_serialize_end();
-	
+static size_t devmap_count_devices_internal(int phone, dev_handle_t ns_handle)
+{
+	ipcarg_t count;
+	int retval = async_req_1_1(phone, DEVMAP_GET_DEVICE_COUNT, ns_handle, &count);
 	if (retval != EOK)
 		return 0;
 	
-	return IPC_GET_ARG1(answer);
-}
+	return count;
+}
+
+size_t devmap_count_namespaces(void)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return 0;
+	
+	return devmap_count_namespaces_internal(phone);
+}
+
+size_t devmap_count_devices(dev_handle_t ns_handle)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return 0;
+	
+	return devmap_count_devices_internal(phone, ns_handle);
+}
+
+size_t devmap_get_namespaces(dev_desc_t **data)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return 0;
+	
+	/* Loop until namespaces read succesful */
+	while (true) {
+		size_t count = devmap_count_namespaces_internal(phone);
+		if (count == 0)
+			return 0;
+		
+		dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
+		if (devs == NULL)
+			return 0;
+		
+		async_serialize_start();
+		
+		ipc_call_t answer;
+		aid_t req = async_send_0(phone, DEVMAP_GET_NAMESPACES, &answer);
+		
+		int rc = async_data_read_start(phone, devs, count * sizeof(dev_desc_t));
+		if (rc == EOVERFLOW) {
+			/*
+			 * Number of namespaces has changed since
+			 * the last call of DEVMAP_DEVICE_GET_NAMESPACE_COUNT
+			 */
+			async_serialize_end();
+			free(devs);
+			continue;
+		}
+		
+		if (rc != EOK) {
+			async_wait_for(req, NULL);
+			async_serialize_end();
+			free(devs);
+			return 0;
+		}
+		
+		ipcarg_t retval;
+		async_wait_for(req, &retval);
+		async_serialize_end();
+		
+		if (retval != EOK)
+			return 0;
+		
+		*data = devs;
+		return count;
+	}
+}
+
+size_t devmap_get_devices(dev_handle_t ns_handle, dev_desc_t **data)
+{
+	int phone = devmap_get_phone(DEVMAP_CLIENT, IPC_FLAG_BLOCKING);
+	
+	if (phone < 0)
+		return 0;
+	
+	/* Loop until namespaces read succesful */
+	while (true) {
+		size_t count = devmap_count_devices_internal(phone, ns_handle);
+		if (count == 0)
+			return 0;
+		
+		dev_desc_t *devs = (dev_desc_t *) calloc(count, sizeof(dev_desc_t));
+		if (devs == NULL)
+			return 0;
+		
+		async_serialize_start();
+		
+		ipc_call_t answer;
+		aid_t req = async_send_1(phone, DEVMAP_GET_DEVICES, ns_handle, &answer);
+		
+		int rc = async_data_read_start(phone, devs, count * sizeof(dev_desc_t));
+		if (rc == EOVERFLOW) {
+			/*
+			 * Number of devices has changed since
+			 * the last call of DEVMAP_DEVICE_GET_DEVICE_COUNT
+			 */
+			async_serialize_end();
+			free(devs);
+			continue;
+		}
+		
+		if (rc != EOK) {
+			async_wait_for(req, NULL);
+			async_serialize_end();
+			free(devs);
+			return 0;
+		}
+		
+		ipcarg_t retval;
+		async_wait_for(req, &retval);
+		async_serialize_end();
+		
+		if (retval != EOK)
+			return 0;
+		
+		*data = devs;
+		return count;
+	}
+}
Index: uspace/lib/libc/generic/vfs/vfs.c
===================================================================
--- uspace/lib/libc/generic/vfs/vfs.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libc/generic/vfs/vfs.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -117,5 +117,5 @@
 }
 
-int mount(const char *fs_name, const char *mp, const char *dev,
+int mount(const char *fs_name, const char *mp, const char *fqdn,
     const char *opts, unsigned int flags)
 {
@@ -126,5 +126,5 @@
 	dev_handle_t dev_handle;
 	
-	res = devmap_device_get_handle(dev, &dev_handle, flags);
+	res = devmap_device_get_handle(fqdn, &dev_handle, flags);
 	if (res != EOK)
 		return res;
@@ -703,8 +703,8 @@
 	rc = fstat(fildes, &stat);
 
-	if (!stat.devfs_stat.device)
+	if (!stat.device)
 		return -1;
 	
-	return devmap_device_connect(stat.devfs_stat.device, 0);
+	return devmap_device_connect(stat.device, 0);
 }
 
Index: uspace/lib/libc/include/devmap.h
===================================================================
--- uspace/lib/libc/include/devmap.h	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libc/include/devmap.h	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -38,4 +38,5 @@
 #include <ipc/devmap.h>
 #include <async.h>
+#include <bool.h>
 
 extern int devmap_get_phone(devmap_interface_t, unsigned int);
@@ -46,4 +47,7 @@
 
 extern int devmap_device_get_handle(const char *, dev_handle_t *, unsigned int);
+extern int devmap_namespace_get_handle(const char *, dev_handle_t *, unsigned int);
+extern devmap_handle_type_t devmap_handle_probe(dev_handle_t);
+
 extern int devmap_device_connect(dev_handle_t, unsigned int);
 
@@ -51,6 +55,9 @@
 extern void devmap_null_destroy(int);
 
-extern ipcarg_t devmap_device_get_count(void);
-extern ipcarg_t devmap_device_get_devices(ipcarg_t, dev_desc_t *);
+extern size_t devmap_count_namespaces(void);
+extern size_t devmap_count_devices(dev_handle_t);
+
+extern size_t devmap_get_namespaces(dev_desc_t **);
+extern size_t devmap_get_devices(dev_handle_t, dev_desc_t **);
 
 #endif
Index: uspace/lib/libc/include/ipc/devmap.h
===================================================================
--- uspace/lib/libc/include/ipc/devmap.h	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libc/include/ipc/devmap.h	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -43,14 +43,23 @@
 
 typedef enum {
+	DEV_HANDLE_NONE,
+	DEV_HANDLE_NAMESPACE,
+	DEV_HANDLE_DEVICE
+} devmap_handle_type_t;
+
+typedef enum {
 	DEVMAP_DRIVER_REGISTER = IPC_FIRST_USER_METHOD,
 	DEVMAP_DRIVER_UNREGISTER,
 	DEVMAP_DEVICE_REGISTER,
 	DEVMAP_DEVICE_UNREGISTER,
-	DEVMAP_DEVICE_GET_NAME,
 	DEVMAP_DEVICE_GET_HANDLE,
-	DEVMAP_DEVICE_NULL_CREATE,
-	DEVMAP_DEVICE_NULL_DESTROY,
-	DEVMAP_DEVICE_GET_COUNT,
-	DEVMAP_DEVICE_GET_DEVICES
+	DEVMAP_NAMESPACE_GET_HANDLE,
+	DEVMAP_HANDLE_PROBE,
+	DEVMAP_NULL_CREATE,
+	DEVMAP_NULL_DESTROY,
+	DEVMAP_GET_NAMESPACE_COUNT,
+	DEVMAP_GET_DEVICE_COUNT,
+	DEVMAP_GET_NAMESPACES,
+	DEVMAP_GET_DEVICES
 } devmap_request_t;
 
Index: uspace/lib/libc/include/sys/stat.h
===================================================================
--- uspace/lib/libc/include/sys/stat.h	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libc/include/sys/stat.h	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -42,15 +42,12 @@
 
 struct stat {
-	fs_handle_t	fs_handle;
-	dev_handle_t	dev_handle;
-	fs_index_t	index;
-	unsigned	lnkcnt;
-	bool		is_file;
-	off_t		size;
-	union {
-		struct {
-			dev_handle_t	device;
-		} devfs_stat;
-	};
+	fs_handle_t fs_handle;
+	dev_handle_t dev_handle;
+	fs_index_t index;
+	unsigned int lnkcnt;
+	bool is_file;
+	bool is_directory;
+	off_t size;
+	dev_handle_t device;
 };
 
Index: uspace/lib/libfs/libfs.c
===================================================================
--- uspace/lib/libfs/libfs.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libfs/libfs.c	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2009 Jakub Jermar 
+ * Copyright (c) 2009 Jakub Jermar
  * All rights reserved.
  *
@@ -27,13 +27,13 @@
  */
 
-/** @addtogroup libfs 
+/** @addtogroup libfs
  * @{
- */ 
+ */
 /**
  * @file
- * Glue code which is commonod to all FS implementations. 
- */
-
-#include "libfs.h" 
+ * Glue code which is common to all FS implementations.
+ */
+
+#include "libfs.h"
 #include "../../srv/vfs/vfs.h"
 #include <errno.h>
@@ -67,13 +67,14 @@
  * code.
  *
- * @param vfs_phone	Open phone for communication with VFS.
- * @param reg		File system registration structure. It will be
- * 			initialized by this function.
- * @param info		VFS info structure supplied by the file system
- *			implementation.
- * @param conn		Connection fibril for handling all calls originating in
- *			VFS.
- *
- * @return		EOK on success or a non-zero error code on errror.
+ * @param vfs_phone Open phone for communication with VFS.
+ * @param reg       File system registration structure. It will be
+ *                  initialized by this function.
+ * @param info      VFS info structure supplied by the file system
+ *                  implementation.
+ * @param conn      Connection fibril for handling all calls originating in
+ *                  VFS.
+ *
+ * @return EOK on success or a non-zero error code on errror.
+ *
  */
 int fs_register(int vfs_phone, fs_reg_t *reg, vfs_info_t *info,
@@ -87,5 +88,5 @@
 	ipc_call_t answer;
 	aid_t req = async_send_0(vfs_phone, VFS_IN_REGISTER, &answer);
-
+	
 	/*
 	 * Send our VFS info structure to VFS.
@@ -96,10 +97,10 @@
 		return rc;
 	}
-
+	
 	/*
 	 * Ask VFS for callback connection.
 	 */
 	ipc_connect_to_me(vfs_phone, 0, 0, 0, &reg->vfs_phonehash);
-
+	
 	/*
 	 * Allocate piece of address space for PLB.
@@ -110,5 +111,5 @@
 		return ENOMEM;
 	}
-
+	
 	/*
 	 * Request sharing the Path Lookup Buffer with VFS.
@@ -136,5 +137,5 @@
 	 */
 	async_set_client_connection(conn);
-
+	
 	return IPC_GET_RETVAL(answer);
 }
@@ -154,18 +155,20 @@
 	int res;
 	ipcarg_t rc;
-
+	
 	ipc_call_t call;
 	ipc_callid_t callid;
-
-	/* accept the phone */
+	
+	/* Accept the phone */
 	callid = async_get_call(&call);
 	int mountee_phone = (int)IPC_GET_ARG1(call);
 	if ((IPC_GET_METHOD(call) != IPC_M_CONNECTION_CLONE) ||
-	    mountee_phone < 0) {
+	    (mountee_phone < 0)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
 		return;
 	}
-	ipc_answer_0(callid, EOK);	/* acknowledge the mountee_phone */
+	
+	/* Acknowledge the mountee_phone */
+	ipc_answer_0(callid, EOK);
 	
 	res = async_data_write_receive(&callid, NULL);
@@ -176,8 +179,8 @@
 		return;
 	}
-
+	
 	fs_node_t *fn;
 	res = ops->node_get(&fn, mp_dev_handle, mp_fs_index);
-	if (res != EOK || !fn) {
+	if ((res != EOK) || (!fn)) {
 		ipc_hangup(mountee_phone);
 		ipc_answer_0(callid, combine_rc(res, ENOENT));
@@ -185,5 +188,5 @@
 		return;
 	}
-
+	
 	if (fn->mp_data.mp_active) {
 		ipc_hangup(mountee_phone);
@@ -193,5 +196,5 @@
 		return;
 	}
-
+	
 	rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
 	if (rc != EOK) {
@@ -215,4 +218,5 @@
 		fn->mp_data.phone = mountee_phone;
 	}
+	
 	/*
 	 * Do not release the FS node so that it stays in memory.
@@ -238,24 +242,24 @@
     ipc_call_t *request)
 {
-	unsigned first = IPC_GET_ARG1(*request);
-	unsigned last = IPC_GET_ARG2(*request);
-	unsigned next = first;
+	unsigned int first = IPC_GET_ARG1(*request);
+	unsigned int last = IPC_GET_ARG2(*request);
+	unsigned int next = first;
 	dev_handle_t dev_handle = IPC_GET_ARG3(*request);
 	int lflag = IPC_GET_ARG4(*request);
-	fs_index_t index = IPC_GET_ARG5(*request); /* when L_LINK specified */
+	fs_index_t index = IPC_GET_ARG5(*request);
 	char component[NAME_MAX + 1];
 	int len;
 	int rc;
-
+	
 	if (last < next)
 		last += PLB_SIZE;
-
+	
 	fs_node_t *par = NULL;
 	fs_node_t *cur = NULL;
 	fs_node_t *tmp = NULL;
-
+	
 	rc = ops->root_get(&cur, dev_handle);
 	on_error(rc, goto out_with_answer);
-
+	
 	if (cur->mp_data.mp_active) {
 		ipc_forward_slow(rid, cur->mp_data.phone, VFS_OUT_LOOKUP,
@@ -265,42 +269,45 @@
 		return;
 	}
-
+	
+	/* Eat slash */
 	if (ops->plb_get_char(next) == '/')
-		next++;		/* eat slash */
+		next++;
 	
 	while (next <= last) {
 		bool has_children;
-
+		
 		rc = ops->has_children(&has_children, cur);
 		on_error(rc, goto out_with_answer);
 		if (!has_children)
 			break;
-
-		/* collect the component */
+		
+		/* Collect the component */
 		len = 0;
-		while ((next <= last) &&  (ops->plb_get_char(next) != '/')) {
+		while ((next <= last) && (ops->plb_get_char(next) != '/')) {
 			if (len + 1 == NAME_MAX) {
-				/* component length overflow */
+				/* Component length overflow */
 				ipc_answer_0(rid, ENAMETOOLONG);
 				goto out;
 			}
 			component[len++] = ops->plb_get_char(next);
-			next++;	/* process next character */
+			/* Process next character */
+			next++;
 		}
-
+		
 		assert(len);
 		component[len] = '\0';
-		next++;		/* eat slash */
-
-		/* match the component */
+		/* Eat slash */
+		next++;
+		
+		/* Match the component */
 		rc = ops->match(&tmp, cur, component);
 		on_error(rc, goto out_with_answer);
-
-		if (tmp && tmp->mp_data.mp_active) {
+		
+		if ((tmp) && (tmp->mp_data.mp_active)) {
 			if (next > last)
 				next = last = first;
 			else
 				next--;
-				
+			
 			ipc_forward_slow(rid, tmp->mp_data.phone,
 			    VFS_OUT_LOOKUP, next, last, tmp->mp_data.dev_handle,
@@ -312,19 +319,21 @@
 			return;
 		}
-
-		/* handle miss: match amongst siblings */
+		
+		/* Handle miss: match amongst siblings */
 		if (!tmp) {
 			if (next <= last) {
-				/* there are unprocessed components */
+				/* There are unprocessed components */
 				ipc_answer_0(rid, ENOENT);
 				goto out;
 			}
-			/* miss in the last component */
-			if (lflag & (L_CREATE | L_LINK)) { 
-				/* request to create a new link */
+			
+			/* Miss in the last component */
+			if (lflag & (L_CREATE | L_LINK)) {
+				/* Request to create a new link */
 				if (!ops->is_directory(cur)) {
 					ipc_answer_0(rid, ENOTDIR);
 					goto out;
 				}
+				
 				fs_node_t *fn;
 				if (lflag & L_CREATE)
@@ -335,4 +344,5 @@
 					    index);
 				on_error(rc, goto out_with_answer);
+				
 				if (fn) {
 					rc = ops->link(cur, fn, component);
@@ -349,33 +359,34 @@
 						(void) ops->node_put(fn);
 					}
-				} else {
+				} else
 					ipc_answer_0(rid, ENOSPC);
-				}
+				
 				goto out;
-			} 
+			}
+			
 			ipc_answer_0(rid, ENOENT);
 			goto out;
 		}
-
+		
 		if (par) {
 			rc = ops->node_put(par);
 			on_error(rc, goto out_with_answer);
 		}
-
-		/* descend one level */
+		
+		/* Descend one level */
 		par = cur;
 		cur = tmp;
 		tmp = NULL;
 	}
-
-	/* handle miss: excessive components */
+	
+	/* Handle miss: excessive components */
 	if (next <= last) {
 		bool has_children;
-
 		rc = ops->has_children(&has_children, cur);
 		on_error(rc, goto out_with_answer);
+		
 		if (has_children)
 			goto skip_miss;
-
+		
 		if (lflag & (L_CREATE | L_LINK)) {
 			if (!ops->is_directory(cur)) {
@@ -383,24 +394,28 @@
 				goto out;
 			}
-
-			/* collect next component */
+			
+			/* Collect next component */
 			len = 0;
 			while (next <= last) {
 				if (ops->plb_get_char(next) == '/') {
-					/* more than one component */
+					/* More than one component */
 					ipc_answer_0(rid, ENOENT);
 					goto out;
 				}
+				
 				if (len + 1 == NAME_MAX) {
-					/* component length overflow */
+					/* Component length overflow */
 					ipc_answer_0(rid, ENAMETOOLONG);
 					goto out;
 				}
+				
 				component[len++] = ops->plb_get_char(next);
-				next++;	/* process next character */
+				/* Process next character */
+				next++;
 			}
+			
 			assert(len);
 			component[len] = '\0';
-				
+			
 			fs_node_t *fn;
 			if (lflag & L_CREATE)
@@ -409,4 +424,5 @@
 				rc = ops->node_get(&fn, dev_handle, index);
 			on_error(rc, goto out_with_answer);
+			
 			if (fn) {
 				rc = ops->link(cur, fn, component);
@@ -423,22 +439,25 @@
 					(void) ops->node_put(fn);
 				}
-			} else {
+			} else
 				ipc_answer_0(rid, ENOSPC);
-			}
+			
 			goto out;
 		}
+		
 		ipc_answer_0(rid, ENOENT);
 		goto out;
 	}
+	
 skip_miss:
-
-	/* handle hit */
+	
+	/* Handle hit */
 	if (lflag & L_UNLINK) {
-		unsigned old_lnkcnt = ops->lnkcnt_get(cur);
+		unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
 		rc = ops->unlink(par, cur, component);
-		ipc_answer_5(rid, (ipcarg_t)rc, fs_handle, dev_handle,
+		ipc_answer_5(rid, (ipcarg_t) rc, fs_handle, dev_handle,
 		    ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
 		goto out;
 	}
+	
 	if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
 	    (lflag & L_LINK)) {
@@ -446,27 +465,35 @@
 		goto out;
 	}
+	
 	if ((lflag & L_FILE) && (ops->is_directory(cur))) {
 		ipc_answer_0(rid, EISDIR);
 		goto out;
 	}
+	
 	if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
 		ipc_answer_0(rid, ENOTDIR);
 		goto out;
 	}
-
+	
 out_with_answer:
+	
 	if (rc == EOK) {
-		ipc_answer_5(rid, EOK, fs_handle, dev_handle,
+		if (lflag & L_OPEN)
+			rc = ops->node_open(cur);
+		
+		ipc_answer_5(rid, rc, fs_handle, dev_handle,
 		    ops->index_get(cur), ops->size_get(cur),
 		    ops->lnkcnt_get(cur));
-	} else {
+	} else
 		ipc_answer_0(rid, rc);
-	}
-
+	
 out:
+	
 	if (par)
 		(void) ops->node_put(par);
+	
 	if (cur)
 		(void) ops->node_put(cur);
+	
 	if (tmp)
 		(void) ops->node_put(tmp);
@@ -478,19 +505,19 @@
 	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
 	fs_node_t *fn;
-	int rc;
-
-	rc = ops->node_get(&fn, dev_handle, index);
+	int rc = ops->node_get(&fn, dev_handle, index);
 	on_error(rc, answer_and_return(rid, rc));
-
+	
 	ipc_callid_t callid;
 	size_t size;
-	if (!async_data_read_receive(&callid, &size) ||
-	    size != sizeof(struct stat)) {
+	if ((!async_data_read_receive(&callid, &size)) ||
+	    (size != sizeof(struct stat))) {
+		ops->node_put(fn);
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
 		return;
 	}
-
+	
 	struct stat stat;
 	memset(&stat, 0, sizeof(struct stat));
@@ -499,8 +526,12 @@
 	stat.dev_handle = dev_handle;
 	stat.index = index;
-	stat.lnkcnt = ops->lnkcnt_get(fn); 
+	stat.lnkcnt = ops->lnkcnt_get(fn);
 	stat.is_file = ops->is_file(fn);
+	stat.is_directory = ops->is_directory(fn);
 	stat.size = ops->size_get(fn);
-
+	stat.device = ops->device_get(fn);
+	
+	ops->node_put(fn);
+	
 	async_data_read_finalize(callid, &stat, sizeof(struct stat));
 	ipc_answer_0(rid, EOK);
@@ -509,8 +540,8 @@
 /** Open VFS triplet.
  *
- * @param ops       libfs operations structure with function pointers to
- *                  file system implementation
- * @param rid       Request ID of the VFS_OUT_OPEN_NODE request.
- * @param request   VFS_OUT_OPEN_NODE request data itself.
+ * @param ops     libfs operations structure with function pointers to
+ *                file system implementation
+ * @param rid     Request ID of the VFS_OUT_OPEN_NODE request.
+ * @param request VFS_OUT_OPEN_NODE request data itself.
  *
  */
@@ -531,5 +562,6 @@
 	}
 	
-	ipc_answer_3(rid, EOK, ops->size_get(fn), ops->lnkcnt_get(fn),
+	rc = ops->node_open(fn);
+	ipc_answer_3(rid, rc, ops->size_get(fn), ops->lnkcnt_get(fn),
 	    (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
 	
Index: uspace/lib/libfs/libfs.h
===================================================================
--- uspace/lib/libfs/libfs.h	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ uspace/lib/libfs/libfs.h	(revision 1313ee92979dd133fd0dd0717213410aada3df10)
@@ -64,4 +64,5 @@
 	int (* match)(fs_node_t **, fs_node_t *, const char *);
 	int (* node_get)(fs_node_t **, dev_handle_t, fs_index_t);
+	int (* node_open)(fs_node_t *);
 	int (* node_put)(fs_node_t *);
 	int (* create)(fs_node_t **, dev_handle_t, int);
@@ -76,8 +77,9 @@
 	fs_index_t (* index_get)(fs_node_t *);
 	size_t (* size_get)(fs_node_t *);
-	unsigned (* lnkcnt_get)(fs_node_t *);
+	unsigned int (* lnkcnt_get)(fs_node_t *);
 	char (* plb_get_char)(unsigned pos);
 	bool (* is_directory)(fs_node_t *);
 	bool (* is_file)(fs_node_t *);
+	dev_handle_t (* device_get)(fs_node_t *);
 } libfs_ops_t;
 
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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 fc6dd18feebbc66893aec4d86827b7c815dbbfe7)
+++ 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;
 }
 
