Index: uspace/lib/c/generic/vbd.c
===================================================================
--- uspace/lib/c/generic/vbd.c	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/c/generic/vbd.c	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -37,4 +37,5 @@
 #include <ipc/vbd.h>
 #include <loc.h>
+#include <macros.h>
 #include <mem.h>
 #include <stdlib.h>
@@ -106,19 +107,31 @@
 }
 
+#include <io/log.h>
 /** Get disk information. */
 int vbd_disk_info(vbd_t *vbd, service_id_t sid, vbd_disk_info_t *vinfo)
 {
 	async_exch_t *exch;
-	sysarg_t ltype;
-	int retval;
-
-	exch = async_exchange_begin(vbd->sess);
-	retval = async_req_1_1(exch, VBD_DISK_INFO, sid, &ltype);
-	async_exchange_end(exch);
-
-	if (retval != EOK)
-		return EIO;
-
-	vinfo->ltype = (label_type_t)ltype;
+	sysarg_t retval;
+	ipc_call_t answer;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_disk_info() begin exchange");
+	exch = async_exchange_begin(vbd->sess);
+	aid_t req = async_send_1(exch, VBD_DISK_INFO, sid, &answer);
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_disk_info() read start");
+	int rc = async_data_read_start(exch, vinfo, sizeof(vbd_disk_info_t));
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_disk_info() end exch");
+	async_exchange_end(exch);
+
+	if (rc != EOK) {
+		async_forget(req);
+		return EIO;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_disk_info() wait fore req reply");
+	async_wait_for(req, &retval);
+	if (retval != EOK)
+		return EIO;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "vbd_disk_info() done");
 	return EOK;
 }
@@ -257,13 +270,20 @@
 {
 	async_exch_t *exch;
-	int retval;
-
-	exch = async_exchange_begin(vbd->sess);
-	retval = async_req_1_0(exch, VBD_PART_GET_INFO, part);
-	async_exchange_end(exch);
-
-	if (retval != EOK)
-		return EIO;
-
+	sysarg_t index;
+	sysarg_t b0_lo, b0_hi;
+	sysarg_t nb_lo, nb_hi;
+	int retval;
+
+	exch = async_exchange_begin(vbd->sess);
+	retval = async_req_1_5(exch, VBD_PART_GET_INFO, part, &index,
+	    &b0_lo, &b0_hi, &nb_lo, &nb_hi);
+	async_exchange_end(exch);
+
+	if (retval != EOK)
+		return EIO;
+
+	pinfo->index = index;
+	pinfo->block0 = MERGE_LOUP32(b0_lo, b0_hi);
+	pinfo->nblocks = MERGE_LOUP32(nb_lo, nb_hi);
 	return EOK;
 }
Index: uspace/lib/c/include/vbd.h
===================================================================
--- uspace/lib/c/include/vbd.h	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/c/include/vbd.h	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -39,4 +39,5 @@
 #include <loc.h>
 #include <types/label.h>
+#include <sys/types.h>
 
 /** VBD service */
@@ -50,4 +51,10 @@
 	/** Label type */
 	label_type_t ltype;
+	/** First block that can be allocated */
+	aoff64_t ablock0;
+	/** Number of blocks that can be allocated */
+	aoff64_t anblocks;
+	/** Block size */
+	size_t block_size;
 } vbd_disk_info_t;
 
@@ -56,4 +63,10 @@
 
 typedef struct {
+	/** Partition index */
+	int index;
+	/** First block */
+	aoff64_t block0;
+	/** Number of blocks */
+	aoff64_t nblocks;
 } vbd_part_info_t;
 
Index: uspace/lib/fdisk/include/types/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/types/fdisk.h	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/fdisk/include/types/fdisk.h	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -106,6 +106,10 @@
 	/** Service ID */
 	service_id_t sid;
-	/** Partitions */
-	list_t parts; /* of fdisk_part_t */
+	/** Partitions sorted by index */
+	list_t parts_idx; /* of fdisk_part_t */
+	/** Partitions sorted by block address */
+	list_t parts_ba;
+	/** Disk info */
+	vbd_disk_info_t dinfo;
 } fdisk_dev_t;
 
