Index: uspace/lib/fdisk/include/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/fdisk.h	(revision 44fe800cf1bcb06ed02fb05841aef4d399d77de4)
+++ uspace/lib/fdisk/include/fdisk.h	(revision b598460af2662df4c20ccda2b3de00d8057bcacd)
@@ -64,5 +64,5 @@
 extern fdisk_part_t *fdisk_part_next(fdisk_part_t *);
 extern int fdisk_part_get_info(fdisk_part_t *, fdisk_part_info_t *);
-extern int fdisk_part_get_max_avail(fdisk_dev_t *, fdisk_cap_t *);
+extern int fdisk_part_get_max_avail(fdisk_dev_t *, fdisk_spc_t, fdisk_cap_t *);
 extern int fdisk_part_create(fdisk_dev_t *, fdisk_part_spec_t *,
     fdisk_part_t **);
Index: uspace/lib/fdisk/include/types/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/types/fdisk.h	(revision 44fe800cf1bcb06ed02fb05841aef4d399d77de4)
+++ uspace/lib/fdisk/include/types/fdisk.h	(revision b598460af2662df4c20ccda2b3de00d8057bcacd)
@@ -45,4 +45,5 @@
 #include <vol.h>
 
+/** Capacity unit */
 typedef enum {
 	cu_byte = 0,
@@ -56,4 +57,11 @@
 	cu_ybyte
 } fdisk_cunit_t;
+
+typedef enum {
+	/** Primary partition space */
+	spc_pri,
+	/** Logical partition space */
+	spc_log
+} fdisk_spc_t;
 
 /** Fdisk device flags */
@@ -177,4 +185,17 @@
 } fdisk_part_info_t;
 
+/** Free range iterator */
+typedef struct {
+	/** Device */
+	fdisk_dev_t *dev;
+	/** Primary or logical partition space */
+	fdisk_spc_t spc;
+	/** First block of free range */
+	aoff64_t b0;
+	/** Next partition following the free range or @c NULL if the range
+	  * is at the end. */
+	fdisk_part_t *npart;
+} fdisk_free_range_t;
+
 /** Fdisk instance */
 typedef struct fdisk {
Index: uspace/lib/fdisk/src/fdisk.c
===================================================================
--- uspace/lib/fdisk/src/fdisk.c	(revision 44fe800cf1bcb06ed02fb05841aef4d399d77de4)
+++ uspace/lib/fdisk/src/fdisk.c	(revision b598460af2662df4c20ccda2b3de00d8057bcacd)
@@ -67,4 +67,9 @@
 static uint64_t fdisk_ba_align_up(fdisk_dev_t *, uint64_t);
 static uint64_t fdisk_ba_align_down(fdisk_dev_t *, uint64_t);
+static int fdisk_part_get_max_free_range(fdisk_dev_t *, fdisk_spc_t, aoff64_t *,
+    aoff64_t *);
+static void fdisk_free_range_first(fdisk_dev_t *, fdisk_spc_t, fdisk_free_range_t *);
+static bool fdisk_free_range_next(fdisk_free_range_t *);
+static bool fdisk_free_range_get(fdisk_free_range_t *, aoff64_t *, aoff64_t *);
 
 static void fdisk_dev_info_delete(fdisk_dev_info_t *info)
@@ -278,22 +283,27 @@
 	}
 
