dcavalca / rpms / util-linux

Forked from rpms/util-linux 2 years ago
Clone

Blame SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch

6ec1d7
From 81745b42a2722f11006c05de87ff90de08cf8cee Mon Sep 17 00:00:00 2001
6ec1d7
From: Karel Zak <kzak@redhat.com>
6ec1d7
Date: Tue, 28 Jun 2016 11:30:21 +0200
6ec1d7
Subject: [PATCH] fdisk: backport DOS logical partitions chain reorder
6ec1d7
6ec1d7
... from the current upstream.
6ec1d7
6ec1d7
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304246
6ec1d7
Signed-off-by: Karel Zak <kzak@redhat.com>
6ec1d7
---
6ec1d7
 fdisks/fdiskdoslabel.c | 170 +++++++++++++++++++++++++++++++++----------------
6ec1d7
 include/c.h            |   8 +++
6ec1d7
 2 files changed, 124 insertions(+), 54 deletions(-)
6ec1d7
6ec1d7
diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c
6ec1d7
index fe04ac7..b7eb35a 100644
6ec1d7
--- a/fdisks/fdiskdoslabel.c
6ec1d7
+++ b/fdisks/fdiskdoslabel.c
6ec1d7
@@ -55,6 +55,22 @@ static int MBRbuffer_changed;
6ec1d7
 #define cround(c, n)	(fdisk_context_use_cylinders(c) ? \
6ec1d7
 				((n) / fdisk_context_get_units_per_sector(c)) + 1 : (n))
6ec1d7
 
6ec1d7
+
6ec1d7
+static unsigned long long
6ec1d7
+get_abs_partition_start(struct pte *pe)
6ec1d7
+{
6ec1d7
+	return pe->offset + get_start_sect(pe->part_table);
6ec1d7
+}
6ec1d7
+
6ec1d7
+static unsigned long long
6ec1d7
+get_abs_partition_end(struct pte *pe)
6ec1d7
+{
6ec1d7
+	unsigned long long size;
6ec1d7
+
6ec1d7
+	size = get_nr_sects(pe->part_table);
6ec1d7
+	return get_abs_partition_start(pe) + size - (size ? 1 : 0);
6ec1d7
+}
6ec1d7
+
6ec1d7
 static void warn_alignment(struct fdisk_context *cxt)
6ec1d7
 {
6ec1d7
 	if (nowarn)
6ec1d7
@@ -1254,67 +1270,113 @@ void dos_list_table_expert(struct fdisk_context *cxt, int extend)
6ec1d7
 	}
6ec1d7
 }
6ec1d7
 
6ec1d7
-/*
6ec1d7
- * Fix the chain of logicals.
6ec1d7
- * extended_offset is unchanged, the set of sectors used is unchanged
6ec1d7
- * The chain is sorted so that sectors increase, and so that
6ec1d7
- * starting sectors increase.
6ec1d7
- *
6ec1d7
- * After this it may still be that cfdisk doesn't like the table.
6ec1d7
- * (This is because cfdisk considers expanded parts, from link to
6ec1d7
- * end of partition, and these may still overlap.)
6ec1d7
- * Now
6ec1d7
- *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
6ec1d7
- * may help.
6ec1d7
- */
6ec1d7
+
6ec1d7
+static void print_chain_of_logicals(struct fdisk_context *cxt)
6ec1d7
+{
6ec1d7
+	size_t i;
6ec1d7
+
6ec1d7
+	fputc('\n', stdout);
6ec1d7
+
6ec1d7
+	for (i = 4; i < cxt->label->nparts_max; i++) {
6ec1d7
+		struct pte *pe = &ptes[i];
6ec1d7
+
6ec1d7
+		fprintf(stderr, "#%02zu EBR [%10ju], "
6ec1d7
+			"data[start=%10ju (%10ju), size=%10ju], "
6ec1d7
+			"link[start=%10ju (%10ju), size=%10ju]\n",
6ec1d7
+			i, (uintmax_t) pe->offset,
6ec1d7
+			/* data */
6ec1d7
+			(uintmax_t) get_start_sect(pe->part_table),
6ec1d7
+			(uintmax_t) get_abs_partition_start(pe),
6ec1d7
+			(uintmax_t) get_nr_sects(pe->part_table),
6ec1d7
+			/* link */
6ec1d7
+			(uintmax_t) get_start_sect(pe->ext_pointer),
6ec1d7
+			(uintmax_t) (extended_offset + get_start_sect(pe->ext_pointer)),
6ec1d7
+			(uintmax_t) get_nr_sects(pe->ext_pointer));
6ec1d7
+	}
6ec1d7
+}
6ec1d7
+
6ec1d7
+static int cmp_ebr_offsets(const void *a, const void *b)
6ec1d7
+{
6ec1d7
+	struct pte *ae = (struct pte *) a,
6ec1d7
+		   *be = (struct pte *) b;
6ec1d7
+
6ec1d7
+	if (ae->offset == 0 && be->offset == 0)
6ec1d7
+		return 0;
6ec1d7
+	if (ae->offset == 0)
6ec1d7
+		return 1;
6ec1d7
+	if (be->offset == 0)
6ec1d7
+		return -1;
6ec1d7
+
6ec1d7
+	return cmp_numbers(ae->offset, be->offset);
6ec1d7
+}
6ec1d7
+
6ec1d7
 static void fix_chain_of_logicals(struct fdisk_context *cxt)
6ec1d7
 {
6ec1d7
-	size_t j, oj, ojj, sj, sjj;
6ec1d7
-	struct partition *pj,*pjj,tmp;
6ec1d7
-
6ec1d7
-	/* Stage 1: sort sectors but leave sector of part 4 */
6ec1d7
-	/* (Its sector is the global extended_offset.) */
6ec1d7
- stage1:
6ec1d7
-	for (j = 5; j < cxt->label->nparts_max - 1; j++) {
6ec1d7
-		oj = ptes[j].offset;
6ec1d7
-		ojj = ptes[j+1].offset;
6ec1d7
-		if (oj > ojj) {
6ec1d7
-			ptes[j].offset = ojj;
6ec1d7
-			ptes[j+1].offset = oj;
6ec1d7
-			pj = ptes[j].part_table;
6ec1d7
-			set_start_sect(pj, get_start_sect(pj)+oj-ojj);
6ec1d7
-			pjj = ptes[j+1].part_table;
6ec1d7
-			set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
6ec1d7
-			set_start_sect(ptes[j-1].ext_pointer,
6ec1d7
-				       ojj-extended_offset);
6ec1d7
-			set_start_sect(ptes[j].ext_pointer,
6ec1d7
-				       oj-extended_offset);
6ec1d7
-			goto stage1;
6ec1d7
+	struct pte *last;
6ec1d7
+	size_t i;
6ec1d7
+
6ec1d7
+	DBG(CONTEXT, print_chain_of_logicals(cxt));
6ec1d7
+
6ec1d7
+	/* Sort chain by EBR offsets */
6ec1d7
+	qsort(&ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte),
6ec1d7
+			cmp_ebr_offsets);
6ec1d7
+
6ec1d7
+again:
6ec1d7
+	/* Sort data partitions by start */
6ec1d7
+	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
6ec1d7
+		struct pte *cur = &ptes[i],
6ec1d7
+			   *nxt = &ptes[i + 1];
6ec1d7
+
6ec1d7
+		if (get_abs_partition_start(cur) >
6ec1d7
+		    get_abs_partition_start(nxt)) {
6ec1d7
+
6ec1d7
+			struct partition tmp = *cur->part_table;
6ec1d7
+			sector_t cur_start = get_abs_partition_start(cur),
6ec1d7
+				 nxt_start = get_abs_partition_start(nxt);
6ec1d7
+
6ec1d7
+			/* swap data partitions */
6ec1d7
+			*cur->part_table = *nxt->part_table;
6ec1d7
+			*nxt->part_table = tmp;
6ec1d7
+
6ec1d7
+			/* Recount starts according to EBR offsets, the absolute
6ec1d7
+			 * address still has to be the same! */
6ec1d7
+			set_start_sect(cur->part_table, nxt_start - cur->offset);
6ec1d7
+			set_start_sect(nxt->part_table, cur_start - nxt->offset);
6ec1d7
+
6ec1d7
+			cur->changed = 1;
6ec1d7
+			nxt->changed = 1;
6ec1d7
+			goto again;
6ec1d7
 		}
6ec1d7
 	}
6ec1d7
 
6ec1d7
-	/* Stage 2: sort starting sectors */
6ec1d7
- stage2:
6ec1d7
-	for (j = 4; j < cxt->label->nparts_max - 1; j++) {
6ec1d7
-		pj = ptes[j].part_table;
6ec1d7
-		pjj = ptes[j+1].part_table;
6ec1d7
-		sj = get_start_sect(pj);
6ec1d7
-		sjj = get_start_sect(pjj);
6ec1d7
-		oj = ptes[j].offset;
6ec1d7
-		ojj = ptes[j+1].offset;
6ec1d7
-		if (oj+sj > ojj+sjj) {
6ec1d7
-			tmp = *pj;
6ec1d7
-			*pj = *pjj;
6ec1d7
-			*pjj = tmp;
6ec1d7
-			set_start_sect(pj, ojj+sjj-oj);
6ec1d7
-			set_start_sect(pjj, oj+sj-ojj);
6ec1d7
-			goto stage2;
6ec1d7
-		}
6ec1d7
+	/* Update EBR links */
6ec1d7
+	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
6ec1d7
+		struct pte *cur = &ptes[i],
6ec1d7
+			   *nxt = &ptes[i + 1];
6ec1d7
+
6ec1d7
+		sector_t noff = nxt->offset - extended_offset,
6ec1d7
+		         ooff = get_start_sect(cur->ext_pointer);
6ec1d7
+
6ec1d7
+		if (noff == ooff)
6ec1d7
+			continue;
6ec1d7
+
6ec1d7
+		DBG(CONTEXT, dbgprint("DOS: fix EBR [%10ju] link %ju -> %ju",
6ec1d7
+			(uintmax_t) cur->offset,
6ec1d7
+			(uintmax_t) ooff, (uintmax_t) noff));
6ec1d7
+
6ec1d7
+		set_partition(cxt, i, 1, nxt->offset,
6ec1d7
+				get_abs_partition_end(nxt),
6ec1d7
+				EXTENDED);
6ec1d7
+	}
6ec1d7
+
6ec1d7
+	/* always terminate the chain ! */
6ec1d7
+	last = &ptes[cxt->label->nparts_max - 1];
6ec1d7
+	if (last) {
6ec1d7
+		clear_partition(last->ext_pointer);
6ec1d7
+		last->changed = 1;
6ec1d7
 	}
6ec1d7
 
6ec1d7
-	/* Probably something was changed */
6ec1d7
-	for (j = 4; j < cxt->label->nparts_max; j++)
6ec1d7
-		ptes[j].changed = 1;
6ec1d7
+	DBG(CONTEXT, print_chain_of_logicals(cxt));
6ec1d7
 }
6ec1d7
 
6ec1d7
 void dos_fix_partition_table_order(struct fdisk_context *cxt)
6ec1d7
diff --git a/include/c.h b/include/c.h
6ec1d7
index a50e8a5..ef2ea69 100644
6ec1d7
--- a/include/c.h
6ec1d7
+++ b/include/c.h
6ec1d7
@@ -110,6 +110,14 @@
6ec1d7
 	_max1 > _max2 ? _max1 : _max2; })
6ec1d7
 #endif
6ec1d7
 
6ec1d7
+#ifndef cmp_numbers
6ec1d7
+# define cmp_numbers(x, y) __extension__ ({	\
6ec1d7
+	__typeof__(x) _a = (x);			\
6ec1d7
+	__typeof__(y) _b = (y);			\
6ec1d7
+	(void) (&_a == &_b);			\
6ec1d7
+	_a == _b ? 0 : _a > _b ? 1 : -1; })
6ec1d7
+#endif
6ec1d7
+
6ec1d7
 #ifndef offsetof
6ec1d7
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6ec1d7
 #endif
6ec1d7
-- 
6ec1d7
2.7.4
6ec1d7