Index: uspace/srv/fs/devfs/Makefile
===================================================================
--- uspace/srv/fs/devfs/Makefile	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/devfs/Makefile	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -34,7 +34,7 @@
 all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
 	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
-	$(MAKE) -f Makefile.build
+	$(MAKE) -f Makefile.build PRECHECK=$(PRECHECK)
 
 clean:
-	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
 	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/devfs/Makefile.build
===================================================================
--- uspace/srv/fs/devfs/Makefile.build	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/devfs/Makefile.build	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -59,4 +59,7 @@
 %.o: %.c $(DEPEND)
 	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+ifeq ($(PRECHECK),y)
+	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
+endif
 
 $(DEPEND):
Index: uspace/srv/fs/devfs/Makefile.common
===================================================================
--- uspace/srv/fs/devfs/Makefile.common	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/devfs/Makefile.common	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -38,3 +38,4 @@
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
+JOB = devfs.job
 OUTPUT = devfs
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -42,11 +42,17 @@
 #include <string.h>
 #include <libfs.h>
-#include <fibril_sync.h>
+#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/Makefile
===================================================================
--- uspace/srv/fs/fat/Makefile	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/Makefile	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -34,7 +34,7 @@
 all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
 	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
-	$(MAKE) -f Makefile.build
+	$(MAKE) -f Makefile.build PRECHECK=$(PRECHECK)
 
 clean:
-	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
 	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/fat/Makefile.build
===================================================================
--- uspace/srv/fs/fat/Makefile.build	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/Makefile.build	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -62,4 +62,7 @@
 %.o: %.c $(DEPEND)
 	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+ifeq ($(PRECHECK),y)
+	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
+endif
 
 $(DEPEND):
Index: uspace/srv/fs/fat/Makefile.common
===================================================================
--- uspace/srv/fs/fat/Makefile.common	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/Makefile.common	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -39,3 +39,4 @@
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
+JOB = fat.job
 OUTPUT = fat
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/fat.h	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -36,5 +36,5 @@
 #include "fat_fat.h"
 #include <ipc/ipc.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <libfs.h>
 #include <atomic.h>
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -46,5 +46,5 @@
 #include <align.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <mem.h>
 
@@ -247,10 +247,11 @@
  */
 int
-fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t clst,
-    fat_cluster_t *value)
+fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, unsigned fatno,
+    fat_cluster_t clst, fat_cluster_t *value)
 {
 	block_t *b;
 	uint16_t bps;
 	uint16_t rscnt;
+	uint16_t sf;
 	fat_cluster_t *cp;
 	int rc;
@@ -258,6 +259,7 @@
 	bps = uint16_t_le2host(bs->bps);
 	rscnt = uint16_t_le2host(bs->rscnt);
-
-	rc = block_get(&b, dev_handle, rscnt +
+	sf = uint16_t_le2host(bs->sec_per_fat);
+
+	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
 	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
 	if (rc != EOK)
@@ -480,5 +482,5 @@
 	while (firstc < FAT_CLST_LAST1) {
 		assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
-		rc = fat_get_cluster(bs, dev_handle, firstc, &nextc);
+		rc = fat_get_cluster(bs, dev_handle, FAT1, firstc, &nextc);
 		if (rc != EOK)
 			return rc;
@@ -560,5 +562,5 @@
 		unsigned fatno;
 
-		rc = fat_get_cluster(bs, dev_handle, lastc, &nextc);
+		rc = fat_get_cluster(bs, dev_handle, FAT1, lastc, &nextc);
 		if (rc != EOK)
 			return rc;
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -80,6 +80,6 @@
 extern int fat_alloc_shadow_clusters(struct fat_bs *, dev_handle_t,
     fat_cluster_t *, unsigned);
-extern int fat_get_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t,
-    fat_cluster_t *);
+extern int fat_get_cluster(struct fat_bs *, dev_handle_t, unsigned,
+    fat_cluster_t, fat_cluster_t *);
 extern int fat_set_cluster(struct fat_bs *, dev_handle_t, unsigned,
     fat_cluster_t, fat_cluster_t);
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -43,5 +43,5 @@
 #include <adt/list.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 
 /** Each instance of this type describes one interval of freed VFS indices. */
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -52,5 +52,5 @@
 #include <adt/list.h>
 #include <assert.h>
-#include <fibril_sync.h>
+#include <fibril_synch.h>
 #include <sys/mman.h>
 #include <align.h>
@@ -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);
 
 /*
@@ -288,4 +290,63 @@
 
 	*nodepp = nodep;
+	return EOK;
+}
+
+/** Perform basic sanity checks on the file system.
+ *
+ * Verify if values of boot sector fields are sane. Also verify media
+ * descriptor. This is used to rule out cases when a device obviously
+ * does not contain a fat file system.
+ */
+static int fat_sanity_check(fat_bs_t *bs, dev_handle_t dev_handle)
+{
+	fat_cluster_t e0, e1;
+	unsigned fat_no;
+	int rc;
+
+	/* Check number of FATs. */
+	if (bs->fatcnt == 0)
+		return ENOTSUP;
+
+	/* Check total number of sectors. */
+
+	if (bs->totsec16 == 0 && bs->totsec32 == 0)
+		return ENOTSUP;
+
+	if (bs->totsec16 != 0 && bs->totsec32 != 0 &&
+	    bs->totsec16 != bs->totsec32) 
+		return ENOTSUP;
+
+	/* Check media descriptor. Must be between 0xf0 and 0xff. */
+	if ((bs->mdesc & 0xf0) != 0xf0)
+		return ENOTSUP;
+
+	/* Check number of sectors per FAT. */
+	if (bs->sec_per_fat == 0)
+		return ENOTSUP;
+
+	/* Check signature of each FAT. */
+
+	for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {
+		rc = fat_get_cluster(bs, dev_handle, fat_no, 0, &e0);
+		if (rc != EOK)
+			return EIO;
+
+		rc = fat_get_cluster(bs, dev_handle, fat_no, 1, &e1);
+		if (rc != EOK)
+			return EIO;
+
+		/* Check that first byte of FAT contains the media descriptor. */
+		if ((e0 & 0xff) != bs->mdesc)
+			return ENOTSUP;
+
+		/*
+		 * Check that remaining bits of the first two entries are
+		 * set to one.
+		 */
+		if ((e0 >> 8) != 0xff || e1 != 0xffff)
+			return ENOTSUP;
+	}
+
 	return EOK;
 }
@@ -407,4 +468,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 +937,9 @@
 }
 
+dev_handle_t fat_device_get(fs_node_t *node)
+{
+	return 0;
+}
+
 /** libfs operations */
 libfs_ops_t fat_libfs_ops = {
@@ -872,4 +947,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 +957,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
 };
 
@@ -957,4 +1034,12 @@
 	/* Initialize the block cache */
 	rc = block_cache_init(dev_handle, bps, 0 /* XXX */, cmode);
+	if (rc != EOK) {
+		block_fini(dev_handle);
+		ipc_answer_0(rid, rc);
+		return;
+	}
+
+	/* Do some simple sanity checks on the file system. */
+	rc = fat_sanity_check(bs, dev_handle);
 	if (rc != EOK) {
 		block_fini(dev_handle);
Index: uspace/srv/fs/tmpfs/Makefile
===================================================================
--- uspace/srv/fs/tmpfs/Makefile	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/tmpfs/Makefile	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -34,7 +34,7 @@
 all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
 	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
-	$(MAKE) -f Makefile.build
+	$(MAKE) -f Makefile.build PRECHECK=$(PRECHECK)
 
 clean:
-	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	rm -f $(DEPEND) $(DEPEND_PREV) $(JOB) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
 	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/tmpfs/Makefile.build
===================================================================
--- uspace/srv/fs/tmpfs/Makefile.build	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/tmpfs/Makefile.build	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -60,4 +60,7 @@
 %.o: %.c $(DEPEND)
 	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+ifeq ($(PRECHECK),y)
+	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
+endif
 
 $(DEPEND):
Index: uspace/srv/fs/tmpfs/Makefile.common
===================================================================
--- uspace/srv/fs/tmpfs/Makefile.common	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/tmpfs/Makefile.common	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -39,3 +39,4 @@
 DEPEND = Makefile.depend
 DEPEND_PREV = $(DEPEND).prev
+JOB = tmpfs.job
 OUTPUT = tmpfs
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 50f9c3a7c6d0cb3cef99ff7ccda9019bcd77df94)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 963462af16f4105e1f849d59aafc9d89a09411fe)
@@ -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;
 }
 
