Index: uspace/app/fdisk/fdisk.c
===================================================================
--- uspace/app/fdisk/fdisk.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/app/fdisk/fdisk.c	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -429,4 +429,6 @@
 	}
 
+	fdisk_cap_simplify(&mcap);
+
 	rc = fdisk_cap_format(&mcap, &smcap);
 	if (rc != EOK) {
Index: uspace/lib/fdisk/include/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/fdisk.h	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/fdisk/include/fdisk.h	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -75,5 +75,5 @@
 extern void fdisk_cap_simplify(fdisk_cap_t *);
 extern void fdisk_cap_from_blocks(uint64_t, size_t, fdisk_cap_t *);
-extern int fdisk_cap_to_blocks(fdisk_cap_t *, size_t, uint64_t *);
+extern int fdisk_cap_to_blocks(fdisk_cap_t *, fdisk_cvsel_t, size_t, uint64_t *);
 
 extern int fdisk_ltype_format(label_type_t, char **);
Index: uspace/lib/fdisk/include/types/fdisk.h
===================================================================
--- uspace/lib/fdisk/include/types/fdisk.h	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/fdisk/include/types/fdisk.h	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -57,4 +57,14 @@
 	cu_ybyte
 } fdisk_cunit_t;
+
+/** Which of values within the precision of the capacity */
+typedef enum {
+	/** The nominal (middling) value */
+	fcv_nom,
+	/** The minimum value */
+	fcv_min,
+	/** The maximum value */
+	fcv_max
+} fdisk_cvsel_t;
 
 typedef enum {
Index: uspace/lib/fdisk/src/cap.c
===================================================================
--- uspace/lib/fdisk/src/cap.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/fdisk/src/cap.c	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -76,14 +76,23 @@
  * of bytes is not divisible by the number of blocks, it is rounded
  * up to an integer number of blocks.
- */
-int fdisk_cap_to_blocks(fdisk_cap_t *cap, size_t block_size,
-    uint64_t *blocks)
+ *
+ * A capacity value entails precision, i.e. it corresponds to a range
+ * of values. @a cvsel selects the value to return. @c fcv_nom gives
+ * the nominal (middle) value, @c fcv_min gives the minimum value
+ * and @c fcv_max gives the maximum value.
+ */
+int fdisk_cap_to_blocks(fdisk_cap_t *cap, fdisk_cvsel_t cvsel,
+    size_t block_size, uint64_t *rblocks)
 {
 	int exp;
 	uint64_t bytes;
 	uint64_t f;
+	uint64_t adj;
+	uint64_t blocks;
+	uint64_t rem;
 	int rc;
 
-	// XXX Check for overflow
+	printf("fdisk_cap_to_blocks: m=%" PRIu64 ", dp=%d, cunit=%d\n",
+	    cap->m, cap->dp, cap->cunit);
 
 	exp = cap->cunit * 3 - cap->dp;
@@ -93,12 +102,39 @@
 			return ERANGE;
 		bytes = (cap->m + (f / 2)) / f;
+		if (bytes * f - (f / 2) != cap->m)
+			return ERANGE;
 	} else {
 		rc = ipow10_u64(exp, &f);
 		if (rc != EOK)
 			return ERANGE;
-		bytes = cap->m * f;
-	}
-
-	*blocks = (bytes + block_size - 1) / block_size;
+
+		adj = 0;
+		switch (cvsel) {
+		case fcv_nom:
+			adj = 0;
+			break;
+		case fcv_min:
+			adj = -(f / 2);
+			break;
+		case fcv_max:
+			adj = f / 2 - 1;
+			break;
+		}
+
+		printf("f=%" PRIu64 ", adj=%" PRId64 "\n", f, adj);
+		bytes = cap->m * f + adj;
+		printf("bytes=%" PRIu64 "\n", bytes);
+		if ((bytes - adj) / f != cap->m)
+			return ERANGE;
+	}
+
+	rem = bytes % block_size;
+	if ((bytes + rem) < bytes)
+		return ERANGE;
+
+	blocks = (bytes + rem) / block_size;
+	printf("blocks=%" PRIu64 "\n", blocks);
+
+	*rblocks = blocks;
 	return EOK;
 }
@@ -185,12 +221,52 @@
 }
 
+static int fdisk_digit_val(char c, int *val)
+{
+	switch (c) {
+	case '0': *val = 0; break;
+	case '1': *val = 1; break;
+	case '2': *val = 2; break;
+	case '3': *val = 3; break;
+	case '4': *val = 4; break;
+	case '5': *val = 5; break;
+	case '6': *val = 6; break;
+	case '7': *val = 7; break;
+	case '8': *val = 8; break;
+	case '9': *val = 9; break;
+	default:
+		return EINVAL;
+	}
+
+	return EOK;
+}
+
 int fdisk_cap_parse(const char *str, fdisk_cap_t *cap)
 {
-	char *eptr;
-	char *p;
-	unsigned long val;
+	const char *eptr;
+	const char *p;
+	int d;
+	int dp;
+	unsigned long m;
 	int i;
 
-	val = strtoul(str, &eptr, 10);
+	m = 0;
+
+	eptr = str;
+	while (fdisk_digit_val(*eptr, &d) == EOK) {
+		m = m * 10 + d;
+		++eptr;
+	}
+
+	if (*eptr == '.') {
+		++eptr;
+		dp = 0;
+		while (fdisk_digit_val(*eptr, &d) == EOK) {
+			m = m * 10 + d;
+			++dp;
+			++eptr;
+		}
+	} else {
+		m = 0; dp = 0;
+	}
 
 	while (*eptr == ' ')
@@ -216,6 +292,6 @@
 	}
 
-	cap->m = val;
-	cap->dp = 0;
+	cap->m = m;
+	cap->dp = dp;
 	return EOK;
 }
