Index: uspace/lib/libblock/libblock.c
===================================================================
--- uspace/lib/libblock/libblock.c	(revision 5ac89183b0e61e6f5ed1db0505b0ddee71ba32bd)
+++ uspace/lib/libblock/libblock.c	(revision ddfc39a31401f06ff111123048735c82653db1a8)
@@ -438,4 +438,6 @@
 	devcon_t *devcon = devcon_search(block->dev_handle);
 	cache_t *cache;
+	unsigned blocks_cached;
+	enum cache_mode mode;
 	int rc;
 
@@ -444,4 +446,30 @@
 
 	cache = devcon->cache;
+
+retry:
+	fibril_mutex_lock(&cache->lock);
+	blocks_cached = cache->blocks_cached;
+	mode = cache->mode;
+	fibril_mutex_unlock(&cache->lock);
+
+	/*
+	 * Determine whether to sync the block. Syncing the block is best done
+	 * when not holding the cache lock as it does not impede concurrency.
+	 * Since the situation may have changed when we unlocked the cache, the
+	 * blocks_cached and mode variables are mere hints. We will recheck the
+	 * conditions later when the cache lock is held again.
+	 */
+	fibril_mutex_lock(&block->lock);
+	if (block->dirty && (block->refcnt == 1) &&
+	    (blocks_cached > CACHE_HI_WATERMARK || mode != CACHE_MODE_WB)) {
+		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;
+	}
+	fibril_mutex_unlock(&block->lock);
+
 	fibril_mutex_lock(&cache->lock);
 	fibril_mutex_lock(&block->lock);
@@ -456,11 +484,12 @@
 			 */
 			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);
+				/*
+				 * We cannot sync the block while holding the
+				 * cache lock. Release everything and retry.
+				 */
+				block->refcnt++;
+				fibril_mutex_unlock(&block->lock);
+				fibril_mutex_unlock(&cache->lock);
+				goto retry;
 			}
 			/*
@@ -478,14 +507,15 @@
 		 * Put the block on the free list.
 		 */
+		if (cache->mode != CACHE_MODE_WB && block->dirty) {
+			/*
+			 * We cannot sync the block while holding the cache
+			 * lock. Release everything and retry.
+			 */
+			block->refcnt++;
+			fibril_mutex_unlock(&block->lock);
+			fibril_mutex_unlock(&cache->lock);
+			goto retry;
+		}
 		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;
-		}
 	}
 	fibril_mutex_unlock(&block->lock);