@@ -121,6 +125,8 @@
 	/** Containing device */
 	fdisk_dev_t *dev;
-	/** Link to fdisk_dev_t.parts */
-	link_t ldev;
+	/** Link to fdisk_dev_t.parts_idx */
+	link_t ldev_idx;
+	/** Link to fdisk_dev_t.parts_ba */
+	link_t ldev_ba;
 	/** Capacity */
 	fdisk_cap_t capacity;
@@ -129,4 +135,10 @@
 	/** Partition ID */
 	vbd_part_id_t part_id;
+	/** Partition index */
+	int index;
+	/** First block */
+	aoff64_t block0;
+	/** Number of blocks */
+	aoff64_t nblocks;
 } fdisk_part_t;
 
Index: uspace/lib/fdisk/src/fdisk.c
===================================================================
--- uspace/lib/fdisk/src/fdisk.c	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/fdisk/src/fdisk.c	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -246,7 +246,76 @@
 }
 
+static int fdisk_part_add(fdisk_dev_t *dev, vbd_part_id_t partid,
+    fdisk_part_t **rpart)
+{
+	fdisk_part_t *part, *p;
+	vbd_part_info_t pinfo;
+	link_t *link;
+	int rc;
+
+	part = calloc(1, sizeof(fdisk_part_t));
+	if (part == NULL)
+		return ENOMEM;
+
+	rc = vbd_part_get_info(dev->fdisk->vbd, partid, &pinfo);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	part->dev = dev;
+	part->index = pinfo.index;
+	part->block0 = pinfo.block0;
+	part->nblocks = pinfo.nblocks;
+
+	/* Insert to list by block address */
+	link = list_first(&dev->parts_ba);
+	while (link != NULL) {
+		p = list_get_instance(link, fdisk_part_t, ldev_ba);
+		if (p->block0 > part->block0) {
+			list_insert_before(&part->ldev_ba, &p->ldev_ba);
+			break;
+		}
+
+		link = list_next(link, &dev->parts_ba);
+	}
+
+	if (link == NULL)
+		list_append(&part->ldev_ba, &dev->parts_ba);
+
+	/* Insert to list by index */
+	link = list_first(&dev->parts_idx);
+	while (link != NULL) {
+		p = list_get_instance(link, fdisk_part_t, ldev_idx);
+		if (p->index > part->index) {
+			list_insert_before(&part->ldev_idx, &p->ldev_idx);
+			break;
+		}
+
+		link = list_next(link, &dev->parts_idx);
+	}
+
+	if (link == NULL)
+		list_append(&part->ldev_idx, &dev->parts_idx);
+
+	part->capacity.cunit = cu_byte;
+	part->capacity.value = part->nblocks * dev->dinfo.block_size;
+	part->part_id = partid;
+
+	if (rpart != NULL)
+		*rpart = part;
+	return EOK;
+error:
+	free(part);
+	return rc;
+}
+
+
 int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
 {
-	fdisk_dev_t *dev;
+	fdisk_dev_t *dev = NULL;
+	service_id_t *psids = NULL;
+	size_t nparts, i;
+	int rc;
 
 	dev = calloc(1, sizeof(fdisk_dev_t));
@@ -256,11 +325,50 @@
 	dev->fdisk = fdisk;
 	dev->sid = sid;
-	list_initialize(&dev->parts);
+	list_initialize(&dev->parts_idx);
+	list_initialize(&dev->parts_ba);
+
+	printf("get info\n");
+	rc = vbd_disk_info(fdisk->vbd, sid, &dev->dinfo);
+	if (rc != EOK) {
+		printf("failed\n");
+		rc = EIO;
+		goto error;
+	}
+
+	printf("block size: %zu\n", dev->dinfo.block_size);
+	printf("get partitions\n");
+	rc = vbd_label_get_parts(fdisk->vbd, sid, &psids, &nparts);
+	if (rc != EOK) {
+		printf("failed\n");
+		rc = EIO;
+		goto error;
+	}
+	printf("OK\n");
+
+	printf("found %zu partitions.\n", nparts);
+	for (i = 0; i < nparts; i++) {
+		printf("add partition sid=%zu\n", psids[i]);
+		rc = fdisk_part_add(dev, psids[i], NULL);
+		if (rc != EOK) {
+			printf("failed\n");
+			goto error;
+		}
+		printf("OK\n");
+	}
+
+	free(psids);
 	*rdev = dev;
 	return EOK;
+error:
+	fdisk_dev_close(dev);
+	return rc;
 }
 
 void fdisk_dev_close(fdisk_dev_t *dev)
 {
+	if (dev == NULL)
+		return;
+
+	/* XXX Clean up partitions */
 	free(dev);
 }
