Index: uspace/srv/bd/hr/raid0.c
===================================================================
--- uspace/srv/bd/hr/raid0.c	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/raid0.c	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -181,5 +181,5 @@
 	if (vol->status == HR_VOL_ONLINE)
 		return EOK;
-	return EINVAL;
+	return EIO;
 }
 
@@ -190,15 +190,17 @@
 static errno_t hr_raid0_update_vol_status(hr_volume_t *vol)
 {
+	hr_vol_status_t old_state = vol->status;
+
 	for (size_t i = 0; i < vol->extent_no; i++) {
 		if (vol->extents[i].status != HR_EXT_ONLINE) {
-			HR_WARN("RAID 0 needs all extents to be ONLINE, "
-			    "marking \"%s\" (%lu) as FAULTY",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_FAULTY;
-			return EINVAL;
+			if (old_state != HR_VOL_FAULTY)
+				hr_update_vol_status(vol, HR_VOL_FAULTY);
+			return EIO;
 		}
 	}
 
-	vol->status = HR_VOL_ONLINE;
+	if (old_state != HR_VOL_ONLINE)
+		hr_update_vol_status(vol, HR_VOL_ONLINE);
+
 	return EOK;
 }
@@ -244,4 +246,5 @@
 
 	left = cnt;
+
 	while (left != 0) {
 		phys_block = ext_stripe * strip_size + strip_off;
Index: uspace/srv/bd/hr/raid1.c
===================================================================
--- uspace/srv/bd/hr/raid1.c	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/raid1.c	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -147,5 +147,6 @@
 
 	vol->hotspares[vol->hotspare_no].svc_id = hotspare;
-	vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE;
+	hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE);
+
 	vol->hotspare_no++;
 
@@ -158,5 +159,5 @@
 		fid_t fib = fibril_create(hr_raid1_rebuild, vol);
 		if (fib == 0)
-			return EINVAL;
+			return ENOMEM;
 		fibril_start(fib);
 		fibril_detach(fib);
@@ -219,5 +220,5 @@
 	    vol->status == HR_VOL_REBUILD)
 		return EOK;
-	return EINVAL;
+	return EIO;
 }
 
@@ -232,24 +233,18 @@
 
 	if (healthy == 0) {
-		if (old_state != HR_VOL_FAULTY) {
-			HR_WARN("RAID 1 needs at least 1 extent to be"
-			    "ONLINE, marking \"%s\" (%lu) volume as FAULTY",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_FAULTY;
-		}
-		return EINVAL;
+		if (old_state != HR_VOL_FAULTY)
+			hr_update_vol_status(vol, HR_VOL_FAULTY);
+		return EIO;
 	} else if (healthy < vol->extent_no) {
 		if (old_state != HR_VOL_DEGRADED &&
 		    old_state != HR_VOL_REBUILD) {
-			HR_WARN("RAID 1 array \"%s\" (%lu) has some "
-			    "unusable extent(s), marking volume as DEGRADED",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_DEGRADED;
+
+			hr_update_vol_status(vol, HR_VOL_DEGRADED);
+
 			if (vol->hotspare_no > 0) {
 				fid_t fib = fibril_create(hr_raid1_rebuild,
 				    vol);
-				if (fib == 0) {
-					return EINVAL;
-				}
+				if (fib == 0)
+					return ENOMEM;
 				fibril_start(fib);
 				fibril_detach(fib);
@@ -258,10 +253,6 @@
 		return EOK;
 	} else {
-		if (old_state != HR_VOL_ONLINE) {
-			HR_WARN("RAID 1 array \"%s\" (%lu) has all extents "
-			    "active, marking volume as ONLINE",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_ONLINE;
-		}
+		if (old_state != HR_VOL_ONLINE)
+			hr_update_vol_status(vol, HR_VOL_ONLINE);
 		return EOK;
 	}
@@ -297,8 +288,6 @@
 
 	rc = hr_raid1_check_vol_status(vol);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&vol->lock);
-		return EIO;
-	}
+	if (rc != EOK)
+		goto end;
 
 	size_t successful = 0;
@@ -352,4 +341,5 @@
 	default:
 		rc = EINVAL;
+		goto end;
 	}
 
@@ -359,4 +349,5 @@
 		rc = EIO;
 
+end:
 	(void)hr_raid1_update_vol_status(vol);
 	fibril_mutex_unlock(&vol->lock);
@@ -400,32 +391,40 @@
 	}
 
+	size_t hotspare_idx = vol->hotspare_no - 1;
+
+	hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status;
+	if (hs_state != HR_EXT_HOTSPARE) {
+		HR_ERROR("hr_raid1_rebuild(): invalid hotspare state \"%s\", "
+		    "aborting rebuild\n", hr_get_ext_status_msg(hs_state));
+		rc = EINVAL;
+		goto end;
+	}
+
+	HR_DEBUG("hr_raid1_rebuild(): swapping in hotspare\n");
+
 	block_fini(vol->extents[bad].svc_id);
 
-	size_t hotspare_idx = vol->hotspare_no - 1;
-
-	vol->rebuild_blk = 0;
 	vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id;
-	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE);
 
 	vol->hotspares[hotspare_idx].svc_id = 0;
-	vol->hotspares[hotspare_idx].status = HR_EXT_MISSING;
+	hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING);
+
 	vol->hotspare_no--;
 
-	HR_WARN("hr_raid1_rebuild(): changing volume \"%s\" (%lu) state "
-	    "from %s to %s\n", vol->devname, vol->svc_id,
-	    hr_get_vol_status_msg(vol->status),
-	    hr_get_vol_status_msg(HR_VOL_REBUILD));
-	vol->status = HR_VOL_REBUILD;
-
-	hr_extent_t *hotspare = &vol->extents[bad];
-
-	HR_DEBUG("hr_raid1_rebuild(): initing (%lu)\n", hotspare->svc_id);
-
-	rc = block_init(hotspare->svc_id);
+	hr_extent_t *rebuild_ext = &vol->extents[bad];
+
+	rc = block_init(rebuild_ext->svc_id);
 	if (rc != EOK) {
 		HR_ERROR("hr_raid1_rebuild(): initing (%lu) failed, "
-		    "aborting rebuild\n", hotspare->svc_id);
+		    "aborting rebuild\n", rebuild_ext->svc_id);
 		goto end;
 	}
+
+	HR_DEBUG("hr_raid1_rebuild(): starting rebuild on (%lu)\n",
+	    rebuild_ext->svc_id);
+
+	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_vol_status(vol, HR_VOL_REBUILD);
 
 	size_t left = vol->data_blkno;
@@ -435,7 +434,10 @@
 	hr_extent_t *ext;
 
+	vol->rebuild_blk = 0;
+
 	size_t cnt;
 	uint64_t ba = 0;
 	hr_add_ba_offset(vol, &ba);
+
 	while (left != 0) {
 		vol->rebuild_blk = ba;
@@ -462,5 +464,5 @@
 		}
 
-		rc = block_write_direct(hotspare->svc_id, ba, cnt, buf);
+		rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, buf);
 		if (rc != EOK) {
 			hr_raid1_handle_extent_error(vol, bad, rc);
Index: uspace/srv/bd/hr/raid4.c
===================================================================
--- uspace/srv/bd/hr/raid4.c	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/raid4.c	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -161,5 +161,6 @@
 
 	vol->hotspares[vol->hotspare_no].svc_id = hotspare;
-	vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE;
+	hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE);
+
 	vol->hotspare_no++;
 
@@ -172,5 +173,5 @@
 		fid_t fib = fibril_create(hr_raid4_rebuild, vol);
 		if (fib == 0)
-			return EINVAL;
+			return ENOMEM;
 		fibril_start(fib);
 		fibril_detach(fib);
@@ -233,5 +234,5 @@
 	    vol->status == HR_VOL_REBUILD)
 		return EOK;
-	return EINVAL;
+	return EIO;
 }
 
@@ -258,24 +259,18 @@
 	switch (bad) {
 	case 0:
-		if (old_state != HR_VOL_ONLINE) {
-			HR_WARN("RAID 4 has all extents online, "
-			    "marking \"%s\" (%lu) as ONLINE",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_ONLINE;
-		}
+		if (old_state != HR_VOL_ONLINE)
+			hr_update_vol_status(vol, HR_VOL_ONLINE);
 		return EOK;
 	case 1:
 		if (old_state != HR_VOL_DEGRADED &&
 		    old_state != HR_VOL_REBUILD) {
-			HR_WARN("RAID 4 array \"%s\" (%lu) has 1 extent "
-			    "inactive, marking as DEGRADED",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_DEGRADED;
+
+			hr_update_vol_status(vol, HR_VOL_DEGRADED);
+
 			if (vol->hotspare_no > 0) {
 				fid_t fib = fibril_create(hr_raid4_rebuild,
 				    vol);
-				if (fib == 0) {
-					return EINVAL;
-				}
+				if (fib == 0)
+					return ENOMEM;
 				fibril_start(fib);
 				fibril_detach(fib);
@@ -284,11 +279,7 @@
 		return EOK;
 	default:
-		if (old_state != HR_VOL_FAULTY) {
-			HR_WARN("RAID 4 array \"%s\" (%lu) has more "
-			    "than one 1 extent unusable, marking as FAULTY",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_FAULTY;
-		}
-		return EINVAL;
+		if (old_state != HR_VOL_FAULTY)
+			hr_update_vol_status(vol, HR_VOL_FAULTY);
+		return EIO;
 	}
 }
@@ -560,4 +551,5 @@
 
 	left = cnt;
+
 	while (left != 0) {
 		phys_block = ext_stripe * strip_size + strip_off;
@@ -670,31 +662,40 @@
 	}
 
+	size_t hotspare_idx = vol->hotspare_no - 1;
+
+	hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status;
+	if (hs_state != HR_EXT_HOTSPARE) {
+		HR_ERROR("hr_raid4_rebuild(): invalid hotspare state \"%s\", "
+		    "aborting rebuild\n", hr_get_ext_status_msg(hs_state));
+		rc = EINVAL;
+		goto end;
+	}
+
+	HR_DEBUG("hr_raid4_rebuild(): swapping in hotspare\n");
+
 	block_fini(vol->extents[bad].svc_id);
 
-	size_t hotspare_idx = vol->hotspare_no - 1;
-
 	vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id;
-	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE);
 
 	vol->hotspares[hotspare_idx].svc_id = 0;
-	vol->hotspares[hotspare_idx].status = HR_EXT_MISSING;
+	hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING);
+
 	vol->hotspare_no--;
 
-	HR_WARN("hr_raid4_rebuild(): changing volume \"%s\" (%lu) state "
-	    "from %s to %s\n", vol->devname, vol->svc_id,
-	    hr_get_vol_status_msg(vol->status),
-	    hr_get_vol_status_msg(HR_VOL_REBUILD));
-	vol->status = HR_VOL_REBUILD;
-
-	hr_extent_t *hotspare = &vol->extents[bad];
-
-	HR_DEBUG("hr_raid4_rebuild(): initing (%lu)\n", hotspare->svc_id);
-
-	rc = block_init(hotspare->svc_id);
+	hr_extent_t *rebuild_ext = &vol->extents[bad];
+
+	rc = block_init(rebuild_ext->svc_id);
 	if (rc != EOK) {
 		HR_ERROR("hr_raid4_rebuild(): initing (%lu) failed, "
-		    "aborting rebuild\n", hotspare->svc_id);
+		    "aborting rebuild\n", rebuild_ext->svc_id);
 		goto end;
 	}
+
+	HR_DEBUG("hr_raid4_rebuild(): starting rebuild on (%lu)\n",
+	    rebuild_ext->svc_id);
+
+	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_vol_status(vol, HR_VOL_REBUILD);
 
 	uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize;
@@ -705,4 +706,5 @@
 	uint64_t ba = 0, cnt;
 	hr_add_ba_offset(vol, &ba);
+
 	while (left != 0) {
 		cnt = min(left, max_blks);
@@ -735,5 +737,5 @@
 		}
 
-		rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf);
+		rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf);
 		if (rc != EOK) {
 			hr_raid4_handle_extent_error(vol, bad, rc);
Index: uspace/srv/bd/hr/raid5.c
===================================================================
--- uspace/srv/bd/hr/raid5.c	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/raid5.c	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -158,5 +158,6 @@
 
 	vol->hotspares[vol->hotspare_no].svc_id = hotspare;
-	vol->hotspares[vol->hotspare_no].status = HR_EXT_HOTSPARE;
+	hr_update_hotspare_status(vol, vol->hotspare_no, HR_EXT_HOTSPARE);
+
 	vol->hotspare_no++;
 
@@ -169,5 +170,5 @@
 		fid_t fib = fibril_create(hr_raid5_rebuild, vol);
 		if (fib == 0)
-			return EINVAL;
+			return ENOMEM;
 		fibril_start(fib);
 		fibril_detach(fib);
@@ -230,5 +231,5 @@
 	    vol->status == HR_VOL_REBUILD)
 		return EOK;
-	return EINVAL;
+	return EIO;
 }
 
@@ -255,24 +256,18 @@
 	switch (bad) {
 	case 0:
-		if (old_state != HR_VOL_ONLINE) {
-			HR_WARN("RAID 5 has all extents online, "
-			    "marking \"%s\" (%lu) as ONLINE",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_ONLINE;
-		}
+		if (old_state != HR_VOL_ONLINE)
+			hr_update_vol_status(vol, HR_VOL_ONLINE);
 		return EOK;
 	case 1:
 		if (old_state != HR_VOL_DEGRADED &&
 		    old_state != HR_VOL_REBUILD) {
-			HR_WARN("RAID 5 array \"%s\" (%lu) has 1 extent "
-			    "inactive, marking as DEGRADED",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_DEGRADED;
+
+			hr_update_vol_status(vol, HR_VOL_DEGRADED);
+
 			if (vol->hotspare_no > 0) {
 				fid_t fib = fibril_create(hr_raid5_rebuild,
 				    vol);
-				if (fib == 0) {
-					return EINVAL;
-				}
+				if (fib == 0)
+					return ENOMEM;
 				fibril_start(fib);
 				fibril_detach(fib);
@@ -281,11 +276,7 @@
 		return EOK;
 	default:
-		if (old_state != HR_VOL_FAULTY) {
-			HR_WARN("RAID 5 array \"%s\" (%lu) has more "
-			    "than one 1 extent inactive, marking as FAULTY",
-			    vol->devname, vol->svc_id);
-			vol->status = HR_VOL_FAULTY;
-		}
-		return EINVAL;
+		if (old_state != HR_VOL_FAULTY)
+			hr_update_vol_status(vol, HR_VOL_FAULTY);
+		return EIO;
 	}
 }
@@ -560,4 +551,5 @@
 
 	left = cnt;
+
 	while (left != 0) {
 		phys_block = ext_stripe * strip_size + strip_off;
@@ -674,31 +666,40 @@
 	}
 
+	size_t hotspare_idx = vol->hotspare_no - 1;
+
+	hr_ext_status_t hs_state = vol->hotspares[hotspare_idx].status;
+	if (hs_state != HR_EXT_HOTSPARE) {
+		HR_ERROR("hr_raid5_rebuild(): invalid hotspare state \"%s\", "
+		    "aborting rebuild\n", hr_get_ext_status_msg(hs_state));
+		rc = EINVAL;
+		goto end;
+	}
+
+	HR_DEBUG("hr_raid5_rebuild(): swapping in hotspare\n");
+
 	block_fini(vol->extents[bad].svc_id);
 
-	size_t hotspare_idx = vol->hotspare_no - 1;
-
 	vol->extents[bad].svc_id = vol->hotspares[hotspare_idx].svc_id;
-	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_ext_status(vol, bad, HR_EXT_HOTSPARE);
 
 	vol->hotspares[hotspare_idx].svc_id = 0;
-	vol->hotspares[hotspare_idx].status = HR_EXT_MISSING;
+	hr_update_hotspare_status(vol, hotspare_idx, HR_EXT_MISSING);
+
 	vol->hotspare_no--;
 
-	HR_WARN("hr_raid5_rebuild(): changing volume \"%s\" (%lu) state "
-	    "from %s to %s\n", vol->devname, vol->svc_id,
-	    hr_get_vol_status_msg(vol->status),
-	    hr_get_vol_status_msg(HR_VOL_REBUILD));
-	vol->status = HR_VOL_REBUILD;
-
-	hr_extent_t *hotspare = &vol->extents[bad];
-
-	HR_DEBUG("hr_raid5_rebuild(): initing (%lu)\n", hotspare->svc_id);
-
-	rc = block_init(hotspare->svc_id);
+	hr_extent_t *rebuild_ext = &vol->extents[bad];
+
+	rc = block_init(rebuild_ext->svc_id);
 	if (rc != EOK) {
 		HR_ERROR("hr_raid5_rebuild(): initing (%lu) failed, "
-		    "aborting rebuild\n", hotspare->svc_id);
+		    "aborting rebuild\n", rebuild_ext->svc_id);
 		goto end;
 	}
+
+	HR_DEBUG("hr_raid5_rebuild(): starting rebuild on (%lu)\n",
+	    rebuild_ext->svc_id);
+
+	hr_update_ext_status(vol, bad, HR_EXT_REBUILD);
+	hr_update_vol_status(vol, HR_VOL_REBUILD);
 
 	uint64_t max_blks = DATA_XFER_LIMIT / vol->bsize;
@@ -709,4 +710,5 @@
 	uint64_t ba = 0, cnt;
 	hr_add_ba_offset(vol, &ba);
+
 	while (left != 0) {
 		cnt = min(left, max_blks);
@@ -741,5 +743,5 @@
 		}
 
-		rc = block_write_direct(hotspare->svc_id, ba, cnt, xorbuf);
+		rc = block_write_direct(rebuild_ext->svc_id, ba, cnt, xorbuf);
 		if (rc != EOK) {
 			hr_raid5_handle_extent_error(vol, bad, rc);
Index: uspace/srv/bd/hr/util.c
===================================================================
--- uspace/srv/bd/hr/util.c	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/util.c	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -204,9 +204,27 @@
 }
 
-void hr_update_ext_status(hr_volume_t *vol, uint64_t extent, hr_ext_status_t s)
-{
-	HR_WARN("vol %s, changing extent: %lu, to status: %s",
-	    vol->devname, extent, hr_get_ext_status_msg(s));
+void hr_update_ext_status(hr_volume_t *vol, size_t extent, hr_ext_status_t s)
+{
+	hr_ext_status_t old = vol->extents[extent].status;
+	HR_WARN("\"%s\": changing state of extent %lu: %s -> %s\n",
+	    vol->devname, extent, hr_get_ext_status_msg(old),
+	    hr_get_ext_status_msg(s));
 	vol->extents[extent].status = s;
+}
+
+void hr_update_hotspare_status(hr_volume_t *vol, size_t hs, hr_ext_status_t s)
+{
+	hr_ext_status_t old = vol->hotspares[hs].status;
+	HR_WARN("\"%s\": changing state of hotspare %lu: %s -> %s\n",
+	    vol->devname, hs, hr_get_ext_status_msg(old),
+	    hr_get_ext_status_msg(s));
+	vol->hotspares[hs].status = s;
+}
+
+void hr_update_vol_status(hr_volume_t *vol, hr_vol_status_t s)
+{
+	HR_WARN("\"%s\": changing state: %s -> %s\n", vol->devname,
+	    hr_get_vol_status_msg(vol->status), hr_get_vol_status_msg(s));
+	vol->status = s;
 }
 
Index: uspace/srv/bd/hr/util.h
===================================================================
--- uspace/srv/bd/hr/util.h	(revision 65706f1dd3b78368b8130173b8caeeba0642c1ba)
+++ uspace/srv/bd/hr/util.h	(revision a0c3080f8d662e94f980dedc844200d3cc0674f5)
@@ -56,5 +56,7 @@
 extern errno_t hr_check_ba_range(hr_volume_t *, size_t, uint64_t);
 extern void hr_add_ba_offset(hr_volume_t *, uint64_t *);
-extern void hr_update_ext_status(hr_volume_t *, uint64_t, hr_ext_status_t);
+extern void hr_update_ext_status(hr_volume_t *, size_t, hr_ext_status_t);
+extern void hr_update_hotspare_status(hr_volume_t *, size_t, hr_ext_status_t);
+extern void hr_update_vol_status(hr_volume_t *, hr_vol_status_t);
 extern void hr_sync_all_extents(hr_volume_t *);
 extern size_t hr_count_extents(hr_volume_t *, hr_ext_status_t);