Index: uspace/lib/fdisk/src/fdisk.c
===================================================================
--- uspace/lib/fdisk/src/fdisk.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/fdisk/src/fdisk.c	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -1037,9 +1037,13 @@
     vbd_part_spec_t *vpspec)
 {
-	aoff64_t req_blocks;
+	aoff64_t nom_blocks;
+	aoff64_t min_blocks;
+	aoff64_t max_blocks;
+	aoff64_t act_blocks;
 	aoff64_t fblock0;
 	aoff64_t fnblocks;
 	aoff64_t hdrb;
 	label_pcnt_t pcnt;
+	fdisk_spc_t spc;
 	int index;
 	int rc;
@@ -1047,7 +1051,25 @@
 	printf("fdisk_part_spec_prepare() - dev=%p pspec=%p vpspec=%p\n", dev, pspec,
 	    vpspec);
-	fdisk_cap_to_blocks(&pspec->capacity, dev->dinfo.block_size, &req_blocks);
-
-	req_blocks = fdisk_ba_align_up(dev, req_blocks);
+	rc = fdisk_cap_to_blocks(&pspec->capacity, fcv_nom, dev->dinfo.block_size,
+	    &nom_blocks);
+	if (rc != EOK)
+		return rc;
+
+	rc = fdisk_cap_to_blocks(&pspec->capacity, fcv_min, dev->dinfo.block_size,
+	    &min_blocks);
+	if (rc != EOK)
+		return rc;
+
+	rc = fdisk_cap_to_blocks(&pspec->capacity, fcv_max, dev->dinfo.block_size,
+	    &max_blocks);
+	if (rc != EOK)
+		return rc;
+
+	nom_blocks = fdisk_ba_align_up(dev, nom_blocks);
+	min_blocks = fdisk_ba_align_up(dev, min_blocks);
+	max_blocks = fdisk_ba_align_up(dev, max_blocks);
+
+	printf("fdisk_part_spec_prepare: nom=%" PRIu64 ", min=%" PRIu64
+	    ", max=%" PRIu64, nom_blocks, min_blocks, max_blocks);
 
 	pcnt = -1;
@@ -1071,41 +1093,59 @@
 		return EINVAL;
 
-	printf("fdisk_part_spec_prepare() - switch\n");
-	switch (pspec->pkind) {
-	case lpk_primary:
-	case lpk_extended:
-		printf("fdisk_part_spec_prepare() - pri/ext\n");
+	if (pspec->pkind == lpk_logical) {
+		hdrb = max(1, dev->align);
+		spc = spc_log;
+	} else {
+		hdrb = 0;
+		spc = spc_pri;
+	}
+
+	rc = fdisk_part_get_free_range(dev, hdrb + nom_blocks, spc,
+	    &fblock0, &fnblocks);
+
+	if (rc == EOK) {
+		/*
+		 * If the size of the free range would still give the same capacity
+		 * when rounded, allocate entire range. Otherwise allocate exactly
+		 * what we were asked for.
+		 */
+		if (fnblocks <= max_blocks) {
+			act_blocks = fnblocks;
+		} else {
+			act_blocks = hdrb + nom_blocks;
+		}
+	} else {
+		assert(rc == ENOSPC);
+
+		/*
+		 * There is no free range that can contain exactly the requested
+		 * capacity. Try to allocate at least such number of blocks
+		 * that would still fullfill the request within the limits
+		 * of the precision with witch the capacity was specified
+		 * (i.e. when rounded up).
+		 */
+		rc = fdisk_part_get_free_range(dev, hdrb + min_blocks, spc,
+		    &fblock0, &fnblocks);
+		if (rc != EOK)
+			return rc;
+
+		assert(fnblocks < hdrb + nom_blocks);
+		act_blocks = fnblocks;
+	}
+
+	if (pspec->pkind != lpk_logical) {
 		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, spc_pri,
-		    &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;
-		break;
-	case lpk_logical:
-		printf("fdisk_part_spec_prepare() - log\n");
-		hdrb = max(1, dev->align);
-		rc = fdisk_part_get_free_range(dev, hdrb + req_blocks, spc_log,
-		    &fblock0, &fnblocks);
-		if (rc != EOK)
-			return EIO;
-
-		memset(vpspec, 0, sizeof(vbd_part_spec_t));
-		vpspec->hdr_blocks = hdrb;
-		vpspec->block0 = fblock0 + hdrb;
-		vpspec->nblocks = req_blocks;
-		vpspec->pkind = lpk_logical;
-		break;
-	}
+	} else {
+		index = 0;
+	}
+
+	memset(vpspec, 0, sizeof(vbd_part_spec_t));
+	vpspec->index = index;
+	vpspec->hdr_blocks = hdrb;
+	vpspec->block0 = fblock0 + hdrb;
+	vpspec->nblocks = act_blocks;
+	vpspec->pkind = pspec->pkind;
 
 	if (pspec->pkind != lpk_extended) {
@@ -1115,4 +1155,8 @@
 			return EIO;
 	}
+
+	printf("fdisk_part_spec_prepare: hdrb=%" PRIu64 ", b0=%" PRIu64
+	    ", nblocks=%" PRIu64 ", pkind=%d\n", vpspec->hdr_blocks,
+	    vpspec->block0, vpspec->nblocks, vpspec->pkind);
 
 	return EOK;
Index: uspace/lib/label/src/mbr.c
===================================================================
--- uspace/lib/label/src/mbr.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/label/src/mbr.c	(revision 03661d192d37602b5a4a80d9df091bb800a4ba95)
@@ -512,4 +512,5 @@
 	int rc;
 
+	log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create");
 	if (pspec->ptype.fmt != lptf_num)
 		return EINVAL;
@@ -521,5 +522,4 @@
 
 	/* XXX Check if index is used */
-
 	part->label = label;
 	part->index = pspec->index;
@@ -545,5 +545,4 @@
 		break;
 	case lpk_logical:
-		log_msg(LOG_DEFAULT, LVL_NOTE, "check index");
 		part->ptype = pspec->ptype;
 		if (pspec->index != 0) {
@@ -587,11 +586,8 @@
 	} else {
 		/* Logical partition */
-
-		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);
@@ -601,13 +597,10 @@
 		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);
