Index: uspace/lib/c/include/vbd.h
===================================================================
--- uspace/lib/c/include/vbd.h	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/c/include/vbd.h	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -69,4 +69,6 @@
 	/** Number of blocks */
 	aoff64_t nblocks;
+	/** Number of header blocks (EBR for logical partitions) */
+	aoff64_t hdr_blocks;
 	/** Partition kind */
 	label_pkind_t pkind;
Index: uspace/lib/fdisk/include/types/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/types/fdisk.h	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/fdisk/include/types/fdisk.h	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -106,10 +106,18 @@
 	/** Service ID */
 	service_id_t sid;
-	/** Partitions sorted by index */
-	list_t parts_idx; /* of fdisk_part_t */
-	/** Partitions sorted by block address */
-	list_t parts_ba;
+	/** All partitions */
+	list_t parts;
+	/** Primary partitions sorted by index */
+	list_t pri_idx; /* of fdisk_part_t */
+	/** Primary partitions sorted by block address */
+	list_t pri_ba;
+	/** Logical partitions sorted by block address */
+	list_t log_ba;
+	/** Extended partition or NULL */
+	struct fdisk_part *ext_part;
 	/** Disk info */
 	vbd_disk_info_t dinfo;
+	/** Alignment in blocks */
+	uint64_t align;
 } fdisk_dev_t;
 
@@ -124,11 +132,15 @@
 
 /** Partition */
-typedef struct {
+typedef struct fdisk_part {
 	/** Containing device */
 	fdisk_dev_t *dev;
-	/** Link to fdisk_dev_t.parts_idx */
-	link_t ldev_idx;
-	/** Link to fdisk_dev_t.parts_ba */
-	link_t ldev_ba;
+	/** Link to fdisk_dev_t.parts */
+	link_t lparts;
+	/** Link to fdisk_dev_t.pri_idx */
+	link_t lpri_idx;
+	/** Link to fdisk_dev_t.pri_ba */
+	link_t lpri_ba;
+	/** Link to fdisk_dev_t.log_ba */
+	link_t llog_ba;
 	/** Capacity */
 	fdisk_cap_t capacity;
Index: uspace/lib/fdisk/src/fdisk.c
===================================================================
--- uspace/lib/fdisk/src/fdisk.c	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/fdisk/src/fdisk.c	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -60,4 +60,7 @@
 static int fdisk_part_spec_prepare(fdisk_dev_t *, fdisk_part_spec_t *,
     vbd_part_spec_t *);
+static void fdisk_pri_part_insert_lists(fdisk_dev_t *, fdisk_part_t *);
+static void fdisk_log_part_insert_lists(fdisk_dev_t *, fdisk_part_t *);
+static int fdisk_update_dev_info(fdisk_dev_t *);
 
 static void fdisk_dev_info_delete(fdisk_dev_info_t *info)
@@ -252,7 +255,6 @@
     fdisk_part_t **rpart)
 {
-	fdisk_part_t *part, *p;
+	fdisk_part_t *part;
 	vbd_part_info_t pinfo;
-	link_t *link;
 	int rc;
 
@@ -273,33 +275,18 @@
 	part->pkind = pinfo.pkind;
 
-	/* 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);
+	switch (part->pkind) {
+	case lpk_primary:
+	case lpk_extended:
+		fdisk_pri_part_insert_lists(dev, part);
+		break;
+	case lpk_logical:
+		fdisk_log_part_insert_lists(dev, part);
+		break;
+	}
+
+	list_append(&part->lparts, &dev->parts);
+
+	if (part->pkind == lpk_extended)
+		dev->ext_part = part;
 
 	part->capacity.cunit = cu_byte;
@@ -315,4 +302,60 @@
 }
 
+static void fdisk_pri_part_insert_lists(fdisk_dev_t *dev, fdisk_part_t *part)
+{
+	link_t *link;
+	fdisk_part_t *p;
+
+	/* Insert to list by block address */
+	link = list_first(&dev->pri_ba);
+	while (link != NULL) {
+		p = list_get_instance(link, fdisk_part_t, lpri_ba);
+		if (p->block0 > part->block0) {
+			list_insert_before(&part->lpri_ba, &p->lpri_ba);
+			break;
+		}
+
+		link = list_next(link, &dev->pri_ba);
+	}
+
+	if (link == NULL)
+		list_append(&part->lpri_ba, &dev->pri_ba);
+
+	/* Insert to list by index */
+	link = list_first(&dev->pri_idx);
+	while (link != NULL) {
+		p = list_get_instance(link, fdisk_part_t, lpri_idx);
+		if (p->index > part->index) {
+			list_insert_before(&part->lpri_idx, &p->lpri_idx);
+			break;
+		}
+
+		link = list_next(link, &dev->pri_idx);
+	}
+
+	if (link == NULL)
+		list_append(&part->lpri_idx, &dev->pri_idx);
+}
+
+static void fdisk_log_part_insert_lists(fdisk_dev_t *dev, fdisk_part_t *part)
+{
+	link_t *link;
+	fdisk_part_t *p;
+
+	/* Insert to list by block address */
+	link = list_first(&dev->log_ba);
+	while (link != NULL) {
+		p = list_get_instance(link, fdisk_part_t, llog_ba);
+		if (p->block0 > part->block0) {
+			list_insert_before(&part->llog_ba, &p->llog_ba);
+			break;
+		}
+
+		link = list_next(link, &dev->log_ba);
+	}
+
+	if (link == NULL)
+		list_append(&part->llog_ba, &dev->log_ba);
+}
 
 int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
@@ -330,6 +373,8 @@
 	dev->fdisk = fdisk;
 	dev->sid = sid;
-	list_initialize(&dev->parts_idx);
-	list_initialize(&dev->parts_ba);
+	list_initialize(&dev->parts);
+	list_initialize(&dev->pri_idx);
+	list_initialize(&dev->pri_ba);
+	list_initialize(&dev->log_ba);
 
 	rc = vol_disk_info(fdisk->vol, sid, &vinfo);
@@ -345,5 +390,5 @@
 
 	printf("get label info\n");
-	rc = vbd_disk_info(fdisk->vbd, sid, &dev->dinfo);
+	rc = fdisk_update_dev_info(dev);
 	if (rc != EOK) {
 		printf("failed\n");
@@ -451,5 +496,15 @@
 int fdisk_label_create(fdisk_dev_t *dev, label_type_t ltype)
 {
-	return vol_label_create(dev->fdisk->vol, dev->sid, ltype);
+	int rc;
+
+	rc = vol_label_create(dev->fdisk->vol, dev->sid, ltype);
+	if (rc != EOK)
+		return rc;
+
+	rc = fdisk_update_dev_info(dev);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
 }
 
@@ -477,9 +532,9 @@
 	link_t *link;
 
-	link = list_first(&dev->parts_ba);
+	link = list_first(&dev->parts);
 	if (link == NULL)
 		return NULL;
 
-	return list_get_instance(link, fdisk_part_t, ldev_ba);
+	return list_get_instance(link, fdisk_part_t, lparts);
 }
 
@@ -488,9 +543,9 @@
 	link_t *link;
 
-	link = list_next(&part->ldev_ba, &part->dev->parts_ba);
+	link = list_next(&part->lparts, &part->dev->parts);
 	if (link == NULL)
 		return NULL;
 
-	return list_get_instance(link, fdisk_part_t, ldev_ba);
+	return list_get_instance(link, fdisk_part_t, lparts);
 }
 
@@ -552,6 +607,11 @@
 		return EIO;
 
-	list_remove(&part->ldev_ba);
-	list_remove(&part->ldev_idx);
+	list_remove(&part->lparts);
+	if (link_used(&part->lpri_ba))
+		list_remove(&part->lpri_ba);
+	if (link_used(&part->lpri_idx))
+		list_remove(&part->lpri_idx);
+	if (link_used(&part->llog_ba))
+		list_remove(&part->llog_ba);
 	free(part);
 	return EOK;
@@ -707,12 +767,12 @@
 	int nidx;
 
-	link = list_first(&dev->parts_idx);
+	link = list_first(&dev->pri_idx);
 	nidx = 1;
 	while (link != NULL) {
-		part = list_get_instance(link, fdisk_part_t, ldev_idx);
+		part = list_get_instance(link, fdisk_part_t, lpri_idx);
 		if (part->index > nidx)
 			break;
 		nidx = part->index + 1;
-		link = list_next(link, &dev->parts_idx);
+		link = list_next(link, &dev->pri_idx);
 	}
 
@@ -737,12 +797,12 @@
 	int nba;
 
