Index: uspace/srv/bd/vbd/disk.c
===================================================================
--- uspace/srv/bd/vbd/disk.c	(revision f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 	(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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 	(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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 	(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 f57ccb5dbdad2edb2def6970e5d20849ccd9daa9)
+++ 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:
