Index: uspace/srv/fs/pipefs/pipefs.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs.c	(revision 868ef406d879d1f4d1c4ab2c93e66bdfaf36fa43)
+++ uspace/srv/fs/pipefs/pipefs.c	(revision 66bea2437bb9d02ffae938d02247f34e80b03f21)
@@ -57,4 +57,6 @@
 vfs_info_t pipefs_vfs_info = {
 	.name = NAME,
+	.concurrent_read_write = true,
+	.write_retains_size = true,
 };
 
Index: uspace/srv/fs/pipefs/pipefs.h
===================================================================
--- uspace/srv/fs/pipefs/pipefs.h	(revision 868ef406d879d1f4d1c4ab2c93e66bdfaf36fa43)
+++ uspace/srv/fs/pipefs/pipefs.h	(revision 66bea2437bb9d02ffae938d02247f34e80b03f21)
@@ -39,4 +39,5 @@
 #include <bool.h>
 #include <adt/hash_table.h>
+#include <fibril_synch.h>
 
 #define PIPEFS_NODE(node)	((node) ? (pipefs_node_t *)(node)->data : NULL)
@@ -66,16 +67,13 @@
 	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 */
-	size_t size;		/**< File size if type is PIPEFS_FILE. */
-	link_t data_head;	/**< Head of data blocks list for PIPEFS_FILE. */
+	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. */	
+	link_t cs_head;		/**< Head of child's siblings list. */
 } pipefs_node_t;
-
-typedef struct pipefs_data_block {
-	link_t link;		/**< Linkage for the list of data blocks */
-	size_t size;		/**< Size of this block */
-	void *data;			/**< Data for this block */
-} pipefs_data_block_t;
 
 extern fs_reg_t pipefs_reg;
Index: uspace/srv/fs/pipefs/pipefs_ops.c
===================================================================
--- uspace/srv/fs/pipefs/pipefs_ops.c	(revision 868ef406d879d1f4d1c4ab2c93e66bdfaf36fa43)
+++ uspace/srv/fs/pipefs/pipefs_ops.c	(revision 66bea2437bb9d02ffae938d02247f34e80b03f21)
@@ -96,5 +96,5 @@
 static aoff64_t pipefs_size_get(fs_node_t *fn)
 {
-	return PIPEFS_NODE(fn)->size;
+	return 0;
 }
 
@@ -189,14 +189,4 @@
 	}
 
-	while (!list_empty(&nodep->data_head)) {
-		assert(nodep->type == PIPEFS_FILE);
-		
-		pipefs_data_block_t *data_block = list_get_instance(nodep->data_head.next,
-		    pipefs_data_block_t, link);
-		
-		list_remove(&data_block->link);
-		free(data_block->data);
-		free(data_block);
-	}
 	free(nodep->bp);
 	free(nodep);
@@ -218,6 +208,9 @@
 	nodep->lnkcnt = 0;
 	nodep->start = 0;
-	nodep->size = 0;
-	list_initialize(&nodep->data_head);
+	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);
@@ -479,5 +472,5 @@
 	assert(rc == EOK);
 	pipefs_node_t *rootp = PIPEFS_NODE(rootfn);
-	async_answer_3(rid, EOK, rootp->index, rootp->size, rootp->lnkcnt);
+	async_answer_3(rid, EOK, rootp->index, 0, rootp->lnkcnt);
 	free(opts);
 }
@@ -542,71 +535,38 @@
 	size_t bytes;
 	if (nodep->type == PIPEFS_FILE) {
+		fibril_mutex_lock(&nodep->data_lock);
+		
 		/*
-		 * Check if we still have the requested data.
-		 * This may happen if the client seeked backwards
+		 * Check if the client didn't seek somewhere else
 		 */
-		if (pos < nodep->start) {
+		if (pos != nodep->start) {
 			async_answer_0(callid, ENOTSUP);
 			async_answer_0(rid, ENOTSUP);
+			fibril_mutex_unlock(&nodep->data_lock);
 			return;
 		}
 		
-		/*
-		 * Free all data blocks that end before pos.
-		 * This is in case the client seeked forward 
-		 */
-		while (!list_empty(&nodep->data_head)) {
-			pipefs_data_block_t *data_block =
-			    list_get_instance(nodep->data_head.next,
-			        pipefs_data_block_t, link);
-		
-			aoff64_t block_end = nodep->start + data_block->size;
-			
-			if (block_end > pos) {
-				break;
-			}
-			
-			list_remove(&data_block->link);
-			free(data_block->data);
-			free(data_block);
-			nodep->start = block_end;
+		if (nodep->data == NULL || nodep->data_size > 0) {
+			// Wait for the data
+			fibril_condvar_wait(&nodep->data_available, &nodep->data_lock);
 		}
 		
-		if (!list_empty(&nodep->data_head)) {
-			/* We have data block, so let's return its portion after pos */
-			pipefs_data_block_t *data_block =
-			    list_get_instance(nodep->data_head.next,
-			        pipefs_data_block_t, link);
-			
-			assert(nodep->start <= pos);
-			
-			aoff64_t block_end = nodep->start + data_block->size;
-			size_t block_offset = pos - nodep->start;
-			
-			assert(block_end > pos);
-			
-			bytes = min(block_end - pos, size);
-			(void) async_data_read_finalize(callid,
-			    data_block->data + block_offset,
-			    bytes);
-			
-			if (nodep->start + block_offset + bytes == block_end) {
-				/* Free the data block - it was fully read */
-				list_remove(&data_block->link);
-				free(data_block->data);
-				free(data_block);
-				nodep->start = block_end;
-			}
+		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);
 		}
-		else {
-			/*
-			 * there is no data
-			 * TODO implement waiting for the data
-			 * and remove this else clause
-			 */
-			async_answer_0(callid, ENOTSUP);
-			async_answer_1(rid, ENOTSUP, 0);
-			return;
-		}
+		
+		fibril_mutex_unlock(&nodep->data_lock);
 	} else {
 		pipefs_dentry_t *dentryp;
@@ -678,53 +638,65 @@
 		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->size) {
+	if (pos != nodep->start+nodep->data_size) {
+		fibril_mutex_unlock(&nodep->data_lock);
 		async_answer_0(callid, ENOTSUP);
-		async_answer_2(rid, EOK, 0, nodep->size);
-		return;
-	}
+		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, create a data block from this
-	 * and append it to the end of a file
+	 * Currently we accept any size
 	 */
 	void *newdata = malloc(size);
 	if (!newdata) {
+		fibril_mutex_unlock(&nodep->data_lock);
 		async_answer_0(callid, ENOMEM);
-		async_answer_2(rid, EOK, 0, nodep->size);
-		return;
-	}
-	
-	pipefs_data_block_t *newblock = malloc(sizeof(pipefs_data_block_t));
-	
-	if (!newblock) {
-		free(newdata);
-		async_answer_0(callid, ENOMEM);
-		async_answer_2(rid, EOK, 0, nodep->size);
-		return;
-	}
-	
-	int rc = async_data_write_finalize(callid, newdata, size);
-	
-	if (rc != EOK) {
-		free(newblock);
-		free(newdata);
-		async_answer_0(callid, rc);
-		async_answer_2(rid, EOK, 0, nodep->size);
-		return;
-	}
-	
-	link_initialize(&newblock->link);
-	newblock->size = size;
-	newblock->data = newdata;
-	list_append(&newblock->link, &nodep->data_head);
-	
-	nodep->size += size;
-	
-	async_answer_2(rid, EOK, size, nodep->size);
+		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);
 }
 
