Index: uspace/app/fdisk/fdisk.c
===================================================================
--- uspace/app/fdisk/fdisk.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/app/fdisk/fdisk.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -212,5 +212,5 @@
 	}
 
-	for (i = 0; i < LT_LIMIT; i++) {
+	for (i = LT_FIRST; i < LT_LIMIT; i++) {
 		rc = fdisk_ltype_format(i, &sltype);
 		if (rc != EOK)
Index: uspace/lib/c/generic/vbd.c
===================================================================
--- uspace/lib/c/generic/vbd.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/generic/vbd.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -43,4 +43,7 @@
 #include <vbd.h>
 
+static int vbd_get_ids_internal(vbd_t *, sysarg_t, sysarg_t, sysarg_t **,
+    size_t *);
+
 int vbd_create(vbd_t **rvbd)
 {
@@ -85,24 +88,15 @@
 }
 
-int vbd_disk_add(vbd_t *vbd, service_id_t disk_sid)
-{
-	async_exch_t *exch;
-
-	exch = async_exchange_begin(vbd->sess);
-	sysarg_t rc = async_req_1_0(exch, VBD_DISK_ADD, disk_sid);
-	async_exchange_end(exch);
-
-	return (int)rc;
-}
-
-int vbd_disk_remove(vbd_t *vbd, service_id_t disk_sid)
-{
-	async_exch_t *exch;
-
-	exch = async_exchange_begin(vbd->sess);
-	sysarg_t rc = async_req_1_0(exch, VBD_DISK_REMOVE, disk_sid);
-	async_exchange_end(exch);
-
-	return (int)rc;
+/** Get list of partitions as array of service IDs.
+ *
+ * @param vbd Virtual block device service
+ * @param data Place to store pointer to array
+ * @param count Place to store length of array (number of entries)
+ *
+ * @return EOK on success or negative error code
+ */
+int vbd_get_disks(vbd_t *vbd, service_id_t **data, size_t *count)
+{
+	return vbd_get_ids_internal(vbd, VBD_GET_DISKS, 0, data, count);
 }
 
Index: uspace/lib/c/generic/vol.c
===================================================================
--- uspace/lib/c/generic/vol.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/generic/vol.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -175,5 +175,5 @@
 }
 
-/** Get list of disks as array of service IDs.
+/** Get list of partitions as array of service IDs.
  *
  * @param vol Volume service
@@ -183,11 +183,11 @@
  * @return EOK on success or negative error code
  */
-int vol_get_disks(vol_t *vol, service_id_t **data, size_t *count)
-{
-	return vol_get_ids_internal(vol, VOL_GET_DISKS, 0, data, count);
-}
-
-/** Get disk information. */
-int vol_disk_info(vol_t *vol, service_id_t sid, vol_disk_info_t *vinfo)
+int vol_get_parts(vol_t *vol, service_id_t **data, size_t *count)
+{
+	return vol_get_ids_internal(vol, VOL_GET_PARTS, 0, data, count);
+}
+
+/** Get partition information. */
+int vol_part_info(vol_t *vol, service_id_t sid, vol_part_info_t *vinfo)
 {
 	async_exch_t *exch;
@@ -196,5 +196,5 @@
 
 	exch = async_exchange_begin(vol->sess);
-	retval = async_req_1_3(exch, VOL_DISK_INFO, sid, &dcnt, &ltype,
+	retval = async_req_1_3(exch, VOL_PART_INFO, sid, &dcnt, &ltype,
 	    &flags);
 	async_exchange_end(exch);
@@ -209,6 +209,7 @@
 }
 
-/** Create new label. */
-int vol_label_create(vol_t *vol, service_id_t sid, label_type_t ltype)
+/** Erase partition (to the extent where we will consider it not containing
+ * a file system. */
+int vol_part_empty(vol_t *vol, service_id_t sid)
 {
 	async_exch_t *exch;
@@ -216,5 +217,5 @@
 
 	exch = async_exchange_begin(vol->sess);
-	retval = async_req_2_0(exch, VOL_LABEL_CREATE, sid, ltype);
+	retval = async_req_1_0(exch, VOL_PART_EMPTY, sid);
 	async_exchange_end(exch);
 
@@ -225,21 +226,4 @@
 }
 
-/** Erase disk (to the extent where we will consider it not containing
- * a label or file system. */
-int vol_disk_empty(vol_t *vol, service_id_t sid)
-{
-	async_exch_t *exch;
-	int retval;
-
-	exch = async_exchange_begin(vol->sess);
-	retval = async_req_1_0(exch, VOL_DISK_EMPTY, sid);
-	async_exchange_end(exch);
-
-	if (retval != EOK)
-		return EIO;
-
-	return EOK;
-}
-
 /** @}
  */
Index: uspace/lib/c/include/ipc/vbd.h
===================================================================
--- uspace/lib/c/include/ipc/vbd.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/include/ipc/vbd.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -37,6 +37,5 @@
 
 typedef enum {
-	VBD_DISK_ADD = IPC_FIRST_USER_METHOD,
-	VBD_DISK_REMOVE,
+	VBD_GET_DISKS = IPC_FIRST_USER_METHOD,
 	VBD_DISK_INFO,
 	VBD_LABEL_CREATE,
Index: uspace/lib/c/include/ipc/vol.h
===================================================================
--- uspace/lib/c/include/ipc/vol.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/include/ipc/vol.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -37,8 +37,7 @@
 
 typedef enum {
-	VOL_GET_DISKS = IPC_FIRST_USER_METHOD,
-	VOL_DISK_INFO,
-	VOL_LABEL_CREATE,
-	VOL_DISK_EMPTY
+	VOL_GET_PARTS = IPC_FIRST_USER_METHOD,
+	VOL_PART_INFO,
+	VOL_PART_EMPTY
 } vol_request_t;
 
Index: uspace/lib/c/include/types/label.h
===================================================================
--- uspace/lib/c/include/types/label.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/include/types/label.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -52,4 +52,6 @@
 /** Disk label type */
 typedef enum {
+	/** No label */
+	lt_none,
 	/** BIOS Master Boot Record */
 	lt_mbr,
@@ -58,4 +60,5 @@
 } label_type_t;
 
+#define LT_FIRST (lt_mbr)
 #define LT_LIMIT (lt_gpt + 1)
 
Index: uspace/lib/c/include/vbd.h
===================================================================
--- uspace/lib/c/include/vbd.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/include/vbd.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -93,6 +93,5 @@
 extern int vbd_create(vbd_t **);
 extern void vbd_destroy(vbd_t *);
-extern int vbd_disk_add(vbd_t *, service_id_t);
-extern int vbd_disk_remove(vbd_t *, service_id_t);
+extern int vbd_get_disks(vbd_t *, service_id_t **, size_t *);
 extern int vbd_disk_info(vbd_t *, service_id_t, vbd_disk_info_t *);
 extern int vbd_label_create(vbd_t *, service_id_t, label_type_t);
Index: uspace/lib/c/include/vol.h
===================================================================
--- uspace/lib/c/include/vol.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/c/include/vol.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -47,20 +47,19 @@
 } vol_t;
 
-/** Disk information */
+/** Partition information */
 typedef struct {
-	/** Disk contents */
+	/** Partition contents */
 	label_disk_cnt_t dcnt;
-	/** Label type, if disk contents is label */
+	/** Label type, if partition contents is label XXX */
 	label_type_t ltype;
 	/** Label flags */
 	label_flags_t flags;
-} vol_disk_info_t;
+} vol_part_info_t;
 
 extern int vol_create(vol_t **);
 extern void vol_destroy(vol_t *);
-extern int vol_get_disks(vol_t *, service_id_t **, size_t *);
-extern int vol_disk_info(vol_t *, service_id_t, vol_disk_info_t *);
-extern int vol_label_create(vol_t *, service_id_t, label_type_t);
-extern int vol_disk_empty(vol_t *, service_id_t);
+extern int vol_get_parts(vol_t *, service_id_t **, size_t *);
+extern int vol_part_info(vol_t *, service_id_t, vol_part_info_t *);
+extern int vol_part_empty(vol_t *, service_id_t);
 
 #endif
Index: uspace/lib/fdisk/src/fdisk.c
===================================================================
--- uspace/lib/fdisk/src/fdisk.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/fdisk/src/fdisk.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -133,5 +133,7 @@
 	list_initialize(&devlist->devinfos);
 
-	rc = vol_get_disks(fdisk->vol, &svcs, &count);
+	printf("vbd_get_disks()\n");
+	rc = vbd_get_disks(fdisk->vbd, &svcs, &count);
+	printf(" -> %d\n", rc);
 	if (rc != EOK) {
 		rc = EIO;
@@ -363,5 +365,5 @@
 int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
 {
-	vol_disk_info_t vinfo;
+	vbd_disk_info_t vinfo;
 	fdisk_dev_t *dev = NULL;
 	service_id_t *psids = NULL;
@@ -380,5 +382,5 @@
 	list_initialize(&dev->log_ba);
 
-	rc = vol_disk_info(fdisk->vol, sid, &vinfo);
+	rc = vbd_disk_info(fdisk->vbd, sid, &vinfo);
 	if (rc != EOK) {
 		rc = EIO;
@@ -386,8 +388,5 @@
 	}
 
-	dev->dcnt = vinfo.dcnt;
-
-	if (dev->dcnt != dc_label)
-		goto done;
+	dev->dcnt = dc_label;
 
 	printf("get label info\n");
@@ -421,5 +420,4 @@
 
 	free(psids);
-done:
 	*rdev = dev;
 	return EOK;
@@ -479,8 +477,8 @@
 int fdisk_label_get_info(fdisk_dev_t *dev, fdisk_label_info_t *info)
 {
-	vol_disk_info_t vinfo;
-	int rc;
-
-	rc = vol_disk_info(dev->fdisk->vol, dev->sid, &vinfo);
+	vbd_disk_info_t vinfo;
+	int rc;
+
+	rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &vinfo);
 	if (rc != EOK) {
 		rc = EIO;
@@ -488,5 +486,5 @@
 	}
 
-	info->dcnt = vinfo.dcnt;
+	info->dcnt = dc_label;
 	info->ltype = vinfo.ltype;
 	info->flags = vinfo.flags;
@@ -500,5 +498,5 @@
 	int rc;
 
-	rc = vol_label_create(dev->fdisk->vol, dev->sid, ltype);
+	rc = vbd_label_create(dev->fdisk->vbd, dev->sid, ltype);
 	if (rc != EOK)
 		return rc;
@@ -518,9 +516,11 @@
 	part = fdisk_part_first(dev);
 	while (part != NULL) {
-		(void) fdisk_part_destroy(part); /* XXX */
+		rc = fdisk_part_destroy(part);
+		if (rc != EOK)
+			return EIO;
 		part = fdisk_part_first(dev);
 	}
 
-	rc = vol_disk_empty(dev->fdisk->vol, dev->sid);
+	rc = vbd_label_delete(dev->fdisk->vbd, dev->sid);
 	if (rc != EOK)
 		return EIO;
@@ -685,4 +685,7 @@
 	sltype = NULL;
 	switch (ltype) {
+	case lt_none:
+		sltype = "None";
+		break;
 	case lt_mbr:
 		sltype = "MBR";
Index: uspace/lib/label/Makefile
===================================================================
--- uspace/lib/label/Makefile	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/label/Makefile	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -33,4 +33,5 @@
 
 SOURCES = \
+	src/dummy.c \
 	src/mbr.c \
 	src/gpt.c \
Index: uspace/lib/label/src/dummy.c
===================================================================
--- uspace/lib/label/src/dummy.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/lib/label/src/dummy.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup liblabel
+ * @{
+ */
+/**
+ * @file Dummy label (for disks that have no recognized label)
+ */
+
+#include <block.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdlib.h>
+
+#include "dummy.h"
+
+static int dummy_open(service_id_t, label_t **);
+static int dummy_create(service_id_t, label_t **);
+static void dummy_close(label_t *);
+static int dummy_destroy(label_t *);
+static int dummy_get_info(label_t *, label_info_t *);
+static label_part_t *dummy_part_first(label_t *);
+static label_part_t *dummy_part_next(label_part_t *);
+static void dummy_part_get_info(label_part_t *, label_part_info_t *);
+static int dummy_part_create(label_t *, label_part_spec_t *, label_part_t **);
+static int dummy_part_destroy(label_part_t *);
+static int dummy_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
+
+label_ops_t dummy_label_ops = {
+	.open = dummy_open,
+	.create = dummy_create,
+	.close = dummy_close,
+	.destroy = dummy_destroy,
+	.get_info = dummy_get_info,
+	.part_first = dummy_part_first,
+	.part_next = dummy_part_next,
+	.part_get_info = dummy_part_get_info,
+	.part_create = dummy_part_create,
+	.part_destroy = dummy_part_destroy,
+	.suggest_ptype = dummy_suggest_ptype
+};
+
+static int dummy_open(service_id_t sid, label_t **rlabel)
+{
+	label_t *label = NULL;
+	label_part_t *part = NULL;
+	size_t bsize;
+	aoff64_t nblocks;
+	uint64_t ba_min, ba_max;
+	int rc;
+
+	rc = block_get_bsize(sid, &bsize);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	rc = block_get_nblocks(sid, &nblocks);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	label = calloc(1, sizeof(label_t));
+	if (label == NULL)
+		return ENOMEM;
+
+	list_initialize(&label->parts);
+	list_initialize(&label->pri_parts);
+	list_initialize(&label->log_parts);
+
+	ba_min = 0;
+	ba_max = nblocks;
+
+	label->ops = &dummy_label_ops;
+	label->ltype = lt_none;
+	label->svc_id = sid;
+	label->ablock0 = ba_min;
+	label->anblocks = ba_max - ba_min + 1;
+	label->pri_entries = 0;
+	label->block_size = bsize;
+
+	part = calloc(1, sizeof(label_part_t));
+	if (part == NULL)
+		return ENOMEM;
+
+	part->index = 0;
+	part->block0 = ba_min;
+	part->nblocks = ba_max - ba_min;
+	part->ptype.fmt = lptf_num;
+
+	part->label = label;
+	list_append(&part->lparts, &label->parts);
+	list_append(&part->lpri, &label->pri_parts);
+
+
+	*rlabel = label;
+	return EOK;
+error:
+	free(part);
+	free(label);
+	return rc;
+}
+
+static int dummy_create(service_id_t sid, label_t **rlabel)
+{
+	return ENOTSUP;
+}
+
+static void dummy_close(label_t *label)
+{
+	label_part_t *part;
+
+	part = dummy_part_first(label);
+	while (part != NULL) {
+		list_remove(&part->lparts);
+		list_remove(&part->lpri);
+		free(part);
+		part = dummy_part_first(label);
+	}
+
+	free(label);
+}
+
+static int dummy_destroy(label_t *label)
+{
+	return ENOTSUP;
+}
+
+static int dummy_get_info(label_t *label, label_info_t *linfo)
+{
+	memset(linfo, 0, sizeof(label_info_t));
+	linfo->dcnt = dc_label;
+	linfo->ltype = lt_none;
+	linfo->flags = 0;
+	linfo->ablock0 = label->ablock0;
+	linfo->anblocks = label->anblocks;
+	return EOK;
+}
+
+static label_part_t *dummy_part_first(label_t *label)
+{
+	link_t *link;
+
+	link = list_first(&label->parts);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, label_part_t, lparts);
+}
+
+static label_part_t *dummy_part_next(label_part_t *part)
+{
+	link_t *link;
+
+	link = list_next(&part->lparts, &part->label->parts);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, label_part_t, lparts);
+}
+
+static void dummy_part_get_info(label_part_t *part, label_part_info_t *pinfo)
+{
+	pinfo->index = part->index;
+	pinfo->pkind = lpk_primary;
+	pinfo->block0 = part->block0;
+	pinfo->nblocks = part->nblocks;
+}
+
+static int dummy_part_create(label_t *label, label_part_spec_t *pspec,
+    label_part_t **rpart)
+{
+	return ENOTSUP;
+}
+
+static int dummy_part_destroy(label_part_t *part)
+{
+	return ENOTSUP;
+}
+
+static int dummy_suggest_ptype(label_t *label, label_pcnt_t pcnt,
+    label_ptype_t *ptype)
+{
+	return ENOTSUP;
+}
+
+/** @}
+ */
Index: uspace/lib/label/src/dummy.h
===================================================================
--- uspace/lib/label/src/dummy.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/lib/label/src/dummy.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup liblabel
+ * @{
+ */
+/**
+ * @file Dummy label (fallback for disks that have no recognized label).
+ */
+
+#ifndef LIBLABEL_DUMMY_H_
+#define LIBLABEL_DUMMY_H_
+
+#include <types/liblabel.h>
+
+extern label_ops_t dummy_label_ops;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/label/src/label.c
===================================================================
--- uspace/lib/label/src/label.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/lib/label/src/label.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -40,4 +40,5 @@
 #include <stdlib.h>
 
+#include "dummy.h"
 #include "gpt.h"
 #include "mbr.h"
@@ -46,4 +47,5 @@
 	&gpt_label_ops,
 	&mbr_label_ops,
+	&dummy_label_ops,
 	NULL
 };
@@ -70,4 +72,6 @@
 
 	switch (ltype) {
+	case lt_none:
+		return EINVAL;
 	case lt_gpt:
 		ops = &gpt_label_ops;
Index: uspace/srv/bd/vbd/disk.c
===================================================================
--- uspace/srv/bd/vbd/disk.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/bd/vbd/disk.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -48,6 +48,9 @@
 #include "types/vbd.h"
 
+static fibril_mutex_t vbds_disks_lock;
 static list_t vbds_disks; /* of vbds_disk_t */
 static list_t vbds_parts; /* of vbds_part_t */
+
+static category_id_t part_cid;
 
 static int vbds_bd_open(bd_srvs_t *, bd_srv_t *);
@@ -83,9 +86,73 @@
 }
 
-void vbds_disks_init(void)
-{
+int vbds_disks_init(void)
+{
+	int rc;
+
+	fibril_mutex_initialize(&vbds_disks_lock);
 	list_initialize(&vbds_disks);
 	list_initialize(&vbds_parts);
-}
+
+	rc = loc_category_get_id("partition", &part_cid, 0);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Error looking up partition "
+		    "category.");
+		return EIO;
+	}
+
+	return EOK;
+}
+
+/** Check for new disk devices */
+static int vbds_disks_check_new(void)
+{
+	bool already_known;
+	category_id_t disk_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	int rc;
+
+	fibril_mutex_lock(&vbds_disks_lock);
+
+	rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'disk'.");
+		fibril_mutex_unlock(&vbds_disks_lock);
+		return ENOENT;
+	}
+
+	rc = loc_category_get_svcs(disk_cat, &svcs, &count);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of disk "
+		    "devices.");
+		fibril_mutex_unlock(&vbds_disks_lock);
+		return EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		already_known = false;
+
+		list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
+			if (disk->svc_id == svcs[i]) {
+				already_known = true;
+				break;
+			}
+		}
+
+		if (!already_known) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "Found disk '%lu'",
+			    (unsigned long) svcs[i]);
+			rc = vbds_disk_add(svcs[i]);
+			if (rc != EOK) {
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
+				    "disk.");
+			}
+		}
+	}
+
+	fibril_mutex_unlock(&vbds_disks_lock);
+	return EOK;
+}
+
 
 static int vbds_disk_by_svcid(service_id_t sid, vbds_disk_t **rdisk)
@@ -210,4 +277,23 @@
 }
 
+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)
 {
@@ -277,5 +363,5 @@
 		rc = vbds_part_add(disk, part, NULL);
 		if (rc != EOK) {
-			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding partitio "
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding partition "
 			    "(disk %s)", disk->svc_name);
 		}
@@ -313,4 +399,33 @@
 	block_fini(sid);
 	free(disk);
+	return EOK;
+}
+
+/** Get list of disks as array of service IDs. */
+int vbds_disk_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	fibril_mutex_lock(&vbds_disks_lock);
+
+	buf_cnt = buf_size / sizeof(service_id_t);
+
+	act_cnt = list_count(&vbds_disks);
+	*act_size = act_cnt * sizeof(service_id_t);
+
+	if (buf_size % sizeof(service_id_t) != 0) {
+		fibril_mutex_unlock(&vbds_disks_lock);
+		return EINVAL;
+	}
+
+	size_t pos = 0;
+	list_foreach(vbds_disks, ldisks, vbds_disk_t, disk) {
+		if (pos < buf_cnt)
+			id_buf[pos] = disk->svc_id;
+		pos++;
+	}
+
+	fibril_mutex_unlock(&vbds_disks_lock);
 	return EOK;
 }
@@ -751,7 +866,22 @@
 	if (rc != EOK) {
 		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering "
-		    "service %s.", name);
+		    "service %s (%d).", name, rc);
 		free(name);
 		free(part);
+		return EIO;
+	}
+
+	rc = loc_service_add_to_cat(psid, part_cid);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failled adding partition "
+		    "service %s to partition category.", name);
+		free(name);
+		free(part);
+
+		rc = loc_service_unregister(psid);
+		if (rc != EOK) {
+			log_msg(LOG_DEFAULT, LVL_ERROR, "Error unregistering "
+			    "service. Rollback failed.");
+		}
 		return EIO;
 	}
Index: uspace/srv/bd/vbd/disk.h
===================================================================
--- uspace/srv/bd/vbd/disk.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/bd/vbd/disk.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -42,7 +42,9 @@
 #include <vbd.h>
 
-extern void vbds_disks_init(void);
+extern int vbds_disks_init(void);
+extern int vbds_disk_discovery_start(void);
 extern int vbds_disk_add(service_id_t);
 extern int vbds_disk_remove(service_id_t);
+extern int vbds_disk_get_ids(service_id_t *, size_t, size_t *);
 extern int vbds_disk_info(service_id_t, vbd_disk_info_t *);
 extern int vbds_get_parts(service_id_t, service_id_t *, size_t, size_t *);
Index: uspace/srv/bd/vbd/vbd.c
===================================================================
--- uspace/srv/bd/vbd/vbd.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/bd/vbd/vbd.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -60,5 +60,11 @@
 	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_init()");
 
