Index: uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c
===================================================================
--- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/metadata/foreign/geom/hr_g_mirror.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -62,5 +62,5 @@
 static bool meta_gmirror_has_valid_magic(const void *);
 static bool meta_gmirror_compare_uuids(const void *, const void *);
-static void meta_gmirror_inc_counter(void *);
+static void meta_gmirror_inc_counter(hr_volume_t *);
 static errno_t meta_gmirror_save(hr_volume_t *, bool);
 static const char *meta_gmirror_get_devname(const void *);
@@ -284,10 +284,14 @@
 }
 
-static void meta_gmirror_inc_counter(void *md_v)
-{
-	struct g_mirror_metadata *md = md_v;
+static void meta_gmirror_inc_counter(hr_volume_t *vol)
+{
+	fibril_mutex_lock(&vol->md_lock);
+
+	struct g_mirror_metadata *md = vol->in_mem_md;
 
 	/* XXX: probably md_genid and not md_syncid is incremented */
 	md->md_genid++;
+
+	fibril_mutex_unlock(&vol->md_lock);
 }
 
Index: uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c
===================================================================
--- uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/metadata/foreign/geom/hr_g_stripe.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -62,5 +62,5 @@
 static bool meta_gstripe_has_valid_magic(const void *);
 static bool meta_gstripe_compare_uuids(const void *, const void *);
-static void meta_gstripe_inc_counter(void *);
+static void meta_gstripe_inc_counter(hr_volume_t *);
 static errno_t meta_gstripe_save(hr_volume_t *, bool);
 static const char *meta_gstripe_get_devname(const void *);
@@ -286,7 +286,7 @@
 }
 
-static void meta_gstripe_inc_counter(void *md_v)
-{
-	(void)md_v;
+static void meta_gstripe_inc_counter(hr_volume_t *vol)
+{
+	(void)vol;
 }
 
Index: uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c
===================================================================
--- uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/metadata/foreign/softraid/hr_softraid.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -62,5 +62,5 @@
 static bool meta_softraid_has_valid_magic(const void *);
 static bool meta_softraid_compare_uuids(const void *, const void *);
-static void meta_softraid_inc_counter(void *);
+static void meta_softraid_inc_counter(hr_volume_t *);
 static errno_t meta_softraid_save(hr_volume_t *, bool);
 static const char *meta_softraid_get_devname(const void *);
@@ -419,9 +419,13 @@
 }
 
-static void meta_softraid_inc_counter(void *md_v)
-{
-	struct sr_metadata *md = md_v;
+static void meta_softraid_inc_counter(hr_volume_t *vol)
+{
+	fibril_mutex_lock(&vol->md_lock);
+
+	struct sr_metadata *md = vol->in_mem_md;
 
 	md->ssd_ondisk++;
+
+	fibril_mutex_unlock(&vol->md_lock);
 }
 
Index: uspace/srv/bd/hr/metadata/native.c
===================================================================
--- uspace/srv/bd/hr/metadata/native.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/metadata/native.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -63,5 +63,5 @@
 static bool meta_native_has_valid_magic(const void *);
 static bool meta_native_compare_uuids(const void *, const void *);
-static void meta_native_inc_counter(void *);
+static void meta_native_inc_counter(hr_volume_t *);
 static errno_t meta_native_save(hr_volume_t *, bool);
 static const char *meta_native_get_devname(const void *);
@@ -365,9 +365,13 @@
 }
 
-static void meta_native_inc_counter(void *md_v)
-{
-	hr_metadata_t *md = md_v;
+static void meta_native_inc_counter(hr_volume_t *vol)
+{
+	fibril_mutex_lock(&vol->md_lock);
+
+	hr_metadata_t *md = vol->in_mem_md;
 
 	md->counter++;
+
+	fibril_mutex_unlock(&vol->md_lock);
 }
 
@@ -409,5 +413,5 @@
 		meta_native_encode(md, md_block);
 		rc = meta_native_write_block(ext->svc_id, md_block);
-		if (with_state_callback && rc != EOK)
+		if (rc != EOK && with_state_callback)
 			vol->hr_ops.ext_state_cb(vol, i, rc);
 	}
Index: uspace/srv/bd/hr/raid1.c
===================================================================
--- uspace/srv/bd/hr/raid1.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/raid1.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -56,4 +56,5 @@
 #include "var.h"
 
+static void hr_raid1_vol_state_eval_forced(hr_volume_t *);
 static size_t hr_raid1_count_good_extents(hr_volume_t *, uint64_t, size_t,
     uint64_t);
@@ -105,7 +106,5 @@
 	new_volume->hr_bds.sarg = new_volume;
 
-	/* force volume state update */
-	hr_mark_vol_state_dirty(new_volume);
-	hr_raid1_vol_state_eval(new_volume);
+	hr_raid1_vol_state_eval_forced(new_volume);
 
 	fibril_rwlock_read_lock(&new_volume->states_lock);
@@ -155,14 +154,44 @@
 	bool exp = true;
 
-	/* TODO: could also wrap this */
 	if (!atomic_compare_exchange_strong(&vol->state_dirty, &exp, false))
 		return;
 
-	fibril_mutex_lock(&vol->md_lock);
-
-	vol->meta_ops->inc_counter(vol->in_mem_md);
-	/* XXX: save right away */
-
-	fibril_mutex_unlock(&vol->md_lock);
+	vol->meta_ops->inc_counter(vol);
+	(void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
+
+	hr_raid1_vol_state_eval_forced(vol);
+}
+
+void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent,
+    errno_t rc)
+{
+	HR_DEBUG("%s()", __func__);
+
+	if (rc == EOK)
+		return;
+
+	assert(fibril_rwlock_is_locked(&vol->extents_lock));
+
+	fibril_rwlock_write_lock(&vol->states_lock);
+
+	switch (rc) {
+	case ENOMEM:
+		hr_update_ext_state(vol, extent, HR_EXT_INVALID);
+		break;
+	case ENOENT:
+		hr_update_ext_state(vol, extent, HR_EXT_MISSING);
+		break;
+	default:
+		hr_update_ext_state(vol, extent, HR_EXT_FAILED);
+	}
+
+	hr_mark_vol_state_dirty(vol);
+
+	fibril_rwlock_write_unlock(&vol->states_lock);
+}
+
+static void hr_raid1_vol_state_eval_forced(hr_volume_t *vol)
+{
+	HR_DEBUG("%s()", __func__);
 
 	fibril_rwlock_read_lock(&vol->extents_lock);
@@ -209,32 +238,4 @@
 }
 
-void hr_raid1_ext_state_cb(hr_volume_t *vol, size_t extent,
-    errno_t rc)
-{
-	HR_DEBUG("%s()", __func__);
-
-	if (rc == EOK)
-		return;
-
-	assert(fibril_rwlock_is_locked(&vol->extents_lock));
-
-	fibril_rwlock_write_lock(&vol->states_lock);
-
-	switch (rc) {
-	case ENOMEM:
-		hr_update_ext_state(vol, extent, HR_EXT_INVALID);
-		break;
-	case ENOENT:
-		hr_update_ext_state(vol, extent, HR_EXT_MISSING);
-		break;
-	default:
-		hr_update_ext_state(vol, extent, HR_EXT_FAILED);
-	}
-
-	hr_mark_vol_state_dirty(vol);
-
-	fibril_rwlock_write_unlock(&vol->states_lock);
-}
-
 static errno_t hr_raid1_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
 {
@@ -328,4 +329,9 @@
 	if (vol_state == HR_VOL_FAULTY || vol_state == HR_VOL_NONE)
 		return EIO;
+
+	if (!vol->data_dirty && type == HR_BD_WRITE) {
+		vol->meta_ops->inc_counter(vol);
+		vol->data_dirty = true;
+	}
 
 	if (type == HR_BD_READ || type == HR_BD_WRITE)
@@ -543,5 +549,5 @@
 	fibril_rwlock_write_unlock(&vol->states_lock);
 
-	rc = vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
+	(void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
 
 end:
Index: uspace/srv/bd/hr/superblock.c
===================================================================
--- uspace/srv/bd/hr/superblock.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/superblock.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -50,9 +50,9 @@
 #include "var.h"
 
+#include "metadata/native.h"
+
 #include "metadata/foreign/geom/g_mirror.h"
 #include "metadata/foreign/geom/g_stripe.h"
 #include "metadata/foreign/softraid/softraidvar.h"
-
-#include "metadata/native.h"
 
 extern hr_superblock_ops_t metadata_native_ops;
Index: uspace/srv/bd/hr/superblock.h
===================================================================
--- uspace/srv/bd/hr/superblock.h	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/superblock.h	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -54,5 +54,5 @@
 	bool (*has_valid_magic)(const void *);
 	bool (*compare_uuids)(const void *, const void *);
-	void (*inc_counter)(void *);
+	void (*inc_counter)(hr_volume_t *);
 	errno_t (*save)(hr_volume_t *, bool);
 	const char *(*get_devname)(const void *);
Index: uspace/srv/bd/hr/util.c
===================================================================
--- uspace/srv/bd/hr/util.c	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/util.c	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -151,6 +151,7 @@
 	fibril_mutex_initialize(&vol->range_lock_list_lock);
 
+	atomic_init(&vol->state_dirty, false);
+	atomic_init(&vol->data_dirty, false);
 	atomic_init(&vol->rebuild_blk, 0);
-	atomic_init(&vol->state_dirty, false);
 	atomic_init(&vol->open_cnt, 0);
 
@@ -857,42 +858,11 @@
 	meta_ops->init_meta2vol(list, vol);
 
-	/*
-	 * TODO: something like mark md dirty or whatever
-	 *	- probably will be handled by each md type differently,
-	 *	  by specific function pointers
-	 *	- deal with this when foreign md will be handled
-	 *
-	 * XXX: if thats the only thing that can change in metadata
-	 * during volume runtime, then whatever, but if more
-	 * things will need to be synced, think of something more clever
-	 *
-	 * TODO: remove from here and increment it the "first" time (if nothing
-	 * happens - no state changes, no rebuild, etc) - only after the first
-	 * write... but for now leave it here
-	 */
-	(void)vol->meta_ops->inc_counter(vol->in_mem_md);
-
 	rc = vol->hr_ops.create(vol);
 	if (rc != EOK)
 		goto error;
 
-	/*
-	 * XXX: register it here
-	 * ... if it fails on EEXIST try different name... like + 1 on the end
-	 *
-	 * or have metadata edit utility as a part of hrctl..., or create
-	 * the original name + 4 random characters, tell the user that the device
-	 * was created with this new name, and add a option to hrctl to rename
-	 * an active array, and then write the new dirty metadata...
-	 *
-	 * or just refuse to assemble a name that is already used...
-	 *
-	 * TODO: discuss
-	 */
 	rc = hr_register_volume(vol);
 	if (rc != EOK)
 		goto error;
-
-	(void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK);
 
 	fibril_rwlock_write_lock(&hr_volumes_lock);
Index: uspace/srv/bd/hr/var.h
===================================================================
--- uspace/srv/bd/hr/var.h	(revision 83ff12f71d33c0dbac5d5f7f690e5a534f993e85)
+++ uspace/srv/bd/hr/var.h	(revision 7fba1460fce4fbe7ba78460f6556cfc3bd08f204)
@@ -101,4 +101,10 @@
 	_Atomic bool state_dirty; /* dirty state */
 
+	/*
+	 * used to increment metadata counter on first write,
+	 * allowing non-destructive read-only access
+	 */
+	_Atomic bool data_dirty;
+
 	/* XXX: atomic_uint_least64_t? */
 	_Atomic uint64_t rebuild_blk; /* rebuild position */