-	printf("vol_part_add(%zu)...\n", pinfo.svc_id);
-	/*
-	 * Normally vol service discovers the partition asynchronously.
-	 * Here we need to make sure the partition is already known to it.
-	 */
-	rc = vol_part_add(dev->fdisk->vol, pinfo.svc_id);
-	printf("vol_part_add->rc = %d\n", rc);
-	if (rc != EOK && rc != EEXIST) {
-		rc = EIO;
-		goto error;
-	}
-
-	printf("vol_part_info(%zu)\n", pinfo.svc_id);
-	rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
-	printf("vol_part_info->rc = %d\n", rc);
-	if (rc != EOK) {
-		rc = EIO;
-		goto error;
+	if (pinfo.svc_id != 0) {
+		printf("vol_part_add(%zu)...\n", pinfo.svc_id);
+		/*
+		 * Normally vol service discovers the partition asynchronously.
+		 * Here we need to make sure the partition is already known to it.
+		 */
+		rc = vol_part_add(dev->fdisk->vol, pinfo.svc_id);
+		printf("vol_part_add->rc = %d\n", rc);
+		if (rc != EOK && rc != EEXIST) {
+			rc = EIO;
+			goto error;
+		}
+
+		printf("vol_part_info(%zu)\n", pinfo.svc_id);
+		rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
+		printf("vol_part_info->rc = %d\n", rc);
+		if (rc != EOK) {
+			rc = EIO;
+			goto error;
+		}
+
+		part->pcnt = vpinfo.pcnt;
+		part->fstype = vpinfo.fstype;
 	}
 
@@ -304,6 +314,4 @@
 	part->pkind = pinfo.pkind;
 	part->svc_id = pinfo.svc_id;
-	part->pcnt = vpinfo.pcnt;
-	part->fstype = vpinfo.fstype;
 
 	switch (part->pkind) {
@@ -620,4 +628,6 @@
 {
 	vbd_disk_info_t vinfo;
+	uint64_t b0, nb;
+	uint64_t hdrb;
 	int rc;
 
@@ -630,4 +640,22 @@
 	info->ltype = vinfo.ltype;
 	info->flags = vinfo.flags;
+
+	if ((info->flags & lf_can_create_pri) != 0 ||
+	    (info->flags & lf_can_create_ext) != 0) {
+		/* Verify there is enough space to create partition */
+
+		rc = fdisk_part_get_max_free_range(dev, spc_pri, &b0, &nb);
+		if (rc != EOK)
+			info->flags &= ~(lf_can_create_pri | lf_can_create_ext);
+	}
+
+	if ((info->flags & lf_can_create_log) != 0) {
+		/* Verify there is enough space to create logical partition */
+		hdrb = max(1, dev->align);
+		rc = fdisk_part_get_max_free_range(dev, spc_log, &b0, &nb);
+		if (rc != EOK || nb <= hdrb)
+			info->flags &= ~lf_can_create_log;
+	}
+
 	return EOK;
 error:
@@ -735,6 +763,25 @@
 }
 
-int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_cap_t *cap)
-{
+int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_spc_t spc, fdisk_cap_t *cap)
+{
+	int rc;
+	uint64_t b0;
+	uint64_t nb;
+	aoff64_t hdrb;
+
+	rc = fdisk_part_get_max_free_range(dev, spc, &b0, &nb);
+	if (rc != EOK)
+		return rc;
+
+	/* For logical partitions we need to subtract header size */
+	if (spc == spc_log) {
+		hdrb = max(1, dev->align);
+		if (nb <= hdrb)
+			return ENOSPC;
+		nb -= hdrb;
+	}
+
+	cap->value = nb * dev->dinfo.block_size;
+	cap->cunit = cu_byte;
 	return EOK;
 }
@@ -767,15 +814,20 @@
 	}
 
-	rc = vol_part_mkfs(dev->fdisk->vol, part->svc_id, pspec->fstype);
-	if (rc != EOK && rc != ENOTSUP) {
-		printf("mkfs failed\n");
-		fdisk_part_remove(part);
-		(void) vbd_part_delete(dev->fdisk->vbd, partid);
-		return EIO;
+	if (part->svc_id != 0) {
+		rc = vol_part_mkfs(dev->fdisk->vol, part->svc_id, pspec->fstype);
+		if (rc != EOK && rc != ENOTSUP) {
+			printf("mkfs failed\n");
+			fdisk_part_remove(part);
+			(void) vbd_part_delete(dev->fdisk->vbd, partid);
+			return EIO;
+		}
 	}
 
 	printf("fdisk_part_create() - done\n");
-	part->pcnt = vpc_fs;
-	part->fstype = pspec->fstype;
+	if (part->svc_id != 0) {
+		part->pcnt = vpc_fs;
+		part->fstype = pspec->fstype;
+	}
+
 	part->capacity = pspec->capacity;
 
@@ -966,111 +1018,57 @@
  */
 static int fdisk_part_get_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
+    fdisk_spc_t spc, aoff64_t *rblock0, aoff64_t *rnblocks)
+{
+	fdisk_free_range_t fr;
+	uint64_t b0;
+	uint64_t nb;
+
+	fdisk_free_range_first(dev, spc, &fr);
+	do {
+		if (fdisk_free_range_get(&fr, &b0, &nb)) {
+			printf("free range: [%" PRIu64 ",+%" PRIu64 "]\n",
+			    b0, nb);
+			if (nb >= nblocks) {
+				printf("accepted.\n");
+				*rblock0 = b0;
+				*rnblocks = nb;
+				return EOK;
+			}
+		}
+	} while (fdisk_free_range_next(&fr));
+
+	/* No conforming free range found */
+	return ENOSPC;
+}
+
+/** Get largest free range of blocks.
+ *
+ * Get free range of blocks of the maximum size.
+ */
+static int fdisk_part_get_max_free_range(fdisk_dev_t *dev, fdisk_spc_t spc,
     aoff64_t *rblock0, aoff64_t *rnblocks)
 {
-	link_t *link;
-	fdisk_part_t *part;
-	uint64_t avail;
-	uint64_t pb0;
-	uint64_t nba;
-
-	printf("fdisk_part_get_free_range: align=%" PRIu64 "\n",
-	    dev->align);
-
-	link = list_first(&dev->pri_ba);
-	nba = fdisk_ba_align_up(dev, dev->dinfo.ablock0);
-	while (link != NULL) {
-		part = list_get_instance(link, fdisk_part_t, lpri_ba);
-		pb0 = fdisk_ba_align_down(dev, part->block0);
-		if (pb0 >= nba && pb0 - nba >= nblocks)
-			break;
-		nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
-		link = list_next(link, &dev->pri_ba);
-	}
-
-	if (link != NULL) {
-		printf("nba=%" PRIu64 " pb0=%" PRIu64 "\n",
-		    nba, pb0);
-		/* Free range before a partition */
-		avail = pb0 - nba;
-	} else {
-		/* Free range at the end */
-		pb0 = fdisk_ba_align_down(dev, dev->dinfo.ablock0 +
-		    dev->dinfo.anblocks);
-		if (pb0 < nba)
-			return ELIMIT;
-		avail = pb0 - nba;
-		printf("nba=%" PRIu64 " avail=%" PRIu64 "\n",
-		    nba, avail);
-
-	}
-
-	/* Verify that the range is large enough */
-	if (avail < nblocks)
-		return ELIMIT;
-
-	*rblock0 = nba;
-	*rnblocks = avail;
-	return EOK;
-}
-
-/** 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;
-	uint64_t pb0;
-	uint64_t nba;
-
-	printf("fdisk_part_get_log_free_range\n");
-	/* Number of header blocks */
-	hdrb = max(1, dev->align);
-
-	link = list_first(&dev->log_ba);
-	nba = fdisk_ba_align_up(dev, dev->ext_part->block0);
-	while (link != NULL) {
-		part = list_get_instance(link, fdisk_part_t, llog_ba);
-		pb0 = fdisk_ba_align_down(dev, part->block0);
-		if (pb0 >= nba && pb0 - nba >= nblocks)
-			break;
-		nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
-		link = list_next(link, &dev->log_ba);
-	}
-
-	if (link != NULL) {
-		/* Free range before a partition */
-		avail = pb0 - nba;
-	} else {
-		/* Free range at the end */
-		pb0 = fdisk_ba_align_down(dev, dev->ext_part->block0 +
-		    dev->ext_part->nblocks);
-		if (pb0 < nba) {
-			printf("not enough space\n");
-			return ELIMIT;
+	fdisk_free_range_t fr;
+	uint64_t b0;
+	uint64_t nb;
+	uint64_t best_b0;
+	uint64_t best_nb;
+
+	best_b0 = best_nb = 0;
+	fdisk_free_range_first(dev, spc, &fr);
+	do {
+		if (fdisk_free_range_get(&fr, &b0, &nb)) {
+			if (nb > best_nb) {
+				best_b0 = b0;
+				best_nb = nb;
+			}
 		}
-
-		avail = pb0 - nba;
-
-		printf("nba=%" PRIu64 " pb0=%" PRIu64" avail=%" PRIu64 "\n",
-		    nba, pb0, avail);
-	}
-	/* Verify that the range is large enough */
-	if (avail < hdrb + nblocks) {
-		printf("not enough space\n");
-		return ELIMIT;
-	}
-
-	*rhdrb = hdrb;
-	*rblock0 = nba + hdrb;
-	*rnblocks = avail;
-	printf("hdrb=%" PRIu64 " block0=%" PRIu64" avail=%" PRIu64 "\n",
-	    hdrb, nba + hdrb, avail);
+	} while (fdisk_free_range_next(&fr));
+
+	if (best_nb == 0)
+		return ENOSPC;
+
+	*rblock0 = best_b0;
+	*rnblocks = best_nb;
 	return EOK;
 }
@@ -1082,7 +1080,7 @@
 	uint64_t cbytes;
 	aoff64_t req_blocks;
-	aoff64_t fhdr;
 	aoff64_t fblock0;
 	aoff64_t fnblocks;
