From: Phillip Susi <psusi@ubuntu.com>
Date: Sat, 26 Apr 2014 20:52:25 -0400
Subject: libparted: remove old partitions *first* before adding new
 ones
References: bsc#501773, bsc#1092327
Patch-mainline: v3.2
Git-commit: 9e07d797b18609613c53ceb2dabbb5e69d961186

"libparted: avoid disturbing partitions" put the remove of the old
partition in second pass.  If you simultaneously removed partitions 1
and 2, and created a new partition #1 that overlapped the previous second
partition, the sync would fail because it would try to create the new,
larger partition #1 before removing the old partition #2.

Acked-by: Sebastian Parschauer <sparschauer@suse.de>
---
 libparted/arch/linux.c                  |   43 +++++++++++++--------------
 tests/Makefile.am                       |    1 
 tests/t1104-remove-and-add-partition.sh |   50 ++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+), 22 deletions(-)
 create mode 100644 tests/t1104-remove-and-add-partition.sh

--- a/libparted/arch/linux.c
+++ b/libparted/arch/linux.c
@@ -2842,23 +2842,8 @@ _disk_sync_part_table (PedDisk* disk)
                             && start == part->geom.start
                             && length == part->geom.length)
                         {
-                                ok[i - 1] = 1;
-                                continue;
-                        }
-                }
-	}
-        for (i = 1; i <= lpn; i++) {
-                PedPartition *part = ped_disk_get_partition (disk, i);
-                if (part) {
-                        unsigned long long length;
-                        unsigned long long start;
-                        /* get start and length of existing partition */
-                        if (get_partition_start_and_length(part,
-                                                            &start, &length)
-                            && start == part->geom.start
-                            && length == part->geom.length) {
-                                ok[i - 1] = 1;
                                 /* partition is unchanged, so nothing to do */
+                                ok[i - 1] = 1;
                                 continue;
                         }
                 }
@@ -2877,12 +2862,26 @@ _disk_sync_part_table (PedDisk* disk)
                 } while (n_sleep--);
                 if (!ok[i - 1] && errnums[i - 1] == ENXIO)
                         ok[i - 1] = 1; /* it already doesn't exist */
-                if (part && ok[i - 1]) {
-                        /* add the (possibly modified or new) partition */
-                        if (!add_partition (disk, part)) {
-                                ok[i - 1] = 0;
-                                errnums[i - 1] = errno;
-                        }
+	}
+        for (i = 1; i <= lpn; i++) {
+                PedPartition *part = ped_disk_get_partition (disk, i);
+                if (!part)
+                        continue;
+                unsigned long long length;
+                unsigned long long start;
+                /* get start and length of existing partition */
+                if (get_partition_start_and_length(part,
+                                                   &start, &length)
+                    && start == part->geom.start
+                    && length == part->geom.length) {
+                        ok[i - 1] = 1;
+                        /* partition is unchanged, so nothing to do */
+                        continue;
+                }
+                /* add the (possibly modified or new) partition */
+                if (!add_partition (disk, part)) {
+                        ok[i - 1] = 0;
+                        errnums[i - 1] = errno;
                 }
         }
 
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,6 +33,7 @@ TESTS = \
   t0501-duplicate.sh \
   t1100-busy-label.sh \
   t1101-busy-partition.sh \
+  t1104-remove-and-add-partition.sh \
   t1700-probe-fs.sh \
   t2200-dos-label-recog.sh \
   t2201-pc98-label-recog.sh \
--- /dev/null
+++ b/tests/t1104-remove-and-add-partition.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+# make sure that removing a higher numbered partition and adding a lower
+# one using that space at the same time works
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../parted
+path_prepend_ ../partprobe
+require_root_
+ss=$sector_size_
+
+d1= f1=
+cleanup_fn_()
+{
+  test -n "$d1" && losetup -d "$d1"
+  rm -f "$f1"
+}
+
+f1=$(pwd)/1; d1=$(loop_setup_ "$f1") \
+  || skip_ "is this partition mounted with 'nodev'?"
+
+require_partitionable_loop_device_ $d1
+
+# create one big partition
+parted -s $d1 mklabel msdos mkpart primary ext2 1m 10m || fail=1
+
+# save this table
+dd if=$d1 of=saved count=1 || fail=1
+
+# create two small partitions
+parted -s $d1 mklabel msdos mkpart primary ext2 1m 5m mkpart primary ext2 5m 10m || fail=1
+
+# restore first table and make sure partprobe works
+dd if=saved of=$d1 || fail=1
+partprobe $d1 || fail=1
+
+Exit $fail
