diff --git a/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch b/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
new file mode 100644
index 0000000..86e577c
--- /dev/null
+++ b/SOURCES/0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
@@ -0,0 +1,231 @@
+From 81745b42a2722f11006c05de87ff90de08cf8cee Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 28 Jun 2016 11:30:21 +0200
+Subject: [PATCH] fdisk: backport DOS logical partitions chain reorder
+
+... from the current upstream.
+
+Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1304246
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ fdisks/fdiskdoslabel.c | 170 +++++++++++++++++++++++++++++++++----------------
+ include/c.h            |   8 +++
+ 2 files changed, 124 insertions(+), 54 deletions(-)
+
+diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c
+index fe04ac7..b7eb35a 100644
+--- a/fdisks/fdiskdoslabel.c
++++ b/fdisks/fdiskdoslabel.c
+@@ -55,6 +55,22 @@ static int MBRbuffer_changed;
+ #define cround(c, n)	(fdisk_context_use_cylinders(c) ? \
+ 				((n) / fdisk_context_get_units_per_sector(c)) + 1 : (n))
+ 
++
++static unsigned long long
++get_abs_partition_start(struct pte *pe)
++{
++	return pe->offset + get_start_sect(pe->part_table);
++}
++
++static unsigned long long
++get_abs_partition_end(struct pte *pe)
++{
++	unsigned long long size;
++
++	size = get_nr_sects(pe->part_table);
++	return get_abs_partition_start(pe) + size - (size ? 1 : 0);
++}
++
+ static void warn_alignment(struct fdisk_context *cxt)
+ {
+ 	if (nowarn)
+@@ -1254,67 +1270,113 @@ void dos_list_table_expert(struct fdisk_context *cxt, int extend)
+ 	}
+ }
+ 
+-/*
+- * Fix the chain of logicals.
+- * extended_offset is unchanged, the set of sectors used is unchanged
+- * The chain is sorted so that sectors increase, and so that
+- * starting sectors increase.
+- *
+- * After this it may still be that cfdisk doesn't like the table.
+- * (This is because cfdisk considers expanded parts, from link to
+- * end of partition, and these may still overlap.)
+- * Now
+- *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
+- * may help.
+- */
++
++static void print_chain_of_logicals(struct fdisk_context *cxt)
++{
++	size_t i;
++
++	fputc('\n', stdout);
++
++	for (i = 4; i < cxt->label->nparts_max; i++) {
++		struct pte *pe = &ptes[i];
++
++		fprintf(stderr, "#%02zu EBR [%10ju], "
++			"data[start=%10ju (%10ju), size=%10ju], "
++			"link[start=%10ju (%10ju), size=%10ju]\n",
++			i, (uintmax_t) pe->offset,
++			/* data */
++			(uintmax_t) get_start_sect(pe->part_table),
++			(uintmax_t) get_abs_partition_start(pe),
++			(uintmax_t) get_nr_sects(pe->part_table),
++			/* link */
++			(uintmax_t) get_start_sect(pe->ext_pointer),
++			(uintmax_t) (extended_offset + get_start_sect(pe->ext_pointer)),
++			(uintmax_t) get_nr_sects(pe->ext_pointer));
++	}
++}
++
++static int cmp_ebr_offsets(const void *a, const void *b)
++{
++	struct pte *ae = (struct pte *) a,
++		   *be = (struct pte *) b;
++
++	if (ae->offset == 0 && be->offset == 0)
++		return 0;
++	if (ae->offset == 0)
++		return 1;
++	if (be->offset == 0)
++		return -1;
++
++	return cmp_numbers(ae->offset, be->offset);
++}
++
+ static void fix_chain_of_logicals(struct fdisk_context *cxt)
+ {
+-	size_t j, oj, ojj, sj, sjj;
+-	struct partition *pj,*pjj,tmp;
+-
+-	/* Stage 1: sort sectors but leave sector of part 4 */
+-	/* (Its sector is the global extended_offset.) */
+- stage1:
+-	for (j = 5; j < cxt->label->nparts_max - 1; j++) {
+-		oj = ptes[j].offset;
+-		ojj = ptes[j+1].offset;
+-		if (oj > ojj) {
+-			ptes[j].offset = ojj;
+-			ptes[j+1].offset = oj;
+-			pj = ptes[j].part_table;
+-			set_start_sect(pj, get_start_sect(pj)+oj-ojj);
+-			pjj = ptes[j+1].part_table;
+-			set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
+-			set_start_sect(ptes[j-1].ext_pointer,
+-				       ojj-extended_offset);
+-			set_start_sect(ptes[j].ext_pointer,
+-				       oj-extended_offset);
+-			goto stage1;
++	struct pte *last;
++	size_t i;
++
++	DBG(CONTEXT, print_chain_of_logicals(cxt));
++
++	/* Sort chain by EBR offsets */
++	qsort(&ptes[4], cxt->label->nparts_max - 4, sizeof(struct pte),
++			cmp_ebr_offsets);
++
++again:
++	/* Sort data partitions by start */
++	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
++		struct pte *cur = &ptes[i],
++			   *nxt = &ptes[i + 1];
++
++		if (get_abs_partition_start(cur) >
++		    get_abs_partition_start(nxt)) {
++
++			struct partition tmp = *cur->part_table;
++			sector_t cur_start = get_abs_partition_start(cur),
++				 nxt_start = get_abs_partition_start(nxt);
++
++			/* swap data partitions */
++			*cur->part_table = *nxt->part_table;
++			*nxt->part_table = tmp;
++
++			/* Recount starts according to EBR offsets, the absolute
++			 * address still has to be the same! */
++			set_start_sect(cur->part_table, nxt_start - cur->offset);
++			set_start_sect(nxt->part_table, cur_start - nxt->offset);
++
++			cur->changed = 1;
++			nxt->changed = 1;
++			goto again;
+ 		}
+ 	}
+ 
+-	/* Stage 2: sort starting sectors */
+- stage2:
+-	for (j = 4; j < cxt->label->nparts_max - 1; j++) {
+-		pj = ptes[j].part_table;
+-		pjj = ptes[j+1].part_table;
+-		sj = get_start_sect(pj);
+-		sjj = get_start_sect(pjj);
+-		oj = ptes[j].offset;
+-		ojj = ptes[j+1].offset;
+-		if (oj+sj > ojj+sjj) {
+-			tmp = *pj;
+-			*pj = *pjj;
+-			*pjj = tmp;
+-			set_start_sect(pj, ojj+sjj-oj);
+-			set_start_sect(pjj, oj+sj-ojj);
+-			goto stage2;
+-		}
++	/* Update EBR links */
++	for (i = 4; i < cxt->label->nparts_max - 1; i++) {
++		struct pte *cur = &ptes[i],
++			   *nxt = &ptes[i + 1];
++
++		sector_t noff = nxt->offset - extended_offset,
++		         ooff = get_start_sect(cur->ext_pointer);
++
++		if (noff == ooff)
++			continue;
++
++		DBG(CONTEXT, dbgprint("DOS: fix EBR [%10ju] link %ju -> %ju",
++			(uintmax_t) cur->offset,
++			(uintmax_t) ooff, (uintmax_t) noff));
++
++		set_partition(cxt, i, 1, nxt->offset,
++				get_abs_partition_end(nxt),
++				EXTENDED);
++	}
++
++	/* always terminate the chain ! */
++	last = &ptes[cxt->label->nparts_max - 1];
++	if (last) {
++		clear_partition(last->ext_pointer);
++		last->changed = 1;
+ 	}
+ 
+-	/* Probably something was changed */
+-	for (j = 4; j < cxt->label->nparts_max; j++)
+-		ptes[j].changed = 1;
++	DBG(CONTEXT, print_chain_of_logicals(cxt));
+ }
+ 
+ void dos_fix_partition_table_order(struct fdisk_context *cxt)
+diff --git a/include/c.h b/include/c.h
+index a50e8a5..ef2ea69 100644
+--- a/include/c.h
++++ b/include/c.h
+@@ -110,6 +110,14 @@
+ 	_max1 > _max2 ? _max1 : _max2; })
+ #endif
+ 
++#ifndef cmp_numbers
++# define cmp_numbers(x, y) __extension__ ({	\
++	__typeof__(x) _a = (x);			\
++	__typeof__(y) _b = (y);			\
++	(void) (&_a == &_b);			\
++	_a == _b ? 0 : _a > _b ? 1 : -1; })
++#endif
++
+ #ifndef offsetof
+ #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+ #endif
+-- 
+2.7.4
+
diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec
index 2330593..dd22223 100644
--- a/SPECS/util-linux.spec
+++ b/SPECS/util-linux.spec
@@ -2,7 +2,7 @@
 Summary: A collection of basic system utilities
 Name: util-linux
 Version: 2.23.2
-Release: 26%{?dist}.2
+Release: 26%{?dist}.3
 License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain
 Group: System Environment/Base
 URL: http://en.wikipedia.org/wiki/Util-linux
@@ -205,6 +205,8 @@ Patch57: 2.26-libblkid-fat.patch
 Patch58: 2.27-libblkid-xfs-log.patch
 # 1317953 - lslogins crash when executed with buggy username
 Patch59: 2.28-lslogins-1317953.patch
+# 1350777 - fdisk 'f' subcommand updates partition ranges wrongly
+Patch60: 0060-fdisk-backport-DOS-logical-partitions-chain-reorder.patch
 
 %description
 The util-linux package contains a large variety of low-level system
@@ -924,6 +926,9 @@ fi
 %{_libdir}/pkgconfig/uuid.pc
 
 %changelog
+* Thu Jun 30 2016 Karel Zak <kzak@redhat.com> 2.23.2-26.el7_2.3
+- fix #1350777 - fdisk 'f' subcommand updates partition ranges wrongly
+
 * Wed Mar 16 2016 Karel Zak <kzak@redhat.com> 2.23.2-26.el7_2.2
 - fix #1317953 - lslogins crash when executed with buggy username