Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision 6408be36c6763b9e0ae86d2f2f07dbc9247e741e)
+++ uspace/lib/libblock/libblock.c	(revision 80a3bd946652bcf9cf7b6469e7be56639abcc853)
@@ -64,4 +64,5 @@
 	size_t block_size;		/**< Block size. */
 	unsigned block_count;		/**< Total number of blocks. */
+	unsigned blocks_cached;		/**< Number of cached blocks. */
 	hash_table_t block_hash;
 	link_t free_head;
@@ -73,4 +74,5 @@
 	dev_handle_t dev_handle;
 	int dev_phone;
+	fibril_mutex_t com_area_lock;
 	void *com_area;
 	size_t com_size;
@@ -113,4 +115,5 @@
 	devcon->dev_handle = dev_handle;
 	devcon->dev_phone = dev_phone;
+	fibril_mutex_initialize(&devcon->com_area_lock);
 	devcon->com_area = com_area;
 	devcon->com_size = com_size;
@@ -212,11 +215,13 @@
 		return ENOMEM;
 	
+	fibril_mutex_lock(&devcon->com_area_lock);
 	rc = read_block(devcon, 0, size);
 	if (rc != EOK) {
+		fibril_mutex_unlock(&devcon->com_area_lock);
 	    	free(bb_buf);
 		return rc;
 	}
-
 	memcpy(bb_buf, devcon->com_area, size);
+	fibril_mutex_unlock(&devcon->com_area_lock);
 
 	devcon->bb_buf = bb_buf;
@@ -272,4 +277,5 @@
 	cache->block_size = size;
 	cache->block_count = blocks;
+	cache->blocks_cached = 0;
 	cache->mode = mode;
 
@@ -284,6 +290,12 @@
 }
 
+#define CACHE_LO_WATERMARK	10	
+#define CACHE_HI_WATERMARK	20	
 static bool cache_can_grow(cache_t *cache)
 {
+	if (cache->blocks_cached < CACHE_LO_WATERMARK)
+		return true;
+	if (!list_empty(&cache->free_head))
+		return false;
 	return true;
 }
@@ -316,4 +328,5 @@
 	link_t *l;
 	unsigned long key = boff;
+	bn_t oboff;
 	
 	devcon = devcon_search(dev_handle);
@@ -356,4 +369,5 @@
 				goto recycle;
 			}
+			cache->blocks_cached++;
 		} else {
 			/*
@@ -365,6 +379,7 @@
 			l = cache->free_head.next;
 			list_remove(l);
-			b = hash_table_get_instance(l, block_t, hash_link);
+			b = list_get_instance(l, block_t, free_link);
 			sync = b->dirty;
+			oboff = b->boff;
 			temp_key = b->boff;
 			hash_table_remove(&cache->block_hash, &temp_key, 1);
@@ -390,5 +405,9 @@
 			 * the device before we can read in the new contents.
 			 */
-			abort();	/* TODO: block_write() */
+			fibril_mutex_lock(&devcon->com_area_lock);
+			memcpy(devcon->com_area, b->data, b->size);
+			rc = write_block(devcon, oboff, cache->block_size);
+			assert(rc == EOK);
+			fibril_mutex_unlock(&devcon->com_area_lock);
 		}
 		if (!(flags & BLOCK_FLAGS_NOREAD)) {
@@ -397,7 +416,9 @@
 			 * the new contents from the device.
 			 */
+			fibril_mutex_lock(&devcon->com_area_lock);
 			rc = read_block(devcon, b->boff, cache->block_size);
 			assert(rc == EOK);
 			memcpy(b->data, devcon->com_area, cache->block_size);
+			fibril_mutex_unlock(&devcon->com_area_lock);
 		}
 
@@ -427,12 +448,41 @@
 	if (!--block->refcnt) {
 		/*
-		 * Last reference to the block was dropped, put the block on the
-		 * free list.
+		 * Last reference to the block was dropped. Either free the
+		 * block or put it on the free list.
+		 */
+		if (cache->blocks_cached > CACHE_HI_WATERMARK) {
+			/*
+			 * Currently there are too many cached blocks.
+			 */
+			if (block->dirty) {
+				fibril_mutex_lock(&devcon->com_area_lock);
+				memcpy(devcon->com_area, block->data,
+				    block->size);
+				rc = write_block(devcon, block->boff,
+				    block->size);
+				assert(rc == EOK);
+				fibril_mutex_unlock(&devcon->com_area_lock);
+			}
+			/*
+			 * Take the block out of the cache and free it.
+			 */
+			unsigned long key = block->boff;
+			hash_table_remove(&cache->block_hash, &key, 1);
+			free(block);
+			free(block->data);
+			cache->blocks_cached--;
+			fibril_mutex_unlock(&cache->lock);
+			return;
+		}
+		/*
+		 * Put the block on the free list.
 		 */
 		list_append(&block->free_link, &cache->free_head);
 		if (cache->mode != CACHE_MODE_WB && block->dirty) {
+			fibril_mutex_lock(&devcon->com_area_lock);
 			memcpy(devcon->com_area, block->data, block->size);
 			rc = write_block(devcon, block->boff, block->size);
 			assert(rc == EOK);
+			fibril_mutex_unlock(&devcon->com_area_lock);
 
 			block->dirty = false;
@@ -465,4 +515,5 @@
 	assert(devcon);
 	
+	fibril_mutex_lock(&devcon->com_area_lock);
 	while (left > 0) {
 		size_t rd;
@@ -490,6 +541,8 @@
 
 			rc = read_block(devcon, *pos / block_size, block_size);
-			if (rc != EOK)
+			if (rc != EOK) {
+				fibril_mutex_unlock(&devcon->com_area_lock);
 				return rc;
+			}
 			
 			*bufpos = 0;
@@ -497,4 +550,5 @@
 		}
 	}
+	fibril_mutex_unlock(&devcon->com_area_lock);
 	
 	return EOK;