-	vbds_disks_init();
+	rc = vbds_disks_init();
+	if (rc != EOK)
+		return rc;
+
+	rc = vbds_disk_discovery_start();
+	if (rc != EOK)
+		return rc;
 
 	async_set_client_connection(vbds_client_conn);
@@ -79,27 +85,35 @@
 }
 
-
-static void vbds_disk_add_srv(ipc_callid_t iid, ipc_call_t *icall)
-{
-	service_id_t disk_sid;
-	int rc;
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_add_srv()");
-
-	disk_sid = IPC_GET_ARG1(*icall);
-	rc = vbds_disk_add(disk_sid);
-	async_answer_0(iid, (sysarg_t) rc);
-}
-
-static void vbds_disk_remove_srv(ipc_callid_t iid, ipc_call_t *icall)
-{
-	service_id_t disk_sid;
-	int rc;
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_remove_srv()");
-
-	disk_sid = IPC_GET_ARG1(*icall);
-	rc = vbds_disk_remove(disk_sid);
-	async_answer_0(iid, (sysarg_t) rc);
+static void vbds_get_disks_srv(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	int rc;
+
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+
+	service_id_t *id_buf = (service_id_t *) malloc(size);
+	if (id_buf == NULL) {
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+
+	rc = vbds_disk_get_ids(id_buf, size, &act_size);
+	if (rc != EOK) {
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	sysarg_t retval = async_data_read_finalize(callid, id_buf, size);
+	free(id_buf);
+
+	async_answer_1(iid, retval, act_size);
 }
 
@@ -362,9 +376,6 @@
 
 		switch (method) {
-		case VBD_DISK_ADD:
-			vbds_disk_add_srv(callid, &call);
-			break;
-		case VBD_DISK_REMOVE:
-			vbds_disk_remove_srv(callid, &call);
+		case VBD_GET_DISKS:
+			vbds_get_disks_srv(callid, &call);
 			break;
 		case VBD_DISK_INFO:
Index: uspace/srv/locsrv/locsrv.c
===================================================================
--- uspace/srv/locsrv/locsrv.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/locsrv/locsrv.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -1328,4 +1328,7 @@
 	categ_dir_add_cat(&cdir, cat);
 
+	cat = category_new("partition");
+	categ_dir_add_cat(&cdir, cat);
+
 	cat = category_new("iplink");
 	categ_dir_add_cat(&cdir, cat);
Index: uspace/srv/volsrv/Makefile
===================================================================
--- uspace/srv/volsrv/Makefile	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/volsrv/Makefile	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -31,5 +31,5 @@
 
 SOURCES = \
-	disk.c \
+	part.c \
 	volsrv.c
 
Index: uspace/srv/volsrv/disk.c
===================================================================
--- uspace/srv/volsrv/disk.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ 	(revision )
@@ -1,309 +1,0 @@
-/*
- * Copyright (c) 2015 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup volsrv
- * @{
- */
-/**
- * @file Disk device handling
- * @brief
- */
-
-#include <stdbool.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <io/log.h>
-#include <loc.h>
-#include <stdlib.h>
-#include <str.h>
-#include <vbd.h>
-
-#include "disk.h"
-#include "types/disk.h"
-
-static int vol_disk_add(service_id_t);
-
-static LIST_INITIALIZE(vol_disks); /* of vol_disk_t */
-static FIBRIL_MUTEX_INITIALIZE(vol_disks_lock);
-static vbd_t *vbd;
-
-/** Check for new disk devices */
-static int vol_disk_check_new(void)
-{
-	bool already_known;
-	category_id_t disk_cat;
-	service_id_t *svcs;
-	size_t count, i;
-	int rc;
-
-	fibril_mutex_lock(&vol_disks_lock);
-
-	rc = loc_category_get_id("disk", &disk_cat, IPC_FLAG_BLOCKING);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'disk'.");
-		fibril_mutex_unlock(&vol_disks_lock);
-		return ENOENT;
-	}
-
-	rc = loc_category_get_svcs(disk_cat, &svcs, &count);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of disk "
-		    "devices.");
-		fibril_mutex_unlock(&vol_disks_lock);
-		return EIO;
-	}
-
-	for (i = 0; i < count; i++) {
-		already_known = false;
-
-		list_foreach(vol_disks, ldisks, vol_disk_t, disk) {
-			if (disk->svc_id == svcs[i]) {
-				already_known = true;
-				break;
-			}
-		}
-
-		if (!already_known) {
-			log_msg(LOG_DEFAULT, LVL_NOTE, "Found disk '%lu'",
-			    (unsigned long) svcs[i]);
-			rc = vol_disk_add(svcs[i]);
-			if (rc != EOK) {
-				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
-				    "disk.");
-			}
-		}
-	}
-
-	fibril_mutex_unlock(&vol_disks_lock);
-	return EOK;
-}
-
-static vol_disk_t *vol_disk_new(void)
-{
-	vol_disk_t *disk = calloc(1, sizeof(vol_disk_t));
-
-	if (disk == NULL) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating disk "
-		    "structure. Out of memory.");
-		return NULL;
-	}
-
-	link_initialize(&disk->ldisks);
-	disk->dcnt = dc_empty;
-
-	return disk;
-}
-
-static void vol_disk_delete(vol_disk_t *disk)
-{
-	if (disk == NULL)
-		return;
-
-	free(disk->svc_name);
-	free(disk);
-}
-
-static int vol_disk_add(service_id_t sid)
-{
-	vol_disk_t *disk;
-	vbd_disk_info_t dinfo;
-	int rc;
-
-	assert(fibril_mutex_is_locked(&vol_disks_lock));
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "vol_disk_add()");
-	disk = vol_disk_new();
-	if (disk == NULL)
-		return ENOMEM;
-
-	disk->svc_id = sid;
-
-	rc = loc_service_get_name(sid, &disk->svc_name);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
-		goto error;
-	}
-
-	log_msg(LOG_DEFAULT, LVL_NOTE, "Probe disk %s", disk->svc_name);
-
-	rc = vbd_disk_add(vbd, sid);
-	if (rc == EOK) {
-		log_msg(LOG_DEFAULT, LVL_NOTE, "Disk %s accepted by VBD.",
-		    disk->svc_name);
-
-		rc = vbd_disk_info(vbd, sid, &dinfo);
-		log_msg(LOG_DEFAULT, LVL_NOTE, "Got disk info.");
-		if (rc != EOK) {
-			log_msg(LOG_DEFAULT, LVL_NOTE, "Cannot get disk label "
-			    "information.");
-			rc = EIO;
-			goto error;
-		}
-
-		disk->dcnt = dc_label;
-		disk->ltype = dinfo.ltype;
-	} else {
-		log_msg(LOG_DEFAULT, LVL_NOTE, "Disk %s not accepted by VBD.",
-		    disk->svc_name);
-		disk->dcnt = dc_unknown;
-	}
-
-	list_append(&disk->ldisks, &vol_disks);
-
-	return EOK;
-
-error:
-	vol_disk_delete(disk);
-	return rc;
-}
-
-static void vol_disk_cat_change_cb(void)
-{
-	(void) vol_disk_check_new();
-}
-
-int vol_disk_init(void)
-{
-	int rc;
-
-	rc = vbd_create(&vbd);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed initializing VBD.");
-		return EIO;
-	}
-
-	return EOK;
-}
-
-int vol_disk_discovery_start(void)
-{
-	int rc;
-
-	rc = loc_register_cat_change_cb(vol_disk_cat_change_cb);
-	if (rc != EOK) {
-		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
-		    "for disk discovery (%d).", rc);
-		return rc;
-	}
-
-	return vol_disk_check_new();
-}
-
-/** Get list of disks as array of service IDs. */
-int vol_disk_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
-{
-	size_t act_cnt;
-	size_t buf_cnt;
-
-	fibril_mutex_lock(&vol_disks_lock);
-
-	buf_cnt = buf_size / sizeof(service_id_t);
-
-	act_cnt = list_count(&vol_disks);
-	*act_size = act_cnt * sizeof(service_id_t);
-
-	if (buf_size % sizeof(service_id_t) != 0) {
-		fibril_mutex_unlock(&vol_disks_lock);
-		return EINVAL;
-	}
-
-	size_t pos = 0;
-	list_foreach(vol_disks, ldisks, vol_disk_t, disk) {
-		if (pos < buf_cnt)
-			id_buf[pos] = disk->svc_id;
-		pos++;
-	}
-
-	fibril_mutex_unlock(&vol_disks_lock);
-	return EOK;
-}
-
-int vol_disk_find_by_id(service_id_t sid, vol_disk_t **rdisk)
-{
-	list_foreach(vol_disks, ldisks, vol_disk_t, disk) {
-		if (disk->svc_id == sid) {
-			*rdisk = disk;
-			/* XXX Add reference */
-			return EOK;
-		}
-	}
-
-	return ENOENT;
-}
-
-int vol_disk_label_create(vol_disk_t *disk, label_type_t ltype)
-{
-	int rc;
-
-	rc = vbd_label_create(vbd, disk->svc_id, ltype);
-	if (rc != EOK)
-		return rc;
-
-	disk->dcnt = dc_label;
-	disk->ltype = ltype;
-
-	return EOK;
-}
-
-int vol_disk_empty_disk(vol_disk_t *disk)
-{
-	int rc;
-
-	if (disk->dcnt == dc_label) {
-		rc = vbd_label_delete(vbd, disk->svc_id);
-		if (rc != EOK)
-			return rc;
-	}
-
-	disk->dcnt = dc_empty;
-
-	return EOK;
-}
-
-int vol_disk_get_info(vol_disk_t *disk, vol_disk_info_t *dinfo)
-{
-	vbd_disk_info_t vdinfo;
-	int rc;
-
-	dinfo->dcnt = disk->dcnt;
-
-	if (disk->dcnt == dc_label) {
-		rc = vbd_disk_info(vbd, disk->svc_id, &vdinfo);
-		if (rc != EOK)
-			return rc;
-
-		dinfo->ltype = vdinfo.ltype;
-		dinfo->flags = vdinfo.flags;
-	}
-
-	return EOK;
-}
-
-
-/** @}
- */
Index: uspace/srv/volsrv/disk.h
===================================================================
--- uspace/srv/volsrv/disk.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2015 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup volsrv
- * @{
- */
-/**
- * @file
- * @brief
- */
-
-#ifndef DISK_H_
-#define DISK_H_
-
-#include <sys/types.h>
-#include <vol.h>
-#include "types/disk.h"
-
-extern int vol_disk_init(void);
-extern int vol_disk_discovery_start(void);
-extern int vol_disk_get_ids(service_id_t *, size_t, size_t *);
-extern int vol_disk_find_by_id(service_id_t, vol_disk_t **);
-extern int vol_disk_label_create(vol_disk_t *, label_type_t);
-extern int vol_disk_empty_disk(vol_disk_t *);
-extern int vol_disk_get_info(vol_disk_t *, vol_disk_info_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/volsrv/part.c
===================================================================
--- uspace/srv/volsrv/part.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/srv/volsrv/part.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup volsrv
+ * @{
+ */
+/**
+ * @file Partition handling
+ * @brief
+ */
+
+#include <stdbool.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <io/log.h>
+#include <loc.h>
+#include <stdlib.h>
+#include <str.h>
+
+#include "part.h"
+#include "types/part.h"
+
+static int vol_part_add(service_id_t);
+
+static LIST_INITIALIZE(vol_parts); /* of vol_part_t */
+static FIBRIL_MUTEX_INITIALIZE(vol_parts_lock);
+
+/** Check for new partitions */
+static int vol_part_check_new(void)
+{
+	bool already_known;
+	category_id_t part_cat;
+	service_id_t *svcs;
+	size_t count, i;
+	int rc;
+
+	fibril_mutex_lock(&vol_parts_lock);
+
+	rc = loc_category_get_id("partition", &part_cat, IPC_FLAG_BLOCKING);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'partition'.");
+		fibril_mutex_unlock(&vol_parts_lock);
+		return ENOENT;
+	}
+
+	rc = loc_category_get_svcs(part_cat, &svcs, &count);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of partition "
+		    "devices.");
+		fibril_mutex_unlock(&vol_parts_lock);
+		return EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		already_known = false;
+
+		list_foreach(vol_parts, lparts, vol_part_t, part) {
+			if (part->svc_id == svcs[i]) {
+				already_known = true;
+				break;
+			}
+		}
+
+		if (!already_known) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "Found partition '%lu'",
+			    (unsigned long) svcs[i]);
+			rc = vol_part_add(svcs[i]);
+			if (rc != EOK) {
+				log_msg(LOG_DEFAULT, LVL_ERROR, "Could not add "
+				    "partition.");
+			}
+		}
+	}
+
+	fibril_mutex_unlock(&vol_parts_lock);
+	return EOK;
+}
+
+static vol_part_t *vol_part_new(void)
+{
+	vol_part_t *part = calloc(1, sizeof(vol_part_t));
+
+	if (part == NULL) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating partition "
+		    "structure. Out of memory.");
+		return NULL;
+	}
+
+	link_initialize(&part->lparts);
+	part->dcnt = dc_empty;
+
+	return part;
+}
+
+static void vol_part_delete(vol_part_t *part)
+{
+	if (part == NULL)
+		return;
+
+	free(part->svc_name);
+	free(part);
+}
+
+static int vol_part_add(service_id_t sid)
+{
+	vol_part_t *part;
+	int rc;
+
+	assert(fibril_mutex_is_locked(&vol_parts_lock));
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vol_part_add()");
+	part = vol_part_new();
+	if (part == NULL)
+		return ENOMEM;
+
+	part->svc_id = sid;
+
+	rc = loc_service_get_name(sid, &part->svc_name);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Probe partition %s", part->svc_name);
+
+	part->dcnt = dc_unknown;
+	list_append(&part->lparts, &vol_parts);
+
+	return EOK;
+
+error:
+	vol_part_delete(part);
+	return rc;
+}
+
+static void vol_part_cat_change_cb(void)
+{
+	(void) vol_part_check_new();
+}
+
+int vol_part_init(void)
+{
+	return EOK;
+}
+
+int vol_part_discovery_start(void)
+{
+	int rc;
+
+	rc = loc_register_cat_change_cb(vol_part_cat_change_cb);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback "
+		    "for partition discovery (%d).", rc);
+		return rc;
+	}
+
+	return vol_part_check_new();
+}
+
+/** Get list of partitions as array of service IDs. */
+int vol_part_get_ids(service_id_t *id_buf, size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	fibril_mutex_lock(&vol_parts_lock);
+
+	buf_cnt = buf_size / sizeof(service_id_t);
+
+	act_cnt = list_count(&vol_parts);
+	*act_size = act_cnt * sizeof(service_id_t);
+
+	if (buf_size % sizeof(service_id_t) != 0) {
+		fibril_mutex_unlock(&vol_parts_lock);
+		return EINVAL;
+	}
+
+	size_t pos = 0;
+	list_foreach(vol_parts, lparts, vol_part_t, part) {
+		if (pos < buf_cnt)
+			id_buf[pos] = part->svc_id;
+		pos++;
+	}
+
+	fibril_mutex_unlock(&vol_parts_lock);
+	return EOK;
+}
+
+int vol_part_find_by_id(service_id_t sid, vol_part_t **rpart)
+{
+	list_foreach(vol_parts, lparts, vol_part_t, part) {
+		if (part->svc_id == sid) {
+			*rpart = part;
+			/* XXX Add reference */
+			return EOK;
+		}
+	}
+
+	return ENOENT;
+}
+
+int vol_part_empty_part(vol_part_t *part)
+{
+	part->dcnt = dc_empty;
+
+	return EOK;
+}
+
+int vol_part_get_info(vol_part_t *part, vol_part_info_t *dinfo)
+{
+	dinfo->dcnt = part->dcnt;
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/srv/volsrv/part.h
===================================================================
--- uspace/srv/volsrv/part.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/srv/volsrv/part.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup volsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef PART_H_
+#define pART_H_
+
+#include <sys/types.h>
+#include <vol.h>
+#include "types/part.h"
+
+extern int vol_part_init(void);
+extern int vol_part_discovery_start(void);
+extern int vol_part_get_ids(service_id_t *, size_t, size_t *);
+extern int vol_part_find_by_id(service_id_t, vol_part_t **);
+extern int vol_part_empty_part(vol_part_t *);
+extern int vol_part_get_info(vol_part_t *, vol_part_info_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/volsrv/types/disk.h
===================================================================
--- uspace/srv/volsrv/types/disk.h	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ 	(revision )
@@ -1,59 +1,0 @@
-/*
- * Copyright (c) 2015 Jiri Svoboda
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup volsrv
- * @{
- */
-/**
- * @file
- * @brief
- */
-
-#ifndef TYPES_DISK_H_
-#define TYPES_DISK_H_
-
-#include <types/label.h>
-
-/** Disk */
-typedef struct {
-	/** Link to vol_disks */
-	link_t ldisks;
-	/** Service ID */
-	service_id_t svc_id;
-	/** Service name */
-	char *svc_name;
-	/** Disk contents */
-	label_disk_cnt_t dcnt;
-	/** Label type */
-	label_type_t ltype;
-} vol_disk_t;
-
-#endif
-
-/** @}
- */
Index: uspace/srv/volsrv/types/part.h
===================================================================
--- uspace/srv/volsrv/types/part.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
+++ uspace/srv/volsrv/types/part.h	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup volsrv
+ * @{
+ */
+/**
+ * @file
+ * @brief
+ */
+
+#ifndef TYPES_PART_H_
+#define TYPES_PART_H_
+
+#include <types/label.h>
+
+/** Partition */
+typedef struct {
+	/** Link to vol_parts */
+	link_t lparts;
+	/** Service ID */
+	service_id_t svc_id;
+	/** Service name */
+	char *svc_name;
+	/** Disk contents */
+	label_disk_cnt_t dcnt;
+	/** Label type */
+	label_type_t ltype;
+} vol_part_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/volsrv/volsrv.c
===================================================================
--- uspace/srv/volsrv/volsrv.c	(revision 0bde85234853375aa8b9101ca1141a266db29647)
+++ uspace/srv/volsrv/volsrv.c	(revision 372df8f916002c4dcfde6b3bfe02589b3c2f10da)
@@ -45,5 +45,5 @@
 #include <vol.h>
 
-#include "disk.h"
+#include "part.h"
 
 #define NAME  "volsrv"
@@ -56,9 +56,9 @@
 	log_msg(LOG_DEFAULT, LVL_DEBUG, "vol_init()");
 
-	rc = vol_disk_init();
+	rc = vol_part_init();
 	if (rc != EOK)
 		return rc;
 
-	rc = vol_disk_discovery_start();
+	rc = vol_part_discovery_start();
 	if (rc != EOK)
 		return rc;
@@ -82,5 +82,5 @@
 }
 
-static void vol_get_disks_srv(ipc_callid_t iid, ipc_call_t *icall)
+static void vol_get_parts_srv(ipc_callid_t iid, ipc_call_t *icall)
 {
 	ipc_callid_t callid;
@@ -102,5 +102,5 @@
 	}
 
-	rc = vol_disk_get_ids(id_buf, size, &act_size);
+	rc = vol_part_get_ids(id_buf, size, &act_size);
 	if (rc != EOK) {
 		async_answer_0(callid, rc);
@@ -115,13 +115,13 @@
 }
 
-static void vol_disk_info_srv(ipc_callid_t iid, ipc_call_t *icall)
+static void vol_part_info_srv(ipc_callid_t iid, ipc_call_t *icall)
 {
 	service_id_t sid;
-	vol_disk_t *disk;
-	vol_disk_info_t dinfo;
+	vol_part_t *part;
+	vol_part_info_t pinfo;
 	int rc;
 
 	sid = IPC_GET_ARG1(*icall);
-	rc = vol_disk_find_by_id(sid, &disk);
+	rc = vol_part_find_by_id(sid, &part);
 	if (rc != EOK) {
 		async_answer_0(iid, ENOENT);
@@ -129,5 +129,5 @@
 	}
 
-	rc = vol_disk_get_info(disk, &dinfo);
+	rc = vol_part_get_info(part, &pinfo);
 	if (rc != EOK) {
 		async_answer_0(iid, EIO);
@@ -135,18 +135,16 @@
 	}
 
-	async_answer_3(iid, rc, dinfo.dcnt, dinfo.ltype, dinfo.flags);
-}
-
-static void vol_label_create_srv(ipc_callid_t iid, ipc_call_t *icall)
+	async_answer_3(iid, rc, pinfo.dcnt, pinfo.ltype, pinfo.flags);
+}
+
+static void vol_part_empty_srv(ipc_callid_t iid, ipc_call_t *icall)
 {
 	service_id_t sid;
-	vol_disk_t *disk;
-	label_type_t ltype;
+	vol_part_t *part;
 	int rc;
 
 	sid = IPC_GET_ARG1(*icall);
-	ltype = IPC_GET_ARG2(*icall);
-
-	rc = vol_disk_find_by_id(sid, &disk);
+
+	rc = vol_part_find_by_id(sid, &part);
 	if (rc != EOK) {
 		async_answer_0(iid, ENOENT);
@@ -154,28 +152,5 @@
 	}
 
-	rc = vol_disk_label_create(disk, ltype);
-	if (rc != EOK) {
-		async_answer_0(iid, EIO);
-		return;
-	}
-
-	async_answer_0(iid, EOK);
-}
-
-static void vol_disk_empty_srv(ipc_callid_t iid, ipc_call_t *icall)
-{
-	service_id_t sid;
-	vol_disk_t *disk;
-	int rc;
-
-	sid = IPC_GET_ARG1(*icall);
-
-	rc = vol_disk_find_by_id(sid, &disk);
-	if (rc != EOK) {
-		async_answer_0(iid, ENOENT);
-		return;
-	}
-
-	rc = vol_disk_empty_disk(disk);
+	rc = vol_part_empty_part(part);
 	if (rc != EOK) {
 		async_answer_0(iid, EIO);
@@ -205,15 +180,12 @@
 
 		switch (method) {
-		case VOL_GET_DISKS:
-			vol_get_disks_srv(callid, &call);
+		case VOL_GET_PARTS:
+			vol_get_parts_srv(callid, &call);
 			break;
-		case VOL_DISK_INFO:
-			vol_disk_info_srv(callid, &call);
+		case VOL_PART_INFO:
+			vol_part_info_srv(callid, &call);
 			break;
-		case VOL_LABEL_CREATE:
-			vol_label_create_srv(callid, &call);
-			break;
-		case VOL_DISK_EMPTY:
-			vol_disk_empty_srv(callid, &call);
+		case VOL_PART_EMPTY:
+			vol_part_empty_srv(callid, &call);
 			break;
 		default:
