Leave 2048 sectors space at the end when shrinking
authorNikos Skalkotos <skalkoto@grnet.gr>
Wed, 27 Jun 2012 14:42:17 +0000 (17:42 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Wed, 27 Jun 2012 14:42:17 +0000 (17:42 +0300)
Most partition manipulation programs leave 2048 sector empty space
after the last partition.

image_creator/disk.py
image_creator/gpt.py

index 2191df3..3ff0269 100644 (file)
@@ -320,6 +320,8 @@ class DiskDevice(object):
 
         self.out.output("Shrinking image (this may take a while)...", False)
 
 
         self.out.output("Shrinking image (this may take a while)...", False)
 
+        sector_size = self.g.blockdev_getss(self.guestfs_device)
+
         last_part = None
         fstype = None
         while True:
         last_part = None
         fstype = None
         while True:
@@ -336,7 +338,10 @@ class DiskDevice(object):
                 part_del(last_part['part_num'])
                 continue
 
                 part_del(last_part['part_num'])
                 continue
 
-            self.meta['SIZE'] = last_part['part_end'] + 1
+            # Most disk manipulation programs leave 2048 sectors after the last
+            # partition
+            new_size = last_part['part_end'] + 1 + 2048 * sector_size
+            self.meta['SIZE'] = min(self.meta['SIZE'], new_size)
             break
 
         if not re.match("ext[234]", fstype):
             break
 
         if not re.match("ext[234]", fstype):
@@ -353,7 +358,6 @@ class DiskDevice(object):
         block_cnt = int(
             filter(lambda x: x[0] == 'Block count', out)[0][1])
 
         block_cnt = int(
             filter(lambda x: x[0] == 'Block count', out)[0][1])
 
-        sector_size = self.g.blockdev_getss(self.guestfs_device)
         start = last_part['part_start'] / sector_size
         end = start + (block_size * block_cnt) / sector_size - 1
 
         start = last_part['part_start'] / sector_size
         end = start + (block_size * block_cnt) / sector_size - 1
 
@@ -398,13 +402,18 @@ class DiskDevice(object):
                 part_set_id(last_part['part_num'], last_part['id'])
 
         new_size = (end + 1) * sector_size
                 part_set_id(last_part['part_num'], last_part['id'])
 
         new_size = (end + 1) * sector_size
-        self.out.success("new size is %dMB" % ((new_size + MB - 1) // MB))
+
+        assert (new_size <= self.meta['SIZE'])
 
         if self.meta['PARTITION_TABLE'] == 'gpt':
             ptable = GPTPartitionTable(self.real_device)
 
         if self.meta['PARTITION_TABLE'] == 'gpt':
             ptable = GPTPartitionTable(self.real_device)
-            self.meta['SIZE'] = ptable.shrink(new_size)
+            self.meta['SIZE'] = ptable.shrink(new_size, self.meta['SIZE'])
         else:
         else:
-            self.meta['SIZE'] = new_size
+            self.meta['SIZE'] = min(new_size + 2048 * sector_size,
+                                    self.meta['SIZE'])
+
+        self.out.success("new size is %dMB" %
+                         ((self.meta['SIZE'] + MB - 1) // MB))
 
         return self.meta['SIZE']
 
 
         return self.meta['SIZE']
 
index f6f1cc2..afc2f7a 100644 (file)
@@ -255,18 +255,24 @@ class GPTPartitionTable(object):
         """Returns the payload size of GPT partitioned device."""
         return (self.primary.backup_lba + 1) * BLOCKSIZE
 
         """Returns the payload size of GPT partitioned device."""
         return (self.primary.backup_lba + 1) * BLOCKSIZE
 
-    def shrink(self, size):
+    def shrink(self, size, old_size):
         """Move the secondary GPT Header entries to the address specified by
         size parameter.
         """
         """Move the secondary GPT Header entries to the address specified by
         size parameter.
         """
-        if size == self.size():
-            return size
 
 
-        assert size < self.size()
+        # Most partition manipulation programs leave 2048 sector after the last
+        # partition
+        aligned = size + 2048 * BLOCKSIZE
+
+        # new_size is at least: size + Partition Entries + Secondary GPT Header
+        new_size = aligned if aligned <= old_size else \
+                   size + len(self.part_entries) + BLOCKSIZE
+
+        assert new_size <= old_size, "The secodary GPT fits in the device"
+
+        if new_size == self.size():
+            return new_size
 
 
-        # new_size = size + Partition Entries + Secondary GPT Header
-        new_size = size + len(self.part_entries) + BLOCKSIZE
-        new_size = ((new_size + 4095) // 4096) * 4096  # align to 4K
         lba_count = new_size // BLOCKSIZE
 
         # Correct MBR
         lba_count = new_size // BLOCKSIZE
 
         # Correct MBR