Index: uspace/srv/fs/ext2fs/Makefile
===================================================================
--- uspace/srv/fs/ext2fs/Makefile	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/ext2fs/Makefile	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# Copyright (c) 2010 Martin Sucha
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT2_PREFIX)/libext2.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT2_PREFIX)
+BINARY = ext2fs
+
+SOURCES = \
+	ext2fs.c \
+	ext2fs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/ext2fs/ext2fs.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/ext2fs/ext2fs.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2.c
+ * @brief	EXT2 file system driver for HelenOS.
+ */
+
+#include "ext2fs.h"
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <stdio.h>
+#include <libfs.h>
+#include "../../vfs/vfs.h"
+
+#define NAME	"ext2fs"
+
+vfs_info_t ext2fs_vfs_info = {
+	.name = NAME,
+};
+
+fs_reg_t ext2fs_reg;
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to EXT2FS. To overcome this bottleneck, VFS can send EXT2FS the IPC_M_CONNECT_ME_TO
+ * call. In that case, a new connection fibril will be created, which in turn
+ * will accept the call. Thus, a new phone will be opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, EXT2FS can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, EXT2FS might want to keep the connections open after the
+ * request has been completed.
+ */
+static void ext2fs_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	dprintf(NAME ": connection opened\n");
+	while (1) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+	
+		callid = async_get_call(&call);
+		switch  (IPC_GET_IMETHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			return;
+		case VFS_OUT_MOUNTED:
+			ext2fs_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			ext2fs_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			ext2fs_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			ext2fs_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			ext2fs_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			ext2fs_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			ext2fs_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			ext2fs_truncate(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			ext2fs_stat(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			ext2fs_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			ext2fs_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			ext2fs_open_node(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			ext2fs_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int vfs_phone;
+	int rc;
+
+	printf(NAME ": HelenOS EXT2 file system server\n");
+
+	vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
+	if (vfs_phone < EOK) {
+		printf(NAME ": failed to connect to VFS\n");
+		return -1;
+	}
+
+	rc = ext2fs_global_init();
+	if (rc != EOK) {
+		printf(NAME ": Failed global initialization\n");
+		return 1;
+	}	
+		
+	rc = fs_register(vfs_phone, &ext2fs_reg, &ext2fs_vfs_info, ext2fs_connection);
+	
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */ 
Index: uspace/srv/fs/ext2fs/ext2fs.h
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/ext2fs/ext2fs.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */ 
+
+#ifndef EXT2FS_EXT2FS_H_
+#define EXT2FS_EXT2FS_H_
+
+#include <libext2.h>
+#include <fibril_synch.h>
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include "../../vfs/vfs.h"
+
+#ifndef dprintf
+#define dprintf(...)	printf(__VA_ARGS__)
+#endif
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+
+extern fs_reg_t ext2fs_reg;
+
+extern int ext2fs_global_init(void);
+extern int ext2fs_global_fini(void);
+extern void ext2fs_mounted(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_mount(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_unmounted(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_unmount(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_lookup(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_read(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_write(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_truncate(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_close(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_destroy(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_open_node(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_stat(ipc_callid_t, ipc_call_t *);
+extern void ext2fs_sync(ipc_callid_t, ipc_call_t *);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/ext2fs/ext2fs_ops.c
===================================================================
--- uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/ext2fs/ext2fs_ops.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Martin Sucha
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */ 
+
+/**
+ * @file	ext2fs_ops.c
+ * @brief	Implementation of VFS operations for the EXT2 file system server.
+ */
+
+#include "ext2fs.h"
+#include "../../vfs/vfs.h"
+#include <libfs.h>
+#include <libblock.h>
+#include <libext2.h>
+#include <ipc/services.h>
+#include <ipc/devmap.h>
+#include <macros.h>
+#include <async.h>
+#include <errno.h>
+#include <str.h>
+#include <byteorder.h>
+#include <adt/hash_table.h>
+#include <adt/list.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <sys/mman.h>
+#include <align.h>
+#include <adt/hash_table.h>
+#include <sys/typefmt.h>
+
+#define EXT2FS_NODE(node)	((node) ? (ext2fs_node_t *) (node)->data : NULL)
+#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
+
+typedef struct ext2fs_instance {
+	link_t link;
+	devmap_handle_t devmap_handle;
+	ext2_filesystem_t *filesystem;
+} ext2fs_instance_t;
+
+typedef struct ext2fs_node {
+	ext2fs_instance_t *instance;
+	ext2_inode_ref_t *inode_ref;
+} ext2fs_node_t;
+
+/*
+ * Forward declarations of auxiliary functions
+ */
+static int ext2fs_instance_get(devmap_handle_t, ext2fs_instance_t **);
+static void ext2fs_read_directory(ipc_callid_t, ipc_callid_t, aoff64_t,
+	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
+static void ext2fs_read_file(ipc_callid_t, ipc_callid_t, aoff64_t,
+	size_t, ext2fs_instance_t *, ext2_inode_ref_t *);
+static bool ext2fs_is_dots(const uint8_t *, size_t);
+static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
+
+/*
+ * Forward declarations of EXT2 libfs operations.
+ */
+static int ext2fs_root_get(fs_node_t **, devmap_handle_t);
+static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
+static int ext2fs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int ext2fs_node_open(fs_node_t *);
+static int ext2fs_node_put(fs_node_t *);
+static int ext2fs_create_node(fs_node_t **, devmap_handle_t, int);
+static int ext2fs_destroy_node(fs_node_t *);
+static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
+static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
+static int ext2fs_has_children(bool *, fs_node_t *);
+static fs_index_t ext2fs_index_get(fs_node_t *);
+static aoff64_t ext2fs_size_get(fs_node_t *);
+static unsigned ext2fs_lnkcnt_get(fs_node_t *);
+static char ext2fs_plb_get_char(unsigned);
+static bool ext2fs_is_directory(fs_node_t *);
+static bool ext2fs_is_file(fs_node_t *node);
+static devmap_handle_t ext2fs_device_get(fs_node_t *node);
+
+/*
+ * Static variables
+ */
+static LIST_INITIALIZE(instance_list);
+static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
+
+/**
+ * 
+ */
+int ext2fs_global_init(void)
+{
+	return EOK;
+}
+
+int ext2fs_global_fini(void)
+{
+	return EOK;
+}
+
+
+
+/*
+ * EXT2 libfs operations.
+ */
+
+/**
+ * Find an instance of filesystem for the given devmap_handle
+ */
+int ext2fs_instance_get(devmap_handle_t devmap_handle, ext2fs_instance_t **inst)
+{
+	EXT2FS_DBG("(%u, -)", devmap_handle);
+	link_t *link;
+	ext2fs_instance_t *tmp;
+	
+	fibril_mutex_lock(&instance_list_mutex);
+
+	if (list_empty(&instance_list)) {
+		EXT2FS_DBG("list empty");
+		fibril_mutex_unlock(&instance_list_mutex);
+		return EINVAL;
+	}
+
+	for (link = instance_list.next; link != &instance_list; link = link->next) {
+		tmp = list_get_instance(link, ext2fs_instance_t, link);
+		
+		if (tmp->devmap_handle == devmap_handle) {
+			*inst = tmp;
+			fibril_mutex_unlock(&instance_list_mutex);
+			return EOK;
+		}
+	}
+	
+	EXT2FS_DBG("not found");
+	
+	fibril_mutex_unlock(&instance_list_mutex);
+	return EINVAL;
+}
+
+
+
+int ext2fs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
+{
+	EXT2FS_DBG("(-, %u)", devmap_handle);
+	return ext2fs_node_get(rfn, devmap_handle, EXT2_INODE_ROOT_INDEX);
+}
+
+int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	EXT2FS_DBG("(-,-,%s)", component);
+	ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
+	ext2_filesystem_t *fs;
+	ext2_directory_iterator_t it;
+	int rc;
+	size_t name_size;
+	size_t component_size;
+	bool found = false;
+	
+	fs = eparent->instance->filesystem;
+	
+	if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		return ENOTDIR;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	// Find length of component in bytes
+	// TODO: check for library function call that does this
+	component_size = 0;
+	while (*(component+component_size) != 0) {
+		component_size++;
+	}
+	
+	while (it.current != NULL) {
+		// ignore empty directory entries
+		if (it.current->inode != 0) {
+			name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+				it.current);
+
+			if (name_size == component_size && bcmp(component, &it.current->name,
+				    name_size) == 0) {
+				rc = ext2fs_node_get_core(rfn, eparent->instance,
+					it.current->inode);
+				if (rc != EOK) {
+					ext2_directory_iterator_fini(&it);
+					return rc;
+				}
+				found = true;
+				break;
+			}
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			return rc;
+		}
+	}
+	
+	ext2_directory_iterator_fini(&it);
+	
+	if (!found) {
+		return ENOENT;
+	}
+	
+	return EOK;
+}
+
+/** Instantiate a EXT2 in-core node. */
+int ext2fs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+{
+	EXT2FS_DBG("(-,%u,%u)", devmap_handle, index);
+	
+	ext2fs_instance_t *inst = NULL;
+	int rc;
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		return rc;
+	}
+	
+	return ext2fs_node_get_core(rfn, inst, index);
+}
+
+int ext2fs_node_get_core(fs_node_t **rfn, ext2fs_instance_t *inst,
+		fs_index_t index)
+{
+	int rc;
+	fs_node_t *node = NULL;
+	ext2fs_node_t *enode = NULL;
+	
+	ext2_inode_ref_t *inode_ref = NULL;
+
+	enode = malloc(sizeof(ext2fs_node_t));
+	if (enode == NULL) {
+		return ENOMEM;
+	}
+
+	node = malloc(sizeof(fs_node_t));
+	if (node == NULL) {
+		free(enode);
+		return ENOMEM;
+	}	
+	fs_node_initialize(node);
+
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		free(enode);
+		free(node);
+		return rc;
+	}
+	
+	enode->inode_ref = inode_ref;
+	enode->instance = inst;
+	node->data = enode;
+	*rfn = node;
+	
+	EXT2FS_DBG("inode: %u", inode_ref->index);
+	
+	EXT2FS_DBG("EOK");
+
+	return EOK;
+}
+
+int ext2fs_node_open(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	/*
+	 * Opening a file is stateless, nothing
+	 * to be done here.
+	 */
+	return EOK;
+}
+
+int ext2fs_node_put(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	int rc;
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
+	}
+	return rc;
+}
+
+int ext2fs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_destroy_node(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	EXT2FS_DBG("");
+	// TODO
+	return ENOTSUP;
+}
+
+int ext2fs_has_children(bool *has_children, fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	ext2_directory_iterator_t it;
+	ext2_filesystem_t *fs;
+	int rc;
+	bool found = false;
+	size_t name_size;
+
+	fs = enode->instance->filesystem;
+
+	if (!ext2_inode_is_type(fs->superblock, enode->inode_ref->inode,
+	    EXT2_INODE_MODE_DIRECTORY)) {
+		*has_children = false;
+		EXT2FS_DBG("EOK - false");
+		return EOK;
+	}
+	
+	rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+	
+	// Find a non-empty directory entry
+	while (it.current != NULL) {
+		if (it.current->inode != 0) {
+			name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
+				it.current);
+			if (!ext2fs_is_dots(&it.current->name, name_size)) {
+				found = true;
+				break;
+			}
+		}
+		
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			EXT2FS_DBG("error %u", rc);
+			return rc;
+		}
+	}
+	
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		EXT2FS_DBG("error %u", rc);
+		return rc;
+	}
+
+	*has_children = found;
+	EXT2FS_DBG("EOK");
+	
+	return EOK;
+}
+
+
+fs_index_t ext2fs_index_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return enode->inode_ref->index;
+}
+
+aoff64_t ext2fs_size_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	aoff64_t size = ext2_inode_get_size(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode);
+	EXT2FS_DBG("%" PRIu64, size);
+	return size;
+}
+
+unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	unsigned count = ext2_inode_get_usage_count(enode->inode_ref->inode);
+	EXT2FS_DBG("%u", count);
+	return count;
+}
+
+char ext2fs_plb_get_char(unsigned pos)
+{
+	return ext2fs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+bool ext2fs_is_directory(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
+	EXT2FS_DBG("%s", is_dir ? "true" : "false");
+	EXT2FS_DBG("%u", enode->inode_ref->index);
+	return is_dir;
+}
+
+bool ext2fs_is_file(fs_node_t *fn)
+{
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
+	    enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
+	EXT2FS_DBG("%s", is_file ? "true" : "false");
+	return is_file;
+}
+
+devmap_handle_t ext2fs_device_get(fs_node_t *fn)
+{
+	EXT2FS_DBG("");
+	ext2fs_node_t *enode = EXT2FS_NODE(fn);
+	return enode->instance->devmap_handle;
+}
+
+/** libfs operations */
+libfs_ops_t ext2fs_libfs_ops = {
+	.root_get = ext2fs_root_get,
+	.match = ext2fs_match,
+	.node_get = ext2fs_node_get,
+	.node_open = ext2fs_node_open,
+	.node_put = ext2fs_node_put,
+	.create = ext2fs_create_node,
+	.destroy = ext2fs_destroy_node,
+	.link = ext2fs_link,
+	.unlink = ext2fs_unlink,
+	.has_children = ext2fs_has_children,
+	.index_get = ext2fs_index_get,
+	.size_get = ext2fs_size_get,
+	.lnkcnt_get = ext2fs_lnkcnt_get,
+	.plb_get_char = ext2fs_plb_get_char,
+	.is_directory = ext2fs_is_directory,
+	.is_file = ext2fs_is_file,
+	.device_get = ext2fs_device_get
+};
+
+/*
+ * VFS operations.
+ */
+
+void ext2fs_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	int rc;
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	ext2_filesystem_t *fs;
+	ext2fs_instance_t *inst;
+	bool read_only;
+	
+	/* Accept the mount options */
+	char *opts;
+	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	free(opts);
+	
+	/* Allocate libext2 filesystem structure */
+	fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
+	if (fs == NULL) {
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	/* Allocate instance structure */
+	inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
+	if (inst == NULL) {
+		free(fs);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	/* Initialize the filesystem  */
+	rc = ext2_filesystem_init(fs, devmap_handle);
+	if (rc != EOK) {
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Do some sanity checking */
+	rc = ext2_filesystem_check_sanity(fs);
+	if (rc != EOK) {
+		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Check flags */
+	rc = ext2_filesystem_check_flags(fs, &read_only);
+	if (rc != EOK) {
+		ext2_filesystem_fini(fs);
+		free(fs);
+		free(inst);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	/* Initialize instance and add to the list */
+	link_initialize(&inst->link);
+	inst->devmap_handle = devmap_handle;
+	inst->filesystem = fs;
+	
+	fibril_mutex_lock(&instance_list_mutex);
+	list_append(&inst->link, &instance_list);
+	fibril_mutex_unlock(&instance_list_mutex);
+	
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_mount(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	ext2fs_instance_t *inst;
+	int rc;
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	// TODO: check if the fs is busy
+	
+	// Remove the instance from list
+	fibril_mutex_lock(&instance_list_mutex);
+	list_remove(&inst->link);
+	fibril_mutex_unlock(&instance_list_mutex);
+	
+	ext2_filesystem_fini(inst->filesystem);
+	
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_unmount(&ext2fs_libfs_ops, rid, request);
+}
+
+void ext2fs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_lookup(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	ext2fs_instance_t *inst;
+	ext2_inode_ref_t *inode_ref;
+	int rc;
+	
+	/*
+	 * Receive the read request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	rc = ext2fs_instance_get(devmap_handle, &inst);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_FILE)) {
+		ext2fs_read_file(rid, callid, pos, size, inst, inode_ref);
+	}
+	else if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
+		    EXT2_INODE_MODE_DIRECTORY)) {
+		ext2fs_read_directory(rid, callid, pos, size, inst, inode_ref);
+	}
+	else {
+		// Other inode types not supported
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+	}
+	
+	ext2_filesystem_put_inode_ref(inode_ref);
+	
+}
+
+/**
+ * Determine whether given directory entry name is . or ..
+ */
+bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
+	if (name_size == 1 && name[0] == '.') {
+		return true;
+	}
+	
+	if (name_size == 2 && name[0] == '.' && name[1] == '.') {
+		return true;
+	}
+	
+	return false;
+}
+
+void ext2fs_read_directory(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
+	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+{
+	ext2_directory_iterator_t it;
+	aoff64_t cur;
+	uint8_t *buf;
+	size_t name_size;
+	int rc;
+	bool found = false;
+	
+	rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	// Find the index we want to read
+	// Note that we need to iterate and count as
+	// the underlying structure is a linked list
+	// Moreover, we want to skip . and .. entries
+	// as these are not used in HelenOS
+	cur = 0;
+	while (it.current != NULL) {
+		if (it.current->inode == 0) {
+			goto skip;
+		}
+		
+		name_size = ext2_directory_entry_ll_get_name_length(
+			inst->filesystem->superblock, it.current);
+		
+		// skip . and ..
+		if (ext2fs_is_dots(&it.current->name, name_size)) {
+			goto skip;
+		}
+		
+		// Is this the dir entry we want to read?
+		if (cur == pos) {
+			// The on-disk entry does not contain \0 at the end
+			// end of entry name, so we copy it to new buffer
+			// and add the \0 at the end
+			buf = malloc(name_size+1);
+			if (buf == NULL) {
+				ext2_directory_iterator_fini(&it);
+				async_answer_0(callid, ENOMEM);
+				async_answer_0(rid, ENOMEM);
+				return;
+			}
+			memcpy(buf, &it.current->name, name_size);
+			*(buf+name_size) = 0;
+			found = true;
+			(void) async_data_read_finalize(callid, buf, name_size+1);
+			free(buf);
+			break;
+		}
+		cur++;
+		
+skip:
+		rc = ext2_directory_iterator_next(&it);
+		if (rc != EOK) {
+			ext2_directory_iterator_fini(&it);
+			async_answer_0(callid, rc);
+			async_answer_0(rid, rc);
+			return;
+		}
+	}
+	
+	rc = ext2_directory_iterator_fini(&it);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	if (found) {
+		async_answer_1(rid, EOK, 1);
+	}
+	else {
+		async_answer_0(callid, ENOENT);
+		async_answer_0(rid, ENOENT);
+	}
+}
+
+void ext2fs_read_file(ipc_callid_t rid, ipc_callid_t callid, aoff64_t pos,
+	size_t size, ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref)
+{
+	int rc;
+	uint32_t block_size;
+	aoff64_t file_block;
+	uint64_t file_size;
+	uint32_t fs_block;
+	size_t offset_in_block;
+	size_t bytes;
+	block_t *block;
+	uint8_t *buffer;
+	
+	file_size = ext2_inode_get_size(inst->filesystem->superblock,
+		inode_ref->inode);
+	
+	if (pos >= file_size) {
+		// Read 0 bytes successfully
+		async_data_read_finalize(callid, NULL, 0);
+		async_answer_1(rid, EOK, 0);
+		return;
+	}
+	
+	// For now, we only read data from one block at a time
+	block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
+	file_block = pos / block_size;
+	offset_in_block = pos % block_size;
+	bytes = min(block_size - offset_in_block, size);
+	
+	// Handle end of file
+	if (pos + bytes > file_size) {
+		bytes = file_size - pos;
+	}
+	
+	rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
+		inode_ref->inode, file_block, &fs_block);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	// Check for sparse file
+	// If ext2_filesystem_get_inode_data_block_index returned
+	// fs_block == 0, it means that the given block is not allocated for the 
+	// file and we need to return a buffer of zeros
+	if (fs_block == 0) {
+		buffer = malloc(bytes);
+		if (buffer == NULL) {
+			async_answer_0(callid, ENOMEM);
+			async_answer_0(rid, ENOMEM);
+			return;
+		}
+		
+		memset(buffer, 0, bytes);
+		
+		async_data_read_finalize(callid, buffer, bytes);
+		async_answer_1(rid, EOK, bytes);
+		
+		free(buffer);
+		
+		return;
+	}
+	
+	// Usual case - we need to read a block from device
+	rc = block_get(&block, inst->devmap_handle, fs_block, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(rid, rc);
+		return;
+	}
+	
+	assert(offset_in_block + bytes <= block_size);
+	async_data_read_finalize(callid, block->data + offset_in_block, bytes);
+	
+	rc = block_put(block);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+		
+	async_answer_1(rid, EOK, bytes);
+}
+
+void ext2fs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t pos =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+//	aoff64_t size =
+//	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	async_answer_0(rid, EOK);
+}
+
+void ext2fs_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+void ext2fs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_open_node(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+	libfs_stat(&ext2fs_libfs_ops, ext2fs_reg.fs_handle, rid, request);
+}
+
+void ext2fs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	EXT2FS_DBG("");
+//	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+//	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	
+	// TODO
+	async_answer_0(rid, ENOTSUP);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/pipefs/Makefile
===================================================================
--- uspace/srv/fs/pipefs/Makefile	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/pipefs/Makefile	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX)
+BINARY = pipefs
+
+SOURCES = \
+	pipefs.c \
+	pipefs_ops.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/pipefs/pipefs.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/pipefs/pipefs.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */ 
+
+/**
+ * @file	pipefs.c
+ * @brief	File system driver for in-memory file system.
+ *
+ * Every instance of pipefs exists purely in memory and has neither a disk layout
+ * nor any permanent storage (e.g. disk blocks). With each system reboot, data
+ * stored in a pipefs file system is lost.
+ */
+
+#include "pipefs.h"
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <task.h>
+#include <libfs.h>
+#include "../../vfs/vfs.h"
+
+#define NAME "pipefs"
+
+
+vfs_info_t pipefs_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = true,
+	.write_retains_size = true,
+};
+
+fs_reg_t pipefs_reg;
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to PIPEFS. To overcome this bottleneck, VFS can send PIPEFS the
+ * IPC_M_CONNECT_ME_TO call. In that case, a new connection fibril will be
+ * created, which in turn will accept the call. Thus, a new phone will be
+ * opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, PIPEFS can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, PIPEFS might want to keep the connections open after the
+ * request has been completed.
+ */
+static void pipefs_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	dprintf(NAME ": connection opened\n");
+	while (1) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+	
+		callid = async_get_call(&call);
+		switch  (IPC_GET_IMETHOD(call)) {
+		case IPC_M_PHONE_HUNGUP:
+			return;
+		case VFS_OUT_MOUNTED:
+			pipefs_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			pipefs_mount(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			pipefs_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			pipefs_unmount(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			pipefs_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			pipefs_read(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			pipefs_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			pipefs_truncate(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			pipefs_close(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			pipefs_destroy(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			pipefs_open_node(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			pipefs_stat(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			pipefs_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	printf(NAME ": HelenOS PIPEFS file system server\n");
+
+	if (!pipefs_init()) {
+		printf(NAME ": failed to initialize PIPEFS\n");
+		return -1;
+	}
+
+	int vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
+	if (vfs_phone < EOK) {
+		printf(NAME ": Unable to connect to VFS\n");
+		return -1;
+	}
+
+	int rc = fs_register(vfs_phone, &pipefs_reg, &pipefs_vfs_info,
+	    pipefs_connection);
+	if (rc != EOK) {
+		printf(NAME ": Failed to register file system (%d)\n", rc);
+		return rc;
+	}
+
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+}
+
+/**
+ * @}
+ */ 
Index: uspace/srv/fs/pipefs/pipefs.h
===================================================================
--- uspace/srv/fs/pipefs/pipefs.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/pipefs/pipefs.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef PIPEFS_PIPEFS_H_
+#define PIPEFS_PIPEFS_H_
+
+#include <libfs.h>
+#include <atomic.h>
+#include <sys/types.h>
+#include <bool.h>
+#include <adt/hash_table.h>
+#include <fibril_synch.h>
+
+#define PIPEFS_NODE(node)	((node) ? (pipefs_node_t *)(node)->data : NULL)
+#define FS_NODE(node)		((node) ? (node)->bp : NULL)
+
+typedef enum {
+	PIPEFS_NONE,
+	PIPEFS_FILE,
+	PIPEFS_DIRECTORY
+} pipefs_dentry_type_t;
+
+/* forward declaration */
+struct pipefs_node;
+
+typedef struct pipefs_dentry {
+	link_t link;		/**< Linkage for the list of siblings. */
+	struct pipefs_node *node;/**< Back pointer to PIPEFS node. */
+	char *name;		/**< Name of dentry. */
+} pipefs_dentry_t;
+
+typedef struct pipefs_node {
+	fs_node_t *bp;		/**< Back pointer to the FS node. */
+	fs_index_t index;	/**< PIPEFS node index. */
+	devmap_handle_t devmap_handle;/**< Device handle. */
+	link_t nh_link;		/**< Nodes hash table link. */
+	pipefs_dentry_type_t type;
+	unsigned lnkcnt;	/**< Link count. */
+	/* Following is for nodes of type PIPEFS_FILE */
+	fibril_mutex_t data_lock;
+	fibril_condvar_t data_available;
+	fibril_condvar_t data_consumed;
+	aoff64_t start;		/**< File offset where first data block resides */
+	uint8_t *data;		/**< Pointer to data buffer */
+	size_t data_size;	/**< Number of remaining bytes in the data buffer */
+	/* This is for directory */
+	link_t cs_head;		/**< Head of child's siblings list. */
+} pipefs_node_t;
+
+extern fs_reg_t pipefs_reg;
+
+extern libfs_ops_t pipefs_libfs_ops;
+
+extern bool pipefs_init(void);
+
+extern void pipefs_mounted(ipc_callid_t, ipc_call_t *);
+extern void pipefs_mount(ipc_callid_t, ipc_call_t *);
+extern void pipefs_unmounted(ipc_callid_t, ipc_call_t *);
+extern void pipefs_unmount(ipc_callid_t, ipc_call_t *);
+extern void pipefs_lookup(ipc_callid_t, ipc_call_t *);
+extern void pipefs_read(ipc_callid_t, ipc_call_t *);
+extern void pipefs_write(ipc_callid_t, ipc_call_t *);
+extern void pipefs_truncate(ipc_callid_t, ipc_call_t *);
+extern void pipefs_stat(ipc_callid_t, ipc_call_t *);
+extern void pipefs_close(ipc_callid_t, ipc_call_t *);
+extern void pipefs_destroy(ipc_callid_t, ipc_call_t *);
+extern void pipefs_open_node(ipc_callid_t, ipc_call_t *);
+extern void pipefs_sync(ipc_callid_t, ipc_call_t *);
+
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/fs/pipefs/pipefs_ops.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs_ops.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/fs/pipefs/pipefs_ops.c	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	pipefs_ops.c
+ * @brief	Implementation of VFS operations for the PIPEFS file system
+ *		server.
+ */
+
+#include "pipefs.h"
+#include "../../vfs/vfs.h"
+#include <macros.h>
+#include <stdint.h>
+#include <async.h>
+#include <errno.h>
+#include <atomic.h>
+#include <stdlib.h>
+#include <str.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <adt/hash_table.h>
+#include <as.h>
+#include <libfs.h>
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+#define max(a, b)		((a) > (b) ? (a) : (b))
+
+#define NODES_BUCKETS	256
+
+/** All root nodes have index 0. */
+#define PIPEFS_SOME_ROOT		0
+/** Global counter for assigning node indices. Shared by all instances. */
+fs_index_t pipefs_next_index = 1;
+
+/*
+ * Implementation of the libfs interface.
+ */
+
+/* Forward declarations of static functions. */
+static int pipefs_match(fs_node_t **, fs_node_t *, const char *);
+static int pipefs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
+static int pipefs_node_open(fs_node_t *);
+static int pipefs_node_put(fs_node_t *);
+static int pipefs_create_node(fs_node_t **, devmap_handle_t, int);
+static int pipefs_destroy_node(fs_node_t *);
+static int pipefs_link_node(fs_node_t *, fs_node_t *, const char *);
+static int pipefs_unlink_node(fs_node_t *, fs_node_t *, const char *);
+
+/* Implementation of helper functions. */
+static int pipefs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
+{
+	return pipefs_node_get(rfn, devmap_handle, PIPEFS_SOME_ROOT); 
+}
+
+static int pipefs_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = !list_empty(&PIPEFS_NODE(fn)->cs_head);
+	return EOK;
+}
+
+static fs_index_t pipefs_index_get(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->index;
+}
+
+static aoff64_t pipefs_size_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+static unsigned pipefs_lnkcnt_get(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->lnkcnt;
+}
+
+static char pipefs_plb_get_char(unsigned pos)
+{
+	return pipefs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+static bool pipefs_is_directory(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->type == PIPEFS_DIRECTORY;
+}
+
+static bool pipefs_is_file(fs_node_t *fn)
+{
+	return PIPEFS_NODE(fn)->type == PIPEFS_FILE;
+}
+
+static devmap_handle_t pipefs_device_get(fs_node_t *fn)
+{
+	return 0;
+}
+
+/** libfs operations */
+libfs_ops_t pipefs_libfs_ops = {
+	.root_get = pipefs_root_get,
+	.match = pipefs_match,
+	.node_get = pipefs_node_get,
+	.node_open = pipefs_node_open,
+	.node_put = pipefs_node_put,
+	.create = pipefs_create_node,
+	.destroy = pipefs_destroy_node,
+	.link = pipefs_link_node,
+	.unlink = pipefs_unlink_node,
+	.has_children = pipefs_has_children,
+	.index_get = pipefs_index_get,
+	.size_get = pipefs_size_get,
+	.lnkcnt_get = pipefs_lnkcnt_get,
+	.plb_get_char = pipefs_plb_get_char,
+	.is_directory = pipefs_is_directory,
+	.is_file = pipefs_is_file,
+	.device_get = pipefs_device_get
+};
+
+/** Hash table of all PIPEFS nodes. */
+hash_table_t nodes;
+
+#define NODES_KEY_DEV	0	
+#define NODES_KEY_INDEX	1
+
+/* Implementation of hash table interface for the nodes hash table. */
+static hash_index_t nodes_hash(unsigned long key[])
+{
+	return key[NODES_KEY_INDEX] % NODES_BUCKETS;
+}
+
+static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
+	    nh_link);
+	
+	switch (keys) {
+	case 1:
+		return (nodep->devmap_handle == key[NODES_KEY_DEV]);
+	case 2:	
+		return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
+		    (nodep->index == key[NODES_KEY_INDEX]));
+	default:
+		assert((keys == 1) || (keys == 2));
+	}
+
+	return 0;
+}
+
+static void nodes_remove_callback(link_t *item)
+{
+	pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
+	    nh_link);
+
+	while (!list_empty(&nodep->cs_head)) {
+		pipefs_dentry_t *dentryp = list_get_instance(nodep->cs_head.next,
+		    pipefs_dentry_t, link);
+
+		assert(nodep->type == PIPEFS_DIRECTORY);
+		list_remove(&dentryp->link);
+		free(dentryp);
+	}
+
+	free(nodep->bp);
+	free(nodep);
+}
+
+/** PIPEFS nodes hash table operations. */
+hash_table_operations_t nodes_ops = {
+	.hash = nodes_hash,
+	.compare = nodes_compare,
+	.remove_callback = nodes_remove_callback
+};
+
+static void pipefs_node_initialize(pipefs_node_t *nodep)
+{
+	nodep->bp = NULL;
+	nodep->index = 0;
+	nodep->devmap_handle = 0;
+	nodep->type = PIPEFS_NONE;
+	nodep->lnkcnt = 0;
+	nodep->start = 0;
+	nodep->data = NULL;
+	nodep->data_size = 0;
+	fibril_mutex_initialize(&nodep->data_lock);
+	fibril_condvar_initialize(&nodep->data_available);
+	fibril_condvar_initialize(&nodep->data_consumed);
+	link_initialize(&nodep->nh_link);
+	list_initialize(&nodep->cs_head);
+}
+
+static void pipefs_dentry_initialize(pipefs_dentry_t *dentryp)
+{
+	link_initialize(&dentryp->link);
+	dentryp->name = NULL;
+	dentryp->node = NULL;
+}
+
+bool pipefs_init(void)
+{
+	if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
+		return false;
+	
+	return true;
+}
+
+static bool pipefs_instance_init(devmap_handle_t devmap_handle)
+{
+	fs_node_t *rfn;
+	int rc;
+	
+	rc = pipefs_create_node(&rfn, devmap_handle, L_DIRECTORY);
+	if (rc != EOK || !rfn)
+		return false;
+	PIPEFS_NODE(rfn)->lnkcnt = 0;	/* FS root is not linked */
+	return true;
+}
+
+static void pipefs_instance_done(devmap_handle_t devmap_handle)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle
+	};
+	/*
+	 * Here we are making use of one special feature of our hash table
+	 * implementation, which allows to remove more items based on a partial
+	 * key match. In the following, we are going to remove all nodes
+	 * matching our device handle. The nodes_remove_callback() function will
+	 * take care of resource deallocation.
+	 */
+	hash_table_remove(&nodes, key, 1);
+}
+
+int pipefs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	link_t *lnk;
+
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		pipefs_dentry_t *dentryp;
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+		if (!str_cmp(dentryp->name, component)) {
+			*rfn = FS_NODE(dentryp->node);
+			return EOK;
+		}
+	}
+
+	*rfn = NULL;
+	return EOK;
+}
+
+int pipefs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
+{
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	link_t *lnk = hash_table_find(&nodes, key);
+	if (lnk) {
+		pipefs_node_t *nodep;
+		nodep = hash_table_get_instance(lnk, pipefs_node_t, nh_link);
+		*rfn = FS_NODE(nodep);
+	} else {
+		*rfn = NULL;
+	}
+	return EOK;	
+}
+
+int pipefs_node_open(fs_node_t *fn)
+{
+	/* nothing to do */
+	return EOK;
+}
+
+int pipefs_node_put(fs_node_t *fn)
+{
+	/* nothing to do */
+	return EOK;
+}
+
+int pipefs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
+{
+	fs_node_t *rootfn;
+	int rc;
+
+	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
+
+	pipefs_node_t *nodep = malloc(sizeof(pipefs_node_t));
+	if (!nodep)
+		return ENOMEM;
+	pipefs_node_initialize(nodep);
+	nodep->bp = malloc(sizeof(fs_node_t));
+	if (!nodep->bp) {
+		free(nodep);
+		return ENOMEM;
+	}
+	fs_node_initialize(nodep->bp);
+	nodep->bp->data = nodep;	/* link the FS and PIPEFS nodes */
+
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	assert(rc == EOK);
+	if (!rootfn)
+		nodep->index = PIPEFS_SOME_ROOT;
+	else
+		nodep->index = pipefs_next_index++;
+	nodep->devmap_handle = devmap_handle;
+	if (lflag & L_DIRECTORY) 
+		nodep->type = PIPEFS_DIRECTORY;
+	else 
+		nodep->type = PIPEFS_FILE;
+
+	/* Insert the new node into the nodes hash table. */
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_INDEX] = nodep->index
+	};
+	hash_table_insert(&nodes, key, &nodep->nh_link);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int pipefs_destroy_node(fs_node_t *fn)
+{
+	pipefs_node_t *nodep = PIPEFS_NODE(fn);
+	
+	assert(!nodep->lnkcnt);
+	assert(list_empty(&nodep->cs_head));
+
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = nodep->devmap_handle,
+		[NODES_KEY_INDEX] = nodep->index
+	};
+	hash_table_remove(&nodes, key, 2);
+
+	/*
+	 * The nodes_remove_callback() function takes care of the actual
+	 * resource deallocation.
+	 */
+	return EOK;
+}
+
+int pipefs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	pipefs_node_t *childp = PIPEFS_NODE(cfn);
+	pipefs_dentry_t *dentryp;
+	link_t *lnk;
+
+	assert(parentp->type == PIPEFS_DIRECTORY);
+
+	/* Check for duplicit entries. */
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);	
+		if (!str_cmp(dentryp->name, nm))
+			return EEXIST;
+	}
+
+	/* Allocate and initialize the dentry. */
+	dentryp = malloc(sizeof(pipefs_dentry_t));
+	if (!dentryp)
+		return ENOMEM;
+	pipefs_dentry_initialize(dentryp);
+
+	/* Populate and link the new dentry. */
+	size_t size = str_size(nm);
+	dentryp->name = malloc(size + 1);
+	if (!dentryp->name) {
+		free(dentryp);
+		return ENOMEM;
+	}
+	str_cpy(dentryp->name, size + 1, nm);
+	dentryp->node = childp;
+	childp->lnkcnt++;
+	list_append(&dentryp->link, &parentp->cs_head);
+
+	return EOK;
+}
+
+int pipefs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	pipefs_node_t *parentp = PIPEFS_NODE(pfn);
+	pipefs_node_t *childp = NULL;
+	pipefs_dentry_t *dentryp;
+	link_t *lnk;
+
+	if (!parentp)
+		return EBUSY;
+	
+	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
+	    lnk = lnk->next) {
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+		if (!str_cmp(dentryp->name, nm)) {
+			childp = dentryp->node;
+			assert(FS_NODE(childp) == cfn);
+			break;
+		}	
+	}
+
+	if (!childp)
+		return ENOENT;
+		
+	if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_head))
+		return ENOTEMPTY;
+
+	list_remove(&dentryp->link);
+	free(dentryp);
+	childp->lnkcnt--;
+
+	return EOK;
+}
+
+void pipefs_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_node_t *rootfn;
+	int rc;
+	
+	/* Accept the mount options. */
+	char *opts;
+	rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	/* Check if this device is not already mounted. */
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	if ((rc == EOK) && (rootfn)) {
+		(void) pipefs_node_put(rootfn);
+		free(opts);
+		async_answer_0(rid, EEXIST);
+		return;
+	}
+
+	/* Initialize PIPEFS instance. */
+	if (!pipefs_instance_init(devmap_handle)) {
+		free(opts);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	rc = pipefs_root_get(&rootfn, devmap_handle);
+	assert(rc == EOK);
+	pipefs_node_t *rootp = PIPEFS_NODE(rootfn);
+	async_answer_3(rid, EOK, rootp->index, 0, rootp->lnkcnt);
+	free(opts);
+}
+
+void pipefs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_mount(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+
+	pipefs_instance_done(devmap_handle);
+	async_answer_0(rid, EOK);
+}
+
+void pipefs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_unmount(&pipefs_libfs_ops, rid, request);
+}
+
+void pipefs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_lookup(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	/*
+	 * Lookup the respective PIPEFS node.
+	 */
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+	
+	/*
+	 * Receive the read request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+
+	size_t bytes;
+	if (nodep->type == PIPEFS_FILE) {
+		fibril_mutex_lock(&nodep->data_lock);
+		
+		/*
+		 * Check if the client didn't seek somewhere else
+		 */
+		if (pos != nodep->start) {
+			async_answer_0(callid, ENOTSUP);
+			async_answer_0(rid, ENOTSUP);
+			fibril_mutex_unlock(&nodep->data_lock);
+			return;
+		}
+		
+		if (nodep->data == NULL || nodep->data_size > 0) {
+			// Wait for the data
+			fibril_condvar_wait(&nodep->data_available, &nodep->data_lock);
+		}
+		
+		assert(nodep->data != NULL);
+		assert(nodep->data_size > 0);
+		
+		bytes = min(size, nodep->data_size);
+		
+		(void) async_data_read_finalize(callid, nodep->data, bytes);
+		
+		nodep->data += bytes;
+		nodep->data_size -= bytes;
+		nodep->start += bytes;
+		
+		if (nodep->data_size == 0) {
+			nodep->data = NULL;
+			fibril_condvar_broadcast(&nodep->data_consumed);
+		}
+		
+		fibril_mutex_unlock(&nodep->data_lock);
+	} else {
+		pipefs_dentry_t *dentryp;
+		link_t *lnk;
+		aoff64_t i;
+		
+		assert(nodep->type == PIPEFS_DIRECTORY);
+		
+		/*
+		 * Yes, we really use O(n) algorithm here.
+		 * If it bothers someone, it could be fixed by introducing a
+		 * hash table.
+		 */
+		for (i = 0, lnk = nodep->cs_head.next;
+		    (i < pos) && (lnk != &nodep->cs_head);
+		    i++, lnk = lnk->next)
+			;
+
+		if (lnk == &nodep->cs_head) {
+			async_answer_0(callid, ENOENT);
+			async_answer_1(rid, ENOENT, 0);
+			return;
+		}
+
+		dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
+
+		(void) async_data_read_finalize(callid, dentryp->name,
+		    str_size(dentryp->name) + 1);
+		bytes = 1;
+	}
+
+	/*
+	 * Answer the VFS_READ call.
+	 */
+	async_answer_1(rid, EOK, bytes);
+}
+
+void pipefs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos =
+	    (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
+	
+	/*
+	 * Lookup the respective PIPEFS node.
+	 */
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+
+	/*
+	 * Receive the write request.
+	 */
+	ipc_callid_t callid;
+	size_t size;
+	if (!async_data_write_receive(&callid, &size)) {
+		async_answer_0(callid, EINVAL);	
+		async_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	if (size == 0) {
+		async_data_write_finalize(callid, NULL, 0);
+		async_answer_2(rid, EOK, 0, 0);
+		return;
+	}
+	
+	fibril_mutex_lock(&nodep->data_lock);
+
+	/*
+	 * Check whether we are writing to the end
+	 */
+	if (pos != nodep->start+nodep->data_size) {
+		fibril_mutex_unlock(&nodep->data_lock);
+		async_answer_0(callid, ENOTSUP);
+		async_answer_0(rid, ENOTSUP);
+		return;
+	}
+	
+	/*
+	 * Wait until there is no data buffer
+	 */
+	if (nodep->data != NULL) {
+		fibril_condvar_wait(&nodep->data_consumed, &nodep->data_lock);
+	}
+	
+	assert(nodep->data == NULL);
+	
+	/*
+	 * Allocate a buffer for the new data.
+	 * Currently we accept any size
+	 */
+	void *newdata = malloc(size);
+	if (!newdata) {
+		fibril_mutex_unlock(&nodep->data_lock);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	(void) async_data_write_finalize(callid, newdata, size);
+	
+	nodep->data = newdata;
+	nodep->data_size = size;
+	
+	fibril_mutex_unlock(&nodep->data_lock);
+	
+	// Signal that the data is ready
+	fibril_condvar_signal(&nodep->data_available);
+	
+	fibril_mutex_lock(&nodep->data_lock);
+	
+	// Wait until all data is consumed
+	fibril_condvar_wait(&nodep->data_consumed, &nodep->data_lock);
+	
+	assert(nodep->data == NULL);
+	
+	fibril_mutex_unlock(&nodep->data_lock);
+	free(newdata);
+	
+	async_answer_2(rid, EOK, size, 0);
+}
+
+void pipefs_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+	/*
+	 * PIPEFS does not support resizing of files
+	 */
+	async_answer_0(rid, ENOTSUP);
+}
+
+void pipefs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	async_answer_0(rid, EOK);
+}
+
+void pipefs_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	int rc;
+
+	link_t *hlp;
+	unsigned long key[] = {
+		[NODES_KEY_DEV] = devmap_handle,
+		[NODES_KEY_INDEX] = index
+	};
+	hlp = hash_table_find(&nodes, key);
+	if (!hlp) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+	pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
+	    nh_link);
+	rc = pipefs_destroy_node(FS_NODE(nodep));
+	async_answer_0(rid, rc);
+}
+
+void pipefs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_open_node(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_stat(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
+}
+
+void pipefs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	/*
+	 * PIPEFS keeps its data structures always consistent,
+	 * thus the sync operation is a no-op.
+	 */
+	async_answer_0(rid, EOK);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hw/netif/ne2000/dp8390_drv.h
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390_drv.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/hw/netif/ne2000/dp8390_drv.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup dp8390
+ *  @{
+ */
+
+/** @file
+ *  DP8390 network interface driver interface.
+ */
+
+#ifndef __NET_NETIF_DP8390_DRIVER_H__
+#define __NET_NETIF_DP8390_DRIVER_H__
+
+#include "dp8390.h"
+
+/** Initializes and/or starts the network interface.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] mode The state mode.
+ *  @returns EOK on success.
+ *  @returns EXDEV if the network interface is disabled.
+ */
+int do_init(dpeth_t *dep, int mode);
+
+/** Stops the network interface.
+ *  @param[in,out] dep The network interface structure.
+ */
+void do_stop(dpeth_t *dep);
+
+/** Processes the interrupt.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] isr The interrupt status register.
+ */
+void dp_check_ints(dpeth_t *dep, int isr);
+
+/** Probes and initializes the network interface.
+ *  @param[in,out] dep The network interface structure.
+ *  @returns EOK on success.
+ *  @returns EXDEV if the network interface was not recognized.
+ */
+int do_probe(dpeth_t * dep);
+
+/** Sends a packet.
+ *  @param[in,out] dep The network interface structure.
+ *  @param[in] packet The packet t be sent.
+ *  @param[in] from_int The value indicating whether the sending is initialized from the interrupt handler.
+ *  @returns 
+ */
+int do_pwrite(dpeth_t * dep, packet_t *packet, int from_int);
+
+/** Prints out network interface information.
+ *  @param[in] dep The network interface structure.
+ */
+void dp8390_dump(dpeth_t * dep);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/dp8390_port.h
===================================================================
--- uspace/srv/hw/netif/ne2000/dp8390_port.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/hw/netif/ne2000/dp8390_port.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup dp8390
+ *  @{
+ */
+
+/** @file
+ *  DP8390 network interface types and structures ports.
+ */
+
+#ifndef __NET_NETIF_DP8390_PORT_H__
+#define __NET_NETIF_DP8390_PORT_H__
+
+#include <errno.h>
+#include <mem.h>
+#include <stdio.h>
+#include <libarch/ddi.h>
+#include <sys/types.h>
+
+/** Macro for difining functions.
+ *  @param[in] function The function type and name definition.
+ *  @param[in] params The function parameters definition.
+ */
+#define _PROTOTYPE(function, params) function params
+
+/** Success error code.
+ */
+#define OK	EOK
+
+/** Type definition of the unsigned byte.
+ */
+typedef uint8_t u8_t;
+
+/** Type definition of the unsigned short.
+ */
+typedef uint16_t u16_t;
+
+/** Compares two memory blocks.
+ *  @param[in] first The first memory block.
+ *  @param[in] second The second memory block.
+ *  @param[in] size The blocks size in bytes.
+ *  @returns 0 if equeal.
+ *  @returns -1 if the first is greater than the second.
+ *  @returns 1 if the second is greater than the first.
+ */
+#define memcmp(first, second, size)	bcmp((char *) (first), (char *) (second), (size))
+
+/** Reads 1 byte.
+ *  @param[in] port The address to be read.
+ *  @returns The read value.
+ */
+#define inb(port)	pio_read_8((ioport8_t *) (port))
+
+/** Reads 1 word (2 bytes).
+ *  @param[in] port The address to be read.
+ *  @returns The read value.
+ */
+#define inw(port)	pio_read_16((ioport16_t *) (port))
+
+/** Writes 1 byte.
+ *  @param[in] port The address to be written.
+ *  @param[in] value The value to be written.
+ */
+#define outb(port, value)	pio_write_8((ioport8_t *) (port), (value))
+
+/** Writes 1 word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param[in] value The value to be written.
+ */
+#define outw(port, value)	pio_write_16((ioport16_t *) (port), (value))
+
+/** Prints out the driver critical error.
+ *  Does not call the system panic().
+ */
+#define panic(...)	printf("%s%s%d", __VA_ARGS__)
+
+/** Copies a memory block.
+ *  @param proc The source process. Ignored parameter.
+ *  @param src_s Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param me The current proces. Ignored parameter.
+ *  @param dst_s Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ *  @returns EOK.
+ */
+#define sys_vircopy(proc, src_s, src, me, dst_s, dst, bytes)	({memcpy((void *)(dst), (void *)(src), (bytes)); EOK;})
+
+/** Reads a memory block byte by byte.
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_insb(port, proc, dst, bytes)	insb((port), (void *)(dst), (bytes))
+
+/** Reads a memory block word by word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] dst The destination address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_insw(port, proc, dst, bytes)	insw((port), (void *)(dst), (bytes))
+
+/** Writes a memory block byte by byte.
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_outsb(port, proc, src, bytes)	outsb((port), (void *)(src), (bytes))
+
+/** Writes a memory block word by word (2 bytes).
+ *  @param[in] port The address to be written.
+ *  @param proc The source process. Ignored parameter.
+ *  @param[in] src The source address.
+ *  @param[in] bytes The block size in bytes.
+ */
+#define do_vir_outsw(port, proc, src, bytes)	outsw((port), (void *)(src), (bytes))
+
+/* com.h */
+/* Bits in 'DL_MODE' field of DL requests. */
+#  define DL_NOMODE		0x0
+#  define DL_PROMISC_REQ	0x2
+#  define DL_MULTI_REQ		0x4
+#  define DL_BROAD_REQ		0x8
+
+/* const.h */
+/** True value.
+ */
+#define TRUE               1	/* used for turning integers into Booleans */
+
+/** False value.
+ */
+#define FALSE              0	/* used for turning integers into Booleans */
+
+/** No number value.
+ */
+#define NO_NUM        0x8000	/* used as numerical argument to panic() */
+
+/* devio.h */
+//typedef u16_t port_t;
+/** Type definition of a port.
+ */
+typedef long port_t;
+
+/* dl_eth.h */
+/** Ethernet statistics.
+ */
+typedef struct eth_stat
+{
+	/** Number of receive errors.
+	 */
+	unsigned long ets_recvErr;
+	/** Number of send error.
+	 */
+	unsigned long ets_sendErr;
+	/** Number of buffer overwrite warnings.
+	 */
+	unsigned long ets_OVW;
+	/** Number of crc errors of read.
+	 */
+	unsigned long ets_CRCerr;
+	/** Number of frames not alligned (number of bits % 8 != 0).
+	 */
+	unsigned long ets_frameAll;
+	/** Number of packets missed due to slow processing.
+	 */
+	unsigned long ets_missedP;
+	/** Number of packets received.
+	 */
+	unsigned long ets_packetR;
+	/** Number of packets transmitted.
+	 */
+	unsigned long ets_packetT;
+	/** Number of transmission defered (Tx was busy).
+	 */
+	unsigned long ets_transDef;
+	/** Number of collissions.
+	 */
+	unsigned long ets_collision;
+	/** Number of Tx aborted due to excess collisions.
+	 */
+	unsigned long ets_transAb;
+	/** Number of carrier sense lost.
+	 */
+	unsigned long ets_carrSense;
+	/** Number of FIFO underruns (processor too busy).
+	 */
+	unsigned long ets_fifoUnder;
+	/** Number of FIFO overruns (processor too busy).
+	 */
+	unsigned long ets_fifoOver;
+	/** Number of times unable to transmit collision sig.
+	 */
+	unsigned long ets_CDheartbeat;
+	/** Number of times out of window collision.
+	 */
+	unsigned long ets_OWC;
+} eth_stat_t;
+
+/* errno.h */
+/** Generic error.
+ */
+#define EGENERIC     EINVAL
+
+/* ether.h */
+/** Minimum Ethernet packet size in bytes.
+ */
+#define ETH_MIN_PACK_SIZE		  60
+
+/** Maximum Ethernet packet size in bytes.
+ */
+#define ETH_MAX_PACK_SIZE_TAGGED	1518
+
+/** Ethernet address type definition.
+ */
+typedef struct ether_addr
+{
+	/** Address data.
+	 */
+	u8_t ea_addr[6];
+} ether_addr_t;
+
+/* type.h */
+/** Type definition of the physical addresses and lengths in bytes.
+ */
+typedef unsigned long phys_bytes;
+
+/** Type definition of the virtual addresses and lengths in bytes.
+ */
+typedef unsigned long vir_bytes;
+
+/** Type definition of the input/output vector.
+ */
+typedef struct {
+	/** Address of an I/O buffer.
+	 */
+	vir_bytes iov_addr;
+	/** Sizeof an I/O buffer.
+	 */
+	vir_bytes iov_size;
+} iovec_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/local.h
===================================================================
--- uspace/srv/hw/netif/ne2000/local.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/hw/netif/ne2000/local.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * * Any deviations from these conditions require written permission from the copyright holder in advance
+ *
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Changes:
+ *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/** @addtogroup dp8390
+ *  @{
+ */
+
+/** @file
+ *  Network interface probe functions.
+ */
+
+#ifndef __NET_NETIF_DP8390_CONFIG_H__
+#define __NET_NETIF_DP8390_CONFIG_H__
+
+#include "dp8390_port.h"
+
+/*
+local.h
+*/
+
+/** WDETH switch.
+ */
+#define ENABLE_WDETH 0
+
+/** NE2000 switch.
+ */
+#define ENABLE_NE2000 1
+
+/** 3C503 switch.
+ */
+#define ENABLE_3C503 0
+
+/** PCI support switch.
+ */
+#define ENABLE_PCI 0
+
+struct dpeth;
+
+/* 3c503.c */
+/* * Probes a 3C503 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int el2_probe, (struct dpeth*dep)				);
+
+/* ne2000.c */
+/** Probes a NE2000 or NE1000 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+int ne_probe(struct dpeth * dep);
+//_PROTOTYPE(int ne_probe, (struct dpeth *dep)				);
+//_PROTOTYPE(void ne_init, (struct dpeth *dep)				);
+
+/* rtl8029.c */
+/* * Probes a RTL8029 network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int rtl_probe, (struct dpeth *dep)				);
+
+/* wdeth.c */
+/* * Probes a WDETH network interface.
+ *  @param[in] dep The network interface structure.
+ *  @returns 1 if the NE2000 network interface is present.
+ *  @returns 0 otherwise.
+ */
+//_PROTOTYPE(int wdeth_probe, (struct dpeth*dep)				);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/hw/netif/ne2000/ne2000.h
===================================================================
--- uspace/srv/hw/netif/ne2000/ne2000.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
+++ uspace/srv/hw/netif/ne2000/ne2000.h	(revision 694ca93fa1697ba7bdc8a18a613b9b84a0449ca3)
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * * Any deviations from these conditions require written permission from the copyright holder in advance
+ *
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Changes:
+ *  2009 ported to HelenOS, Lukas Mejdrech
+ */
+
+/*
+ne2000.h
+
+Created:	March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
+*/
+
+/** @addtogroup ne2k
+ *  @{
+ */
+
+/** @file
+ *  NE1000 and NE2000 network interface definitions.
+ */
+
+#ifndef __NET_NETIF_NE2000_H__
+#define __NET_NETIF_NE2000_H__
+
+#include <libarch/ddi.h>
+
+#include "dp8390_port.h"
+
+/** DP8390 register offset.
+ */
+#define NE_DP8390	0x00
+
+/** Data register.
+ */
+#define NE_DATA		0x10
+
+/** Reset register.
+ */
+#define NE_RESET	0x1F
+
+/** NE1000 data start.
+ */
+#define NE1000_START	0x2000
+
+/** NE1000 data size.
+ */
+#define NE1000_SIZE	0x2000
+
+/** NE2000 data start.
+ */
+#define NE2000_START	0x4000
+
+/** NE2000 data size.
+ */
+#define NE2000_SIZE	0x4000
+
+/** Reads 1 byte register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @returns The read value.
+ */
+#define inb_ne(dep, reg)	(inb(dep->de_base_port+reg))
+
+/** Writes 1 byte register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @param[in] data The value to be written.
+ */
+#define outb_ne(dep, reg, data)	(outb(dep->de_base_port+reg, data))
+
+/** Reads 1 word (2 bytes) register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @returns The read value.
+ */
+#define inw_ne(dep, reg)	(inw(dep->de_base_port+reg))
+
+/** Writes 1 word (2 bytes) register.
+ *  @param[in] dep The network interface structure.
+ *  @param[in] reg The register offset.
+ *  @param[in] data The value to be written.
+ */
+#define outw_ne(dep, reg, data)	(outw(dep->de_base_port+reg, data))
+
+#endif /* __NET_NETIF_NE2000_H__ */
+
+/*
+ * $PchId: ne2000.h,v 1.4 2004/08/03 12:03:20 philip Exp $
+ */
+
+/** @}
+ */
