Index: uspace/srv/bd/vbd/disk.c
===================================================================
--- uspace/srv/bd/vbd/disk.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/srv/bd/vbd/disk.c	(revision 3a43785aa3ecab0d25624bf56ffb9c5f937cd6d8)
@@ -54,4 +54,7 @@
 static category_id_t part_cid;
 
+static int vbds_disk_parts_add(vbds_disk_t *, label_t *);
+static int vbds_disk_parts_remove(vbds_disk_t *);
+
 static int vbds_bd_open(bd_srvs_t *, bd_srv_t *);
 static int vbds_bd_close(bd_srv_t *);
@@ -242,4 +245,6 @@
 	list_append(&part->lparts, &vbds_parts);
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_add -> %p", part);
+
 	if (rpart != NULL)
 		*rpart = part;
@@ -259,6 +264,9 @@
 	lpart = part->lpart;
 
-	if (part->open_cnt > 0)
+	if (part->open_cnt > 0) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "part->open_cnt = %d",
+		    part->open_cnt);
 		return EBUSY;
+	}
 
 	if (part->svc_id != 0) {
@@ -277,85 +285,10 @@
 }
 
-static void vbds_disk_cat_change_cb(void)
-{
-	(void) vbds_disks_check_new();
-}
-
-int vbds_disk_discovery_start(void)
-{
-	int rc;
-
-	rc = loc_register_cat_change_cb(vbds_disk_cat_change_cb);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
-		    "for disk discovery (%d).", rc);
-		return rc;
-	}
-
-	return vbds_disks_check_new();
-}
-
-int vbds_disk_add(service_id_t sid)
-{
-	label_t *label = NULL;
+/** Remove all disk partitions from our inventory leaving only the underlying
+ * liblabel partition structures. */
+static int vbds_disk_parts_add(vbds_disk_t *disk, label_t *label)
+{
 	label_part_t *part;
-	vbds_disk_t *disk = NULL;
-	bool block_inited = false;
-	size_t block_size;
-	int rc;
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_add(%zu)", sid);
-
-	/* Check for duplicates */
-	rc = vbds_disk_by_svcid(sid, &disk);
-	if (rc == EOK)
-		return EEXISTS;
-
-	disk = calloc(1, sizeof(vbds_disk_t));
-	if (disk == NULL)
-		return ENOMEM;
-
-	rc = loc_service_get_name(sid, &disk->svc_name);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
-		rc = EIO;
-		goto error;
-	}
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "block_init(%zu)", sid);
-	rc = block_init(EXCHANGE_SERIALIZE, sid, 2048);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
-		    disk->svc_name);
-		rc = EIO;
-		goto error;
-	}
-
-	rc = block_get_bsize(sid, &block_size);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
-		    disk->svc_name);
-		rc = EIO;
-		goto error;
-	}
-
-	block_inited = true;
-
-	rc = label_open(sid, &label);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_NOTE, "Label in disk %s not recognized.",
-		    disk->svc_name);
-		rc = EIO;
-		goto error;
-	}
-
-	disk->svc_id = sid;
-	disk->label = label;
-	disk->block_size = block_size;
-
-	list_initialize(&disk->parts);
-	list_append(&disk->ldisks, &vbds_disks);
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "Recognized disk label. Adding partitions.");
+	int rc;
 
 	part = label_part_first(label);
@@ -365,4 +298,5 @@
 			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding partition "
 			    "(disk %s)", disk->svc_name);
+			return rc;
 		}
 
@@ -370,4 +304,110 @@
 	}
 
+	return EOK;
+}
+
+/** Remove all disk partitions from our inventory leaving only the underlying
+ * liblabel partition structures. */
+static int vbds_disk_parts_remove(vbds_disk_t *disk)
+{
+	link_t *link;
+	vbds_part_t *part;
+	int rc;
+
+	link = list_first(&disk->parts);
+	while (link != NULL) {
+		part = list_get_instance(link, vbds_part_t, ldisk);
+		rc = vbds_part_remove(part, NULL);
+		if (rc != EOK)
+			return rc;
+
+		link = list_first(&disk->parts);
+	}
+
+	return EOK;
+}
+
+static void vbds_disk_cat_change_cb(void)
+{
+	(void) vbds_disks_check_new();
+}
+
+int vbds_disk_discovery_start(void)
+{
+	int rc;
+
+	rc = loc_register_cat_change_cb(vbds_disk_cat_change_cb);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
+		    "for disk discovery (%d).", rc);
+		return rc;
+	}
+
+	return vbds_disks_check_new();
+}
+
+int vbds_disk_add(service_id_t sid)
+{
+	label_t *label = NULL;
+	vbds_disk_t *disk = NULL;
+	bool block_inited = false;
+	size_t block_size;
+	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_add(%zu)", sid);
+
+	/* Check for duplicates */
+	rc = vbds_disk_by_svcid(sid, &disk);
+	if (rc == EOK)
+		return EEXISTS;
+
+	disk = calloc(1, sizeof(vbds_disk_t));
+	if (disk == NULL)
+		return ENOMEM;
+
+	rc = loc_service_get_name(sid, &disk->svc_name);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
+		rc = EIO;
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "block_init(%zu)", sid);
+	rc = block_init(EXCHANGE_SERIALIZE, sid, 2048);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
+		    disk->svc_name);
+		rc = EIO;
+		goto error;
+	}
+
+	rc = block_get_bsize(sid, &block_size);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
+		    disk->svc_name);
+		rc = EIO;
+		goto error;
+	}
+
+	block_inited = true;
+
+	rc = label_open(sid, &label);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Failed to open label in disk %s.",
+		    disk->svc_name);
+		rc = EIO;
+		goto error;
+	}
+
+	disk->svc_id = sid;
+	disk->label = label;
+	disk->block_size = block_size;
+
+	list_initialize(&disk->parts);
+	list_append(&disk->ldisks, &vbds_disks);
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Recognized disk label. Adding partitions.");
+
+	(void) vbds_disk_parts_add(disk, label);
 	return EOK;
 error:
@@ -393,4 +433,10 @@
 	if (rc != EOK)
 		return rc;
+
+	rc = vbds_disk_parts_remove(disk);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
+		return rc;
+	}
 
 	list_remove(&disk->ldisks);
@@ -485,53 +531,28 @@
 }
 
-
 int vbds_label_create(service_id_t sid, label_type_t ltype)
 {
 	label_t *label;
 	vbds_disk_t *disk;
-	bool block_inited = false;
-	size_t block_size;
 	int rc;
 
 	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu)", sid);
 
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - chkdup", sid);
-
-	/* Check for duplicates */
+	/* Find disk */
 	rc = vbds_disk_by_svcid(sid, &disk);
-	if (rc == EOK)
-		return EEXISTS;
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - alloc", sid);
-
-	disk = calloc(1, sizeof(vbds_disk_t));
-	if (disk == NULL)
-		return ENOMEM;
-
-	rc = loc_service_get_name(sid, &disk->svc_name);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting disk service name.");
-		rc = EIO;
-		goto error;
-	}
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "block_init(%zu)", sid);
-	rc = block_init(EXCHANGE_SERIALIZE, sid, 2048);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening block device %s.",
-		    disk->svc_name);
-		rc = EIO;
-		goto error;
-	}
-
-	rc = block_get_bsize(sid, &block_size);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting block size of %s.",
-		    disk->svc_name);
-		rc = EIO;
-		goto error;
-	}
-
-	block_inited = true;
+	if (rc != EOK)
+		return rc;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - label_close", sid);
+
+	/* Close dummy label first */
+	rc = vbds_disk_parts_remove(disk);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed removing disk.");
+		return rc;
+	}
+
+	label_close(disk->label);
+	disk->label = NULL;
 
 	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - label_create", sid);
@@ -541,12 +562,6 @@
 		goto error;
 
-	disk->svc_id = sid;
+	(void) vbds_disk_parts_add(disk, label);
 	disk->label = label;
-	disk->block_size = block_size;
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create: block_size=%zu",
-	    block_size);
-	list_initialize(&disk->parts);
-
-	list_append(&disk->ldisks, &vbds_disks);
 
 	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - success", sid);
@@ -554,11 +569,12 @@
 error:
 	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create(%zu) - failure", sid);
-	if (block_inited) {
-		log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
-		block_fini(sid);
-	}
-	if (disk != NULL)
-		free(disk->svc_name);
-	free(disk);
+	if (disk->label == NULL) {
+		rc = label_open(sid, &label);
+		if (rc != EOK) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "Failed to open label in disk %s.",
+			    disk->svc_name);
+		}
+	}
+
 	return rc;
 }
@@ -567,4 +583,5 @@
 {
 	vbds_disk_t *disk;
+	label_t *label;
 	int rc;
 
@@ -575,4 +592,10 @@
 		return rc;
 
+	rc = vbds_disk_parts_remove(disk);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed deleting label.");
+		return rc;
+	}
+
 	rc = label_destroy(disk->label);
 	if (rc != EOK) {
@@ -581,8 +604,15 @@
 	}
 
-	list_remove(&disk->ldisks);
-	log_msg(LOG_DEFAULT, LVL_NOTE, "block_fini(%zu)", sid);
-	block_fini(sid);
-	free(disk);
+	disk->label = NULL;
+
+	rc = label_open(disk->svc_id, &label);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "Failed to open label in disk %s.",
+		    disk->svc_name);
+		return EIO;
+	}
+
+	(void) vbds_disk_parts_add(disk, label);
+	disk->label = label;
 	return EOK;
 }
@@ -897,4 +927,7 @@
 {
 	int rc;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_part_svc_unregister("
+	    "disk->svc_name='%s', id=%zu)", part->disk->svc_name, part->svc_id);
 
 	rc = loc_service_unregister(part->svc_id);