@@ -351,9 +459,9 @@
 	link_t *link;
 
-	link = list_first(&dev->parts);
+	link = list_first(&dev->parts_ba);
 	if (link == NULL)
 		return NULL;
 
-	return list_get_instance(link, fdisk_part_t, ldev);
+	return list_get_instance(link, fdisk_part_t, ldev_ba);
 }
 
@@ -362,9 +470,9 @@
 	link_t *link;
 
-	link = list_next(&part->ldev, &part->dev->parts);
+	link = list_next(&part->ldev_ba, &part->dev->parts_ba);
 	if (link == NULL)
 		return NULL;
 
-	return list_get_instance(link, fdisk_part_t, ldev);
+	return list_get_instance(link, fdisk_part_t, ldev_ba);
 }
 
@@ -399,12 +507,14 @@
 	}
 
-	part->dev = dev;
-	list_append(&part->ldev, &dev->parts);
-	part->capacity = pspec->capacity;
-	part->fstype = pspec->fstype;
-	part->part_id = partid;
-
-	if (rpart != NULL)
-		*rpart = part;
+	rc = fdisk_part_add(dev, partid, rpart);
+	if (rc != EOK) {
+		/* Try rolling back */
+		(void) vbd_part_delete(dev->fdisk->vbd, partid);
+		return EIO;
+	}
+
+	(*rpart)->fstype = pspec->fstype;
+	(*rpart)->capacity = pspec->capacity;
+
 	return EOK;
 }
@@ -418,5 +528,6 @@
 		return EIO;
 
-	list_remove(&part->ldev);
+	list_remove(&part->ldev_ba);
+	list_remove(&part->ldev_idx);
 	free(part);
 	return EOK;
Index: uspace/lib/label/include/std/mbr.h
===================================================================
--- uspace/lib/label/include/std/mbr.h	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/label/include/std/mbr.h	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -38,8 +38,11 @@
 #include <stdint.h>
 
-/** Block address of Master Boot Record. */
-#define MBR_BA	0
+enum {
+	/** Block address of Master Boot Record. */
+	mbr_ba = 0,
 
-enum {
+	/** First block allowed for allocation */
+	mbr_ablock0 = 18,
+
 	/** Number of primary partition records */
 	mbr_nprimary = 4,
Index: uspace/lib/label/include/types/liblabel.h
===================================================================
--- uspace/lib/label/include/types/liblabel.h	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/label/include/types/liblabel.h	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -43,4 +43,5 @@
 
 typedef struct label label_t;
+typedef struct label_info label_info_t;
 typedef struct label_part label_part_t;
 typedef struct label_part_info label_part_info_t;
@@ -53,4 +54,5 @@
 	void (*close)(label_t *);
 	int (*destroy)(label_t *);
+	int (*get_info)(label_t *, label_info_t *);
 	label_part_t *(*part_first)(label_t *);
 	label_part_t *(*part_next)(label_part_t *);
@@ -60,12 +62,18 @@
 } label_ops_t;
 
-typedef struct {
+struct label_info {
 	/** Disk contents */
 	label_disk_cnt_t dcnt;
 	/** Label type */
 	label_type_t ltype;
-} label_info_t;
+	/** First block that can be allocated */
+	aoff64_t ablock0;
+	/** Number of blocks that can be allocated */
+	aoff64_t anblocks;
+};
 
 struct label_part_info {
+	/** Partition index */
+	int index;
 	/** Address of first block */
 	aoff64_t block0;
@@ -80,5 +88,9 @@
 	/** Link to label_t.parts */
 	link_t llabel;
+	/** Index */
+	int index;
+	/** First block */
 	aoff64_t block0;
+	/** Number of blocks */
 	aoff64_t nblocks;
 };
@@ -96,4 +108,8 @@
 	/** Partitions */
 	list_t parts; /* of label_part_t */
+	/** First block that can be allocated */
+	aoff64_t ablock0;
+	/** Number of blocks that can be allocated */
+	aoff64_t anblocks;
 };
 
Index: uspace/lib/label/src/gpt.c
===================================================================
--- uspace/lib/label/src/gpt.c	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/label/src/gpt.c	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -37,4 +37,5 @@
 #include <byteorder.h>
 #include <errno.h>
+#include <mem.h>
 #include <stdlib.h>
 
@@ -46,4 +47,5 @@
 static void gpt_close(label_t *);
 static int gpt_destroy(label_t *);
+static int gpt_get_info(label_t *, label_info_t *);
 static label_part_t *gpt_part_first(label_t *);
 static label_part_t *gpt_part_next(label_part_t *);
@@ -52,5 +54,5 @@
 static int gpt_part_destroy(label_part_t *);
 
-static int gpt_pte_to_part(label_t *, gpt_entry_t *);
+static int gpt_pte_to_part(label_t *, gpt_entry_t *, int);
 
 const uint8_t efi_signature[8] = {
@@ -64,4 +66,5 @@
 	.close = gpt_close,
 	.destroy = gpt_destroy,
+	.get_info = gpt_get_info,
 	.part_first = gpt_part_first,
 	.part_next = gpt_part_next,
@@ -83,4 +86,5 @@
 	uint64_t ba;
 	uint32_t entry;
+	uint64_t ba_min, ba_max;
 	int i;
 	int rc;
@@ -126,4 +130,6 @@
 	bcnt = (num_entries + esize - 1) / esize;
 	ba = uint64_t_le2host(gpt_hdr->entry_lba);
+	ba_min = uint64_t_le2host(gpt_hdr->first_usable_lba);
+	ba_max = uint64_t_le2host(gpt_hdr->last_usable_lba);
 
 	if (num_entries < 1) {
@@ -133,4 +139,9 @@
 
 	if (esize < sizeof(gpt_entry_t)) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	if (ba_max < ba_min) {
 		rc = EINVAL;
 		goto error;
@@ -151,5 +162,5 @@
 	for (entry = 0; entry < num_entries; entry++) {
 		eptr = (gpt_entry_t *)(etable + entry * esize);
-		rc = gpt_pte_to_part(label, eptr);
+		rc = gpt_pte_to_part(label, eptr, entry + 1);
 		if (rc != EOK)
 			goto error;
@@ -163,4 +174,6 @@
 	label->ops = &gpt_label_ops;
 	label->ltype = lt_gpt;
+	label->ablock0 = ba_min;
+	label->anblocks = ba_max - ba_min + 1;
 	*rlabel = label;
 	return EOK;
@@ -187,4 +200,14 @@
 }
 
+static int gpt_get_info(label_t *label, label_info_t *linfo)
+{
+	memset(linfo, 0, sizeof(label_info_t));
+	linfo->dcnt = dc_label;
+	linfo->ltype = lt_gpt;
+	linfo->ablock0 = label->ablock0;
+	linfo->anblocks = label->anblocks;
+	return EOK;
+}
+
 static label_part_t *gpt_part_first(label_t *label)
 {
@@ -211,4 +234,5 @@
 static void gpt_part_get_info(label_part_t *part, label_part_info_t *pinfo)
 {
+	pinfo->index = part->index;
 	pinfo->block0 = part->block0;
 	pinfo->nblocks = part->nblocks;
@@ -218,13 +242,13 @@
     label_part_t **rpart)
 {
-	return EOK;
+	return ENOTSUP;
 }
 
 static int gpt_part_destroy(label_part_t *part)
 {
-	return EOK;
-}
-
-static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte)
+	return ENOTSUP;
+}
+
+static int gpt_pte_to_part(label_t *label, gpt_entry_t *pte, int index)
 {
 	label_part_t *part;
@@ -250,4 +274,5 @@
 		return EINVAL;
 
+	part->index = index;
 	part->block0 = b0;
 	part->nblocks = b1 - b0 + 1;
Index: uspace/lib/label/src/label.c
===================================================================
--- uspace/lib/label/src/label.c	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/label/src/label.c	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -97,8 +97,5 @@
 int label_get_info(label_t *label, label_info_t *linfo)
 {
-	memset(linfo, 0, sizeof(label_info_t));
-	linfo->dcnt = dc_label;
-	linfo->ltype = label->ltype;
-	return EOK;
+	return label->ops->get_info(label, linfo);
 }
 
Index: uspace/lib/label/src/mbr.c
===================================================================
--- uspace/lib/label/src/mbr.c	(revision 3faa03dd95010d106f2bcc2ad1b10dd7ed86bcff)
+++ uspace/lib/label/src/mbr.c	(revision 1626cd4d3269f272038f96a6fa17c3536f1b084c)
@@ -37,4 +37,5 @@
 #include <byteorder.h>
 #include <errno.h>
+#include <mem.h>
 #include <stdlib.h>
 
@@ -46,4 +47,5 @@
 static void mbr_close(label_t *);
 static int mbr_destroy(label_t *);
+static int mbr_get_info(label_t *, label_info_t *);
 static label_part_t *mbr_part_first(label_t *);
 static label_part_t *mbr_part_next(label_part_t *);
@@ -52,5 +54,5 @@
 static int mbr_part_destroy(label_part_t *);
 
-static int mbr_pte_to_part(label_t *, mbr_pte_t *);
+static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
 
 label_ops_t mbr_label_ops = {
@@ -59,4 +61,5 @@
 	.close = mbr_close,
 	.destroy = mbr_destroy,
+	.get_info = mbr_get_info,
 	.part_first = mbr_part_first,
 	.part_next = mbr_part_next,
@@ -73,4 +76,5 @@
 	uint16_t sgn;
 	size_t bsize;
+	aoff64_t nblocks;
 	uint32_t entry;
 	int rc;
@@ -82,5 +86,16 @@
 	}
 
+	rc = block_get_nblocks(sid, &nblocks);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
 	if (bsize < 512 || (bsize % 512) != 0) {
+		rc = EINVAL;
+		goto error;
+	}
+
+	if (nblocks < mbr_ablock0) {
 		rc = EINVAL;
 		goto error;
@@ -93,5 +108,5 @@
 	}
 
-	rc = block_read_direct(sid, MBR_BA, 1, mbr);
+	rc = block_read_direct(sid, mbr_ba, 1, mbr);
 	if (rc != EOK) {
 		rc = EIO;
@@ -114,5 +129,5 @@
 	for (entry = 0; entry < mbr_nprimary; entry++) {
 		eptr = &mbr->pte[entry];
-		rc = mbr_pte_to_part(label, eptr);
+		rc = mbr_pte_to_part(label, eptr, entry + 1);
 		if (rc != EOK)
 			goto error;
@@ -124,4 +139,6 @@
 	label->ops = &mbr_label_ops;
 	label->ltype = lt_mbr;
+	label->ablock0 = mbr_ablock0;
+	label->anblocks = nblocks - mbr_ablock0;
 	*rlabel = label;
 	return EOK;
@@ -147,4 +164,14 @@
 }
 
+static int mbr_get_info(label_t *label, label_info_t *linfo)
+{
+	memset(linfo, 0, sizeof(label_info_t));
+	linfo->dcnt = dc_label;
+	linfo->ltype = lt_mbr;
+	linfo->ablock0 = label->ablock0;
+	linfo->anblocks = label->anblocks;
+	return EOK;
+}
+
 static label_part_t *mbr_part_first(label_t *label)
 {
@@ -171,4 +198,5 @@
 static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
 {
+	pinfo->index = part->index;
 	pinfo->block0 = part->block0;
 	pinfo->nblocks = part->nblocks;
@@ -178,13 +206,13 @@
     label_part_t **rpart)
 {
-	return EOK;
+	return ENOTSUP;
 }
 
 static int mbr_part_destroy(label_part_t *part)
 {
-	return EOK;
-}
-
-static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte)
+	return ENOTSUP;
+}
+
+static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
 {
 	label_part_t *part;
@@ -204,4 +232,5 @@
 		return ENOMEM;
 
+	part->index = index;
 	part->block0 = block0;
 	part->nblocks = nblocks;
