Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision 4b11571f9ef913e6736d4f664b1c4964eebb2677)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 36d852c81b0cd5dc20eb486f72e3451ade4780a2)
@@ -113,4 +113,7 @@
 			tmpfs_lookup(callid, &call);
 			break;
+		case VFS_READ:
+			tmpfs_read(callid, &call);
+			break;
 		default:
 			ipc_answer_0(callid, ENOTSUP);
Index: uspace/srv/fs/tmpfs/tmpfs.h
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.h	(revision 4b11571f9ef913e6736d4f664b1c4964eebb2677)
+++ uspace/srv/fs/tmpfs/tmpfs.h	(revision 36d852c81b0cd5dc20eb486f72e3451ade4780a2)
@@ -39,9 +39,11 @@
 #include <sys/types.h>
 #include <bool.h>
+#include <libadt/hash_table.h>
 
 #define dprintf(...)	printf(__VA_ARGS__)
 
 typedef struct tmpfs_dentry {
-	unsigned index;		/**< TMPFS node index. */
+	unsigned long index;	/**< TMPFS node index. */
+	link_t dh_link;		/**< Dentries hash table link. */
 	struct tmpfs_dentry *parent;
 	struct tmpfs_dentry *sibling;
@@ -60,4 +62,5 @@
 
 extern void tmpfs_lookup(ipc_callid_t, ipc_call_t *);
+extern void tmpfs_read(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 4b11571f9ef913e6736d4f664b1c4964eebb2677)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 36d852c81b0cd5dc20eb486f72e3451ade4780a2)
@@ -46,6 +46,43 @@
 #include <string.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <libadt/hash_table.h>
+#include <as.h>
+
+#define min(a, b)		((a) < (b) ? (a) : (b))
+#define max(a, b)		((a) > (b) ? (a) : (b))
 
 #define PLB_GET_CHAR(i)		(tmpfs_reg.plb_ro[(i) % PLB_SIZE])
+
+#define DENTRIES_BUCKETS	256
+
+/*
+ * Hash table of all directory entries.
+ */
+hash_table_t dentries;
+
+static hash_index_t dentries_hash(unsigned long *key)
+{
+	return *key % DENTRIES_BUCKETS;
+}
+
+static int dentries_compare(unsigned long *key, hash_count_t keys,
+    link_t *item)
+{
+	tmpfs_dentry_t *dentry = hash_table_get_instance(item, tmpfs_dentry_t,
+	    dh_link);
+	return dentry->index == *key;
+}
+
+static void dentries_remove_callback(link_t *item)
+{
+}
+
+/** TMPFS dentries hash table operations. */
+hash_table_operations_t dentries_ops = {
+	.hash = dentries_hash,
+	.compare = dentries_compare,
+	.remove_callback = dentries_remove_callback
+};
 
 unsigned tmpfs_next_index = 1;
@@ -61,4 +98,5 @@
 	dentry->size = 0;
 	dentry->data = NULL;
+	link_initialize(&dentry->dh_link);
 }
 
@@ -71,12 +109,15 @@
 static bool tmpfs_init(void)
 {
+	if (!hash_table_create(&dentries, DENTRIES_BUCKETS, 1, &dentries_ops))
+		return false;
+
 	root = (tmpfs_dentry_t *) malloc(sizeof(tmpfs_dentry_t));
-	if (!root) {
-		return false;
-	}
+	if (!root)
+		return false;
 	tmpfs_dentry_initialize(root);
 	root->index = tmpfs_next_index++;
 	root->name = "";
 	root->type = TMPFS_DIRECTORY;
+	hash_table_insert(&dentries, &root->index, &root->dh_link);
 
 	/*
@@ -97,4 +138,5 @@
 	d->type = TMPFS_DIRECTORY;
 	d->name = "dir1";
+	hash_table_insert(&dentries, &d->index, &d->dh_link);
 
 	d = (tmpfs_dentry_t *) malloc(sizeof(tmpfs_dentry_t));
@@ -111,4 +153,5 @@
 	d->type = TMPFS_DIRECTORY;
 	d->name = "dir2";
+	hash_table_insert(&dentries, &d->index, &d->dh_link);
 	
 	d = (tmpfs_dentry_t *) malloc(sizeof(tmpfs_dentry_t));
@@ -128,4 +171,5 @@
 	d->data = "This is the contents of /dir1/file1.\n";
 	d->size = strlen(d->data);
+	hash_table_insert(&dentries, &d->index, &d->dh_link);
 
 	d = (tmpfs_dentry_t *) malloc(sizeof(tmpfs_dentry_t));
@@ -146,4 +190,5 @@
 	d->data = "This is the contents of /dir2/file2.\n";
 	d->size = strlen(d->data);
+	hash_table_insert(&dentries, &d->index, &d->dh_link);
 
 	return true;
@@ -233,4 +278,58 @@
 }
 
+void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	int dev_handle = IPC_GET_ARG1(*request);
+	unsigned long index = IPC_GET_ARG2(*request);
+	off_t pos = IPC_GET_ARG3(*request);
+	size_t size = IPC_GET_ARG4(*request);
+
+	/*
+	 * Lookup the respective dentry.
+	 */
+	link_t *hlp;
+	hlp = hash_table_find(&dentries, &index);
+	if (!hlp) {
+		ipc_answer_0(rid, ENOENT);
+		return;
+	}
+	tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
+	    dh_link);
+
+	/*
+	 * Receive the communication area.
+	 */
+	ipc_callid_t callid;
+	ipc_call_t call;
+	callid = async_get_call(&call);
+	if (IPC_GET_METHOD(call) != IPC_M_AS_AREA_SEND) {
+		ipc_answer_0(callid, EINVAL);	
+		ipc_answer_0(rid, EINVAL);
+		return;
+	}
+
+	int flags = IPC_GET_ARG3(call);
+	if (!(flags & AS_AREA_WRITE)) {
+		ipc_answer_0(callid, EINVAL);
+		ipc_answer_0(rid, EINVAL);
+		return;
+	}
+	size_t sz = IPC_GET_ARG2(call);
+	uint8_t *buf = as_get_mappable_page(sz);
+	if (!buf) {
+		ipc_answer_0(callid, ENOMEM);
+		ipc_answer_0(rid, ENOMEM);
+		return;
+	}
+	ipc_answer_1(callid, EOK, buf);		/* commit to share the area */
+
+	size_t bytes = max(0, min(dentry->size - pos, size));
+	memcpy(buf, dentry->data + pos, bytes);
+
+	(void) as_area_destroy(buf);
+
+	ipc_answer_1(rid, EOK, bytes);
+}
+
 /**
  * @}