-	link = list_first(&dev->parts_ba);
+	link = list_first(&dev->pri_ba);
 	nba = dev->dinfo.ablock0;
 	while (link != NULL) {
-		part = list_get_instance(link, fdisk_part_t, ldev_ba);
+		part = list_get_instance(link, fdisk_part_t, lpri_ba);
 		if (part->block0 - nba >= nblocks)
 			break;
 		nba = part->block0 + part->nblocks;
-		link = list_next(link, &dev->parts_ba);
+		link = list_next(link, &dev->pri_ba);
 	}
 
@@ -764,4 +824,50 @@
 }
 
+/** Get free range of blocks in extended partition.
+ *
+ * Get free range of blocks in extended partition that can accomodate
+ * a partition of at least the specified size plus the header (EBR + padding).
+ * Returns the header size in blocks, the start and length of the partition.
+ */
+static int fdisk_part_get_log_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
+    aoff64_t *rhdrb, aoff64_t *rblock0, aoff64_t *rnblocks)
+{
+	link_t *link;
+	fdisk_part_t *part;
+	uint64_t avail;
+	uint64_t hdrb;
+	int nba;
+
+	/* Number of header blocks */
+	hdrb = max(1, dev->align);
+
+	link = list_first(&dev->log_ba);
+	nba = dev->ext_part->block0;
+	while (link != NULL) {
+		part = list_get_instance(link, fdisk_part_t, llog_ba);
+		if (part->block0 - nba >= nblocks)
+			break;
+		nba = part->block0 + part->nblocks;
+		link = list_next(link, &dev->log_ba);
+	}
+
+	if (link != NULL) {
+		/* Free range before a partition */
+		avail = part->block0 - nba;
+	} else {
+		/* Free range at the end */
+		avail = dev->ext_part->block0 + dev->ext_part->nblocks - nba;
+
+		/* Verify that the range is large enough */
+		if (avail < hdrb + nblocks)
+			return ELIMIT;
+	}
+
+	*rhdrb = hdrb;
+	*rblock0 = nba + hdrb;
+	*rnblocks = avail;
+	return EOK;
+}
+
 /** Prepare new partition specification for VBD. */
 static int fdisk_part_spec_prepare(fdisk_dev_t *dev, fdisk_part_spec_t *pspec,
@@ -770,4 +876,5 @@
 	uint64_t cbytes;
 	aoff64_t req_blocks;
+	aoff64_t fhdr;
 	aoff64_t fblock0;
 	aoff64_t fnblocks;
@@ -778,28 +885,73 @@
 
 //	pspec->fstype
-	printf("fdisk_part_spec_prepare()\n");
+	printf("fdisk_part_spec_prepare() - dev=%p pspec=%p vpspec=%p\n", dev, pspec,
+	    vpspec);
+	printf("fdisk_part_spec_prepare() - block size\n");
 	block_size = dev->dinfo.block_size;
+	printf("fdisk_part_spec_prepare() - cbytes\n");
 	cbytes = pspec->capacity.value;
+	printf("fdisk_part_spec_prepare() - cunit\n");
 	for (i = 0; i < pspec->capacity.cunit; i++)
 		cbytes = cbytes * 1000;
 
+	printf("fdisk_part_spec_prepare() - req_blocks block_size=%zu\n",
+	    block_size);
 	req_blocks = (cbytes + block_size - 1) / block_size;
 
-	rc = fdisk_part_get_free_idx(dev, &index);
+	printf("fdisk_part_spec_prepare() - switch\n");
+	switch (pspec->pkind) {
+	case lpk_primary:
+	case lpk_extended:
+		printf("fdisk_part_spec_prepare() - pri/ext\n");
+		rc = fdisk_part_get_free_idx(dev, &index);
+		if (rc != EOK)
+			return EIO;
+
+		printf("fdisk_part_spec_prepare() - get free range\n");
+		rc = fdisk_part_get_free_range(dev, req_blocks, &fblock0, &fnblocks);
+		if (rc != EOK)
+			return EIO;
+
+		printf("fdisk_part_spec_prepare() - memset\n");
+		memset(vpspec, 0, sizeof(vbd_part_spec_t));
+		vpspec->index = index;
+		vpspec->block0 = fblock0;
+		vpspec->nblocks = req_blocks;
+		vpspec->pkind = pspec->pkind;
+		if (pspec->pkind != lpk_extended)
+			vpspec->ptype = 42;
+		break;
+	case lpk_logical:
+		printf("fdisk_part_spec_prepare() - log\n");
+		rc = fdisk_part_get_log_free_range(dev, req_blocks, &fhdr,
+		    &fblock0, &fnblocks);
+		if (rc != EOK)
+			return EIO;
+
+		memset(vpspec, 0, sizeof(vbd_part_spec_t));
+		vpspec->hdr_blocks = fhdr;
+		vpspec->block0 = fblock0;
+		vpspec->nblocks = req_blocks;
+		vpspec->pkind = lpk_logical;
+		vpspec->ptype = 42;
+		break;
+	}
+
+	return EOK;
+}
+
+static int fdisk_update_dev_info(fdisk_dev_t *dev)
+{
+	int rc;
+	size_t align_bytes;
+
+	rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &dev->dinfo);
 	if (rc != EOK)
 		return EIO;
 
-	rc = fdisk_part_get_free_range(dev, req_blocks, &fblock0, &fnblocks);
-	if (rc != EOK)
-		return EIO;
-
-	memset(vpspec, 0, sizeof(vbd_part_spec_t));
-	vpspec->index = index;
-	vpspec->block0 = fblock0;
-	vpspec->nblocks = req_blocks;
-	vpspec->pkind = pspec->pkind;
-	if (pspec->pkind != lpk_extended)
-		vpspec->ptype = 42;
-
+	align_bytes = 512; //1024 * 1024; /* 1 MiB */ /* XXX */
+	dev->align = align_bytes / dev->dinfo.block_size;
+	if (dev->align < 1)
+		dev->align = 1;
 	return EOK;
 }
Index: uspace/lib/label/include/std/mbr.h
===================================================================
--- uspace/lib/label/include/std/mbr.h	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/label/include/std/mbr.h	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -49,5 +49,10 @@
 
 	/** Boot record signature */
-	mbr_br_signature = 0xAA55
+	mbr_br_signature = 0xAA55,
+
+	/** EBR PTE slot describing partition corresponding to this EBR */
+	mbr_ebr_pte_this = 0,
+	/** EBR PTE slot describing the next EBR */
+	mbr_ebr_pte_next = 1
 };
 
Index: uspace/lib/label/include/types/liblabel.h
===================================================================
--- uspace/lib/label/include/types/liblabel.h	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/label/include/types/liblabel.h	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -99,4 +99,6 @@
 	/** Index */
 	int index;
+	/** Number of EBR blocks preceding a logical partition */
+	aoff64_t hdr_blocks;
 	/** First block */
 	aoff64_t block0;
@@ -117,4 +119,6 @@
 	/** Number of blocks */
 	aoff64_t nblocks;
+	/** Number of header blocks (EBR for logical partitions) */
+	aoff64_t hdr_blocks;
 	/** Partition kind */
 	label_pkind_t pkind;
@@ -155,6 +159,6 @@
 	/** Number of primary partition entries */
 	int pri_entries;
-	/** Index of extended partition or -1 if there is none */
-	int ext_part_idx;
+	/** Extended partition or NULL if there is none */
+	label_part_t *ext_part;
 	/** Block size */
 	size_t block_size;
Index: uspace/lib/label/src/gpt.c
===================================================================
--- uspace/lib/label/src/gpt.c	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/label/src/gpt.c	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -302,5 +302,4 @@
 	label->pri_entries = num_entries;
 	label->block_size = bsize;
-	label->ext_part_idx = -1;
 
 	label->lt.gpt.hdr_ba[0] = gpt_hdr_ba;
@@ -449,5 +448,4 @@
 	label->pri_entries = num_entries;
 	label->block_size = bsize;
-	label->ext_part_idx = -1;
 
 	label->lt.gpt.hdr_ba[0] = hdr_ba[0];
Index: uspace/lib/label/src/mbr.c
===================================================================
--- uspace/lib/label/src/mbr.c	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/lib/label/src/mbr.c	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -44,4 +44,5 @@
 
 static int mbr_open(service_id_t, label_t **);
+static int mbr_open_ext(label_t *);
 static int mbr_create(service_id_t, label_t **);
 static void mbr_close(label_t *);
@@ -57,5 +58,12 @@
 static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
 static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
+static int mbr_pte_to_log_part(label_t *, uint64_t, mbr_pte_t *);
+static void mbr_log_part_to_ptes(label_part_t *, mbr_pte_t *, mbr_pte_t *);
 static int mbr_pte_update(label_t *, mbr_pte_t *, int);
+static int mbr_log_part_insert(label_t *, label_part_t *);
+static int mbr_ebr_create(label_t *, label_part_t *);
+static int mbr_ebr_delete(label_t *, label_part_t *);
+static int mbr_ebr_update_next(label_t *, label_part_t *);
+static void mbr_update_log_indices(label_t *);
 
 label_ops_t mbr_label_ops = {
@@ -132,5 +140,6 @@
 	}
 
-	label->ext_part_idx = -1;
+
+	label->ext_part = NULL;
 	for (entry = 0; entry < mbr_nprimary; entry++) {
 		eptr = &mbr->pte[entry];
@@ -150,9 +159,116 @@
 	label->anblocks = nblocks - mbr_ablock0;
 	label->pri_entries = mbr_nprimary;
+
+	if (label->ext_part != NULL) {
+		/* Open extended partition */
+		rc = mbr_open_ext(label);
+		if (rc != EOK)
+			goto error;
+	}
+
 	*rlabel = label;
 	return EOK;
 error:
 	free(mbr);
-	free(label);
+	mbr_close(label);
+	return rc;
+}
+
+/** Open extended partition */
+static int mbr_open_ext(label_t *label)
+{
+	mbr_br_block_t *ebr = NULL;
+	mbr_pte_t *ethis;
+	mbr_pte_t *enext;
+	uint64_t ebr_b0;
+	uint64_t ebr_nblocks_min;
+	uint64_t ebr_nblocks_max;
+	uint64_t pebr_b0;
+	uint64_t pebr_nblocks;
+	uint64_t pb0;
+	uint64_t pnblocks;
+	uint64_t ep_b0;
+	int rc;
+
+	ebr = calloc(1, label->block_size);
+	if (ebr == NULL) {
+		rc = ENOMEM;
+		goto error;
+	}
+
+	/* First block of extended partition */
+	ep_b0 = label->ext_part->block0;
+
+	/* First block of current EBR */
+	ebr_b0 = label->ext_part->block0;
+
+	/*
+	 * We don't have bounds for the first EBR, so for purpose of
+	 * verification let's say it contains at least one block and
+	 * at most all blocks from the extended partition.
+	 */
+	ebr_nblocks_min = 1;
+	ebr_nblocks_max = label->ext_part->nblocks;
+
+	while (true) {
+		/* Read EBR */
+		rc = block_read_direct(label->svc_id, ebr_b0, 1, ebr);
+		if (rc != EOK) {
+			rc = EIO;
+			goto error;
+		}
+
+		ethis = &ebr->pte[mbr_ebr_pte_this];
+		enext = &ebr->pte[mbr_ebr_pte_next];
+
+		pb0 = ebr_b0 + uint32_t_le2host(ethis->first_lba);
+		pnblocks = uint32_t_le2host(ethis->length);
+
+		if (ethis->ptype == mbr_pt_unused || pnblocks == 0)
+			break;
+
+		/* Verify partition lies within the range of EBR */
+		if (pb0 + pnblocks > ebr_b0 + ebr_nblocks_max) {
+			rc = EIO;
+			goto error;
+		}
+
+		/* Create partition structure */
+		rc = mbr_pte_to_log_part(label, ebr_b0, ethis);
+		if (rc != EOK) {
+			rc= EIO;
+			goto error;
+		}
+
+		/* Save previous EBR range */
+		pebr_b0 = ebr_b0;
+		pebr_nblocks = ebr_nblocks_min;
+
+		/* Proceed to next EBR */
+		ebr_b0 = ep_b0 + uint32_t_le2host(enext->first_lba);
+		ebr_nblocks_min = uint32_t_le2host(enext->length);
+		ebr_nblocks_max = ebr_nblocks_min;
+
+		if (enext->ptype == mbr_pt_unused || ebr_nblocks_min == 0)
+			break;
+
+		/* Verify next EBR does not overlap this EBR */
+		if (ebr_b0 < pebr_b0 + pebr_nblocks) {
+			rc = EIO;
+			goto error;
+		}
+
+		/* Verify next EBR does not extend beyond end of label */
+		if (ebr_b0 + ebr_nblocks_max > label->ablock0 + label->anblocks) {
+			rc = EIO;
+			goto error;
+		}
+	}
+
+	free(ebr);
+	return EOK;
+error:
+	/* Note that logical partitions need to be deleted by caller */
+	free(ebr);
 	return rc;
 }
@@ -215,5 +331,5 @@
 	label->anblocks = nblocks - mbr_ablock0;
 	label->pri_entries = mbr_nprimary;
-	label->ext_part_idx = -1;
+	label->ext_part = NULL;
 
 	*rlabel = label;
@@ -228,4 +344,7 @@
 {
 	label_part_t *part;
+
+	if (label == NULL)
+		return;
 
 	part = mbr_part_first(label);
@@ -291,8 +410,8 @@
 		linfo->flags |= lf_can_create_pri;
 	/* Can create extended if there is a free slot and no extended */
-	if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part_idx < 0)
+	if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part == NULL)
 		linfo->flags |= lf_can_create_ext;
 	/* Can create logical if there is an extended partition */
-	if (label->ext_part_idx >= 0)
+	if (label->ext_part != NULL)
 		linfo->flags |= lf_can_create_log;
 
@@ -323,4 +442,37 @@
 
 	return list_get_instance(link, label_part_t, lparts);
+}
+
+static label_part_t *mbr_log_part_first(label_t *label)
+{
+	link_t *link;
+
+	link = list_first(&label->log_parts);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, label_part_t, llog);
+}
+
+static label_part_t *mbr_log_part_next(label_part_t *part)
+{
+	link_t *link;
+
+	link = list_next(&part->llog, &part->label->log_parts);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, label_part_t, llog);
+}
+
+static label_part_t *mbr_log_part_prev(label_part_t *part)
+{
+	link_t *link;
+
+	link = list_prev(&part->llog, &part->label->log_parts);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, label_part_t, llog);
 }
 
@@ -346,4 +498,6 @@
 {
 	label_part_t *part;
+	label_part_t *prev;
+	label_part_t *next;
 	mbr_pte_t pte;
 	int rc;
@@ -360,4 +514,5 @@
 	part->block0 = pspec->block0;
 	part->nblocks = pspec->nblocks;
+	part->hdr_blocks = pspec->hdr_blocks;
 
 	switch (pspec->pkind) {
@@ -371,5 +526,5 @@
 			goto error;
 		}
-		if (label->ext_part_idx >= 0) {
+		if (label->ext_part != NULL) {
 			rc = EEXISTS;
 			goto error;
@@ -377,4 +532,5 @@
 		break;
 	case lpk_logical:
+		log_msg(LOG_DEFAULT, LVL_NOTE, "check index");
 		part->ptype = pspec->ptype;
 		if (pspec->index != 0) {
@@ -394,4 +550,9 @@
 		}
 
+		if (pspec->hdr_blocks != 0) {
+			rc = EINVAL;
+			goto error;
+		}
+
 		rc = mbr_part_to_pte(part, &pte);
 		if (rc != EOK) {
@@ -410,11 +571,49 @@
 
 		if (pspec->pkind == lpk_extended)
-			label->ext_part_idx = pspec->index - 1;
+			label->ext_part = part;
 	} else {
 		/* Logical partition */
-		rc = ENOTSUP;
-		goto error;
-	}
-
+
+		log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_log_part_insert");
+		rc = mbr_log_part_insert(label, part);
+		if (rc != EOK)
+			goto error;
+
+		log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_ebr_create");
+		/* Create EBR for new partition */
+		rc = mbr_ebr_create(label, part);
+		if (rc != EOK)
+			goto error;
+
+		prev = mbr_log_part_prev(part);
+		if (prev != NULL) {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "update next");
+			/* Update 'next' PTE in EBR of previous partition */
+			rc = mbr_ebr_update_next(label, prev);
+			if (rc != EOK) {
+				log_msg(LOG_DEFAULT, LVL_NOTE, "failed to update next");
+				goto error;
+			}
+		} else {
+			log_msg(LOG_DEFAULT, LVL_NOTE, "relocate first EBR");
+			/* New partition is now the first one */
+			next = mbr_log_part_next(part);
+			if (next != NULL) {
+				/*
+				 * Create new, relocated EBR for the former
+				 * first partition
+				 */
+				next->hdr_blocks = pspec->hdr_blocks;
+				rc = mbr_ebr_create(label, next);
+				if (rc != EOK)
+					goto error;
+			}
+		}
+
+		/* This also sets index for the new partition. */
+		mbr_update_log_indices(label);
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create success");
 	*rpart = part;
 	return EOK;
@@ -427,23 +626,46 @@
 {
 	mbr_pte_t pte;
+	label_part_t *prev;
 	int rc;
 
-	/* Prepare unused partition table entry */
-	mbr_unused_pte(&pte);
-
-	/* Modify partition table */
-	rc = mbr_pte_update(part->label, &pte, part->index - 1);
-	if (rc != EOK)
-		return EIO;
-
-	/* If it was the extended partition, clear ext. part. index */
-	if (part->index - 1 == part->label->ext_part_idx)
-		part->label->ext_part_idx = -1;
+	if (link_used(&part->lpri)) {
+		/* Primary/extended partition */
+
+		/* Prepare unused partition table entry */
+		mbr_unused_pte(&pte);
+
+		/* Modify partition table */
+		rc = mbr_pte_update(part->label, &pte, part->index - 1);
+		if (rc != EOK)
+			return EIO;
+
+		/* If it was the extended partition, clear ext. part. pointer */
+		if (part == part->label->ext_part)
+			part->label->ext_part = NULL;
+
+		list_remove(&part->lpri);
+	} else {
+		/* Logical partition */
+
+		prev = mbr_log_part_prev(part);
+		if (prev != NULL) {
+			/* Update next link in previous EBR */
+			list_remove(&part->llog);
+
+			rc = mbr_ebr_update_next(part->label, prev);
+			if (rc != EOK) {
+				/* Roll back */
+				list_insert_after(&part->llog, &prev->llog);
+				return EIO;
+			}
+		} else {
+			list_remove(&part->llog);
+		}
+
+		/* Delete EBR */
+		mbr_ebr_delete(part->label, part);
+	}
 
 	list_remove(&part->lparts);
-	if (link_used(&part->lpri))
-		list_remove(&part->lpri);
-	if (link_used(&part->llog))
-		list_remove(&part->llog);
 	free(part);
 	return EOK;
@@ -507,6 +729,80 @@
 
 	if (pte->ptype == mbr_pt_extended)
-		label->ext_part_idx = index - 1;
-	return EOK;
+		label->ext_part = part;
+	return EOK;
+}
+
+static int mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
+    mbr_pte_t *pte)
+{
+	label_part_t *part;
+	uint32_t block0;
+	uint32_t nblocks;
+	size_t nlparts;
+
+	block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
+	nblocks = uint32_t_le2host(pte->length);
+
+	if (pte->ptype == mbr_pt_unused || nblocks == 0)
+		return EOK;
+
+	part = calloc(1, sizeof(label_part_t));
+	if (part == NULL)
+		return ENOMEM;
+
+	nlparts = list_count(&label->log_parts);
+
+	part->ptype = pte->ptype;
+	part->index = mbr_nprimary + 1 + nlparts;
+	part->block0 = block0;
+	part->nblocks = nblocks;
+
+	part->label = label;
+	list_append(&part->lparts, &label->parts);
+	list_append(&part->llog, &label->log_parts);
+
+	return EOK;
+}
+#include <stdio.h>
+static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
+    mbr_pte_t *pnext)
+{
+	label_part_t *next;
+	uint64_t ep_b0;
+	uint64_t totsize;
+
+	/* First block of extended partition */
+	ep_b0 = part->label->ext_part->block0;
+
+	assert(link_used(&part->llog));
+	assert(part->block0 >= ep_b0);
+	printf("part->hdr_blocks = %" PRIu64 "\n", part->hdr_blocks);
+	printf("part->block0 = %" PRIu64 "\n", part->block0);
+	printf("ep_b0 = %" PRIu64 "\n", ep_b0);
+	assert(part->hdr_blocks <= part->block0 - ep_b0);
+
+	/* 'This' EBR entry */
+	if (pthis != NULL) {
+		memset(pthis, 0, sizeof(mbr_pte_t));
+		pthis->ptype = part->ptype;
+		pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
+		pthis->length = host2uint32_t_le(part->nblocks);
+	}
+
+	/* 'Next' EBR entry */
+	if (pnext != NULL) {
+		next = mbr_part_next(part);
+
+		memset(pnext, 0, sizeof(mbr_pte_t));
+		if (next != NULL) {
+			/* Total size of EBR + partition */
+			totsize = next->hdr_blocks + next->nblocks;
+
+			pnext->ptype = mbr_pt_extended;
+			pnext->first_lba = host2uint32_t_le(next->block0 -
+			    next->hdr_blocks - ep_b0);
+			pnext->length = host2uint32_t_le(totsize);
+		}
+	}
 }
 
@@ -546,4 +842,156 @@
 }
 
+/** Insert logical partition into logical partition list. */
+static int mbr_log_part_insert(label_t *label, label_part_t *part)
+{
+	label_part_t *cur;
+
+	cur = mbr_log_part_first(label);
+	while (cur != NULL) {
+		if (cur->block0 + cur->nblocks > part->block0)
+			break;
+		cur = mbr_log_part_next(part);
+	}
+
+	if (cur != NULL)
+		list_insert_before(&part->llog, &cur->llog);
+	else
+		list_append(&part->llog, &label->log_parts);
+
+	return EOK;
+}
+
+/** Create EBR for partition. */
+static int mbr_ebr_create(label_t *label, label_part_t *part)
+{
+	mbr_br_block_t *br;
+	uint64_t ba;
+	int rc;
+
+	br = calloc(1, label->block_size);
+	if (br == NULL)
+		return ENOMEM;
+
+	mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
+	    &br->pte[mbr_ebr_pte_next]);
+	br->signature = host2uint16_t_le(mbr_br_signature);
+
+	ba = part->block0 - part->hdr_blocks;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "Write EBR to ba=%" PRIu64, ba);
+	rc = block_write_direct(label->svc_id, ba, 1, br);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	free(br);
+	return EOK;
+error:
+	free(br);
+	return rc;
+}
+
+static int mbr_ebr_delete(label_t *label, label_part_t *part)
+{
+	mbr_br_block_t *br;
+	uint64_t ba;
+	int rc;
+
+	br = calloc(1, label->block_size);
+	if (br == NULL)
+		return ENOMEM;
+
+	ba = part->block0 - part->hdr_blocks;
+
+	rc = block_write_direct(label->svc_id, ba, 1, br);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	free(br);
+	return EOK;
+error:
+	free(br);
+	return rc;
+}
+
+/** Update 'next' PTE in EBR of partition. */
+static int mbr_ebr_update_next(label_t *label, label_part_t *part)
+{
+	mbr_br_block_t *br;
+	uint64_t ba;
+	uint16_t sgn;
+	int rc;
+
+	ba = part->block0 - part->hdr_blocks;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next ba=%" PRIu64,
+	    ba);
+
+	br = calloc(1, label->block_size);
+	if (br == NULL)
+		return ENOMEM;
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next read ba=%" PRIu64,
+	    ba);
+
+	rc = block_read_direct(label->svc_id, ba, 1, br);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	/* Verify boot record signature */
+	sgn = uint16_t_le2host(br->signature);
+	if (sgn != mbr_br_signature) {
+		log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next signature error");
+		rc = EIO;
+		goto error;
+	}
+
+	mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next write ba=%" PRIu64,
+	    ba);
+
+	rc = block_write_direct(label->svc_id, ba, 1, br);
+	if (rc != EOK) {
+		rc = EIO;
+		goto error;
+	}
+
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next success");
+
+	free(br);
+	return EOK;
+error:
+	free(br);
+	return rc;
+}
+
+/** Update indices of logical partitions.
+ *
+ * Logical partition indices are unstable, i.e. they can change during
+ * the lifetime of a logical partition. Since the index corresponds to the
+ * position of the partition in order of block address, anytime a partition
+ * is created or deleted, indices of all partitions at higher addresses
+ * change.
+ */
+static void mbr_update_log_indices(label_t *label)
+{
+	label_part_t *part;
+	int idx;
+
+	idx = mbr_nprimary + 1;
+
+	part = mbr_log_part_first(label);
+	while (part != NULL) {
+		part->index = idx++;
+		part = mbr_log_part_next(part);
+	}
+}
+
 /** @}
  */
Index: uspace/srv/bd/vbd/disk.c
===================================================================
--- uspace/srv/bd/vbd/disk.c	(revision c43db5f9ec884dbf2d9a67843b408f94641c79eb)
+++ uspace/srv/bd/vbd/disk.c	(revision c02d098887d0049fec4eb72260cc0efa28e1a0d4)
@@ -346,4 +346,6 @@
 	info->anblocks = linfo.anblocks;
 	info->block_size = disk->block_size;
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_disk_info - block_size=%zu",
+	    info->block_size);
 	return EOK;
 }
@@ -438,4 +440,6 @@
 	disk->label = label;
 	disk->block_size = block_size;
+	log_msg(LOG_DEFAULT, LVL_NOTE, "vbds_label_create: block_size=%zu",
+	    block_size);
 	list_initialize(&disk->parts);
 
@@ -519,4 +523,5 @@
 	lpspec.block0 = pspec->block0;
 	lpspec.nblocks = pspec->nblocks;
+	lpspec.hdr_blocks = pspec->hdr_blocks;
 	lpspec.pkind = pspec->pkind;
 	lpspec.ptype = pspec->ptype;