+	aoff64_t hdrb;
 	uint64_t block_size;
 	label_pcnt_t pcnt;
@@ -1136,5 +1134,6 @@
 
 		printf("fdisk_part_spec_prepare() - get free range\n");
-		rc = fdisk_part_get_free_range(dev, req_blocks, &fblock0, &fnblocks);
+		rc = fdisk_part_get_free_range(dev, req_blocks, spc_pri,
+		    &fblock0, &fnblocks);
 		if (rc != EOK)
 			return EIO;
@@ -1149,5 +1148,6 @@
 	case lpk_logical:
 		printf("fdisk_part_spec_prepare() - log\n");
-		rc = fdisk_part_get_log_free_range(dev, req_blocks, &fhdr,
+		hdrb = max(1, dev->align);
+		rc = fdisk_part_get_free_range(dev, hdrb + req_blocks, spc_log,
 		    &fblock0, &fnblocks);
 		if (rc != EOK)
@@ -1155,10 +1155,8 @@
 
 		memset(vpspec, 0, sizeof(vbd_part_spec_t));
-		vpspec->hdr_blocks = fhdr;
-		vpspec->block0 = fblock0;
+		vpspec->hdr_blocks = hdrb;
+		vpspec->block0 = fblock0 + hdrb;
 		vpspec->nblocks = req_blocks;
 		vpspec->pkind = lpk_logical;
-		vpspec->ptype.fmt = lptf_num;
-		vpspec->ptype.t.num = 42;
 		break;
 	}
@@ -1209,4 +1207,88 @@
 }
 
+static void fdisk_free_range_first(fdisk_dev_t *dev, fdisk_spc_t spc,
+    fdisk_free_range_t *fr)
+{
+	link_t *link;
+
+	fr->dev = dev;
+	fr->spc = spc;
+
+	if (fr->spc == spc_pri) {
+		/* Primary partitions */
+		fr->b0 = fdisk_ba_align_up(fr->dev, fr->dev->dinfo.ablock0);
+
+		link = list_first(&dev->pri_ba);
+		if (link != NULL)
+			fr->npart = list_get_instance(link, fdisk_part_t, lpri_ba);
+		else
+			fr->npart = NULL;
+	} else { /* fr->spc == spc_log */
+		/* Logical partitions */
+		fr->b0 = fdisk_ba_align_up(fr->dev, fr->dev->ext_part->block0);
+
+		link = list_first(&dev->log_ba);
+		if (link != NULL)
+			fr->npart = list_get_instance(link, fdisk_part_t, llog_ba);
+		else
+			fr->npart = NULL;
+	}
+}
+
+static bool fdisk_free_range_next(fdisk_free_range_t *fr)
+{
+	link_t *link;
+
+	if (fr->npart == NULL)
+		return false;
+
+	fr->b0 = fdisk_ba_align_up(fr->dev, fr->npart->block0 +
+	    fr->npart->nblocks);
+
+	if (fr->spc == spc_pri) {
+		/* Primary partitions */
+		link = list_next(&fr->npart->lpri_ba, &fr->dev->pri_ba);
+		if (link != NULL)
+			fr->npart = list_get_instance(link, fdisk_part_t, lpri_ba);
+		else
+			fr->npart = NULL;
+	} else { /* fr->spc == spc_log */
+		/* Logical partitions */
+		link = list_next(&fr->npart->llog_ba, &fr->dev->log_ba);
+		if (link != NULL)
+			fr->npart = list_get_instance(link, fdisk_part_t, llog_ba);
+		else
+			fr->npart = NULL;
+	}
+
+	return true;
+}
+
+static bool fdisk_free_range_get(fdisk_free_range_t *fr,
+    aoff64_t *b0, aoff64_t *nb)
+{
+	aoff64_t b1;
+
+	if (fr->npart != NULL) {
+		b1 = fdisk_ba_align_down(fr->dev, fr->npart->block0);
+	} else {
+		if (fr->spc == spc_pri) {
+			b1 = fdisk_ba_align_down(fr->dev,
+			    fr->dev->dinfo.ablock0 + fr->dev->dinfo.anblocks);
+		} else { /* fr->spc == spc_log */
+			b1 = fdisk_ba_align_down(fr->dev,
+			    fr->dev->ext_part->block0 + fr->dev->ext_part->nblocks);
+		}
+	}
+
+	if (b1 < fr->b0)
+		return false;
+
+	*b0 = fr->b0;
+	*nb = b1 - fr->b0;
+
+	return true;
+}
+
 /** @}
  */
