From 951c9515b3e13c86f9d92b25098ccf79387ffb43 Mon Sep 17 00:00:00 2001 From: Gui Chen Date: Fri, 23 Mar 2012 15:05:31 +0800 Subject: [PATCH] Backport: Add alignment option for partitions This a backport of Marko's mic2 patch with a few changes: https://meego.gitorious.org/meego-developer-tools/image-creator/merge_requests/28 use '--align' to specify the alignment in ks file e.g. in kickstart, 'part /boot --size 256 --ondisk sda --align=4' to specify the alignment of boot partition as 4k, align option is counted by KB. Signed-off-by: Gui Chen --- mic/imager/raw.py | 23 ++++++--- mic/kickstart/__init__.py | 4 ++ mic/kickstart/custom_commands/__init__.py | 2 + mic/kickstart/custom_commands/partition.py | 47 ++++++++++++++++++ mic/utils/partitionedfs.py | 76 +++++++++++++++++++++++------- 5 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 mic/kickstart/custom_commands/partition.py diff --git a/mic/imager/raw.py b/mic/imager/raw.py index 7c20079..b313b47 100644 --- a/mic/imager/raw.py +++ b/mic/imager/raw.py @@ -23,7 +23,7 @@ from pykickstart.urlgrabber import progress from mic import kickstart, msger from mic.utils import fs_related, runner -from mic.utils.partitionedfs import PartitionedMount +from mic.utils.partitionedfs import PartitionedMount, MBR_SECTOR_LEN, SECTOR_SIZE from mic.utils.errors import CreatorError, MountError from baseimager import BaseImageCreator @@ -154,6 +154,11 @@ class RawImageCreator(BaseImageCreator): size = parts[i].size * 1024L * 1024L + # If we have alignment set for partition we need to enlarge the + # drive, so that the alignment changes fits there as well + if parts[i].align: + size += parts[i].align * 1024L + found = False for j in range(len(self._diskinfo)): if self._diskinfo[j]['name'] == disk: @@ -166,6 +171,11 @@ class RawImageCreator(BaseImageCreator): if not found: self._diskinfo.append({ 'name': disk, 'size': size }) + # We need to add a bit space for the disk for the MBR. + # NOTE: This could be optimized in some cases when alignment is used. + for j in range(len(self._diskinfo)): + self._diskinfo[j]['size'] += MBR_SECTOR_LEN * SECTOR_SIZE + return self._diskinfo # @@ -178,10 +188,10 @@ class RawImageCreator(BaseImageCreator): #create disk for item in self.get_diskinfo(): - msger.debug("Adding disk %s as %s/%s-%s.raw" % (item['name'], - self.__imgdir, - self.name, - item['name'])) + msger.debug("Adding disk %s as %s/%s-%s.raw with size %s bytes" % + (item['name'], self.__imgdir, self.name, item['name'], + item['size'])) + disk = fs_related.SparseLoopbackDisk("%s/%s-%s.raw" % ( self.__imgdir, self.name, @@ -197,7 +207,8 @@ class RawImageCreator(BaseImageCreator): p.mountpoint, p.fstype, fsopts = p.fsopts, - boot = p.active) + boot = p.active, + align = p.align) self.__instloop.mount() self._create_mkinitrd_config() diff --git a/mic/kickstart/__init__.py b/mic/kickstart/__init__.py index baa6143..36e8feb 100644 --- a/mic/kickstart/__init__.py +++ b/mic/kickstart/__init__.py @@ -36,6 +36,7 @@ from pykickstart.handlers.control import dataMap import custom_commands.desktop as desktop import custom_commands.moblinrepo as moblinrepo import custom_commands.micboot as micboot +import custom_commands.partition as partition def read_kickstart(path): """Parse a kickstart file and return a KickstartParser instance. @@ -54,7 +55,10 @@ def read_kickstart(path): commandMap[using_version]["desktop"] = desktop.Moblin_Desktop commandMap[using_version]["repo"] = moblinrepo.Moblin_Repo commandMap[using_version]["bootloader"] = micboot.Moblin_Bootloader + commandMap[using_version]["part"] = partition.MeeGo_Partition + commandMap[using_version]["partition"] = partition.MeeGo_Partition dataMap[using_version]["RepoData"] = moblinrepo.Moblin_RepoData + dataMap[using_version]["PartData"] = partition.MeeGo_PartData superclass = ksversion.returnClassForVersion(version=using_version) class KSHandlers(superclass): diff --git a/mic/kickstart/custom_commands/__init__.py b/mic/kickstart/custom_commands/__init__.py index 7123ac1..dcfb56e 100644 --- a/mic/kickstart/custom_commands/__init__.py +++ b/mic/kickstart/custom_commands/__init__.py @@ -1,8 +1,10 @@ import desktop import moblinrepo +import partition __all__ = ( "Moblin_Desktop", "Moblin_Repo", "Moblin_RepoData", + "MeeGo_Partition", ) diff --git a/mic/kickstart/custom_commands/partition.py b/mic/kickstart/custom_commands/partition.py new file mode 100644 index 0000000..7b78319 --- /dev/null +++ b/mic/kickstart/custom_commands/partition.py @@ -0,0 +1,47 @@ +#!/usr/bin/python -tt +# +# Marko Saukko +# +# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# +# This copyrighted material is made available to anyone wishing to use, modify, +# copy, or redistribute it subject to the terms and conditions of the GNU +# General Public License v.2. This program is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the +# implied warranties 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, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from pykickstart.commands.partition import * + +class MeeGo_PartData(FC4_PartData): + removedKeywords = FC4_PartData.removedKeywords + removedAttrs = FC4_PartData.removedAttrs + + def __init__(self, *args, **kwargs): + FC4_PartData.__init__(self, *args, **kwargs) + self.deleteRemovedAttrs() + self.align = kwargs.get("align", None) + + def _getArgsAsStr(self): + retval = FC4_PartData._getArgsAsStr(self) + + if self.align: + retval += " --align" + + return retval + +class MeeGo_Partition(FC4_Partition): + removedKeywords = FC4_Partition.removedKeywords + removedAttrs = FC4_Partition.removedAttrs + + def _getParser(self): + op = FC4_Partition._getParser(self) + # The alignment value is given in kBytes. e.g., value 8 means that + # the partition is aligned to start from 8096 byte boundary. + op.add_option("--align", type="int", action="store", dest="align", + default=None) + return op diff --git a/mic/utils/partitionedfs.py b/mic/utils/partitionedfs.py index 63abb0c..2136401 100644 --- a/mic/utils/partitionedfs.py +++ b/mic/utils/partitionedfs.py @@ -25,6 +25,12 @@ from mic.utils import runner from mic.utils.errors import MountError from mic.utils.fs_related import * +# Lenght of MBR in sectors +MBR_SECTOR_LEN = 1 + +# Size of a sector in bytes +SECTOR_SIZE = 512 + class PartitionedMount(Mount): def __init__(self, disks, mountdir, skipformat = False): Mount.__init__(self, mountdir) @@ -37,9 +43,8 @@ class PartitionedMount(Mount): # Partitions with part num higher than 3 will # be put inside extended partition. 'extended': 0, # Size of extended partition - # Sector 0 is used by the MBR and can't be used - # as the start, so setting offset to 1. - 'offset': 1 } # Offset of next partition (in sectors) + # Offset of next partition (in sectors) + 'offset': 0 } self.partitions = [] self.subvolumes = [] @@ -55,10 +60,10 @@ class PartitionedMount(Mount): self.skipformat = skipformat self.snapshot_created = self.skipformat # Size of a sector used in calculations - self.sector_size = 512 + self.sector_size = SECTOR_SIZE - def add_partition(self, size, disk, mountpoint, fstype = None, fsopts = None, boot = False): - # Converting M to s for parted + def add_partition(self, size, disk, mountpoint, fstype = None, fsopts = None, boot = False, align = None): + # Converting MB to sectors for parted size = size * 1024 * 1024 / self.sector_size """ We need to handle subvolumes for btrfs """ @@ -102,12 +107,14 @@ class PartitionedMount(Mount): 'device': None, # kpartx device node for partition 'mount': None, # Mount object 'num': None, # Partition number - 'boot': boot}) # Bootable flag + 'boot': boot, # Bootable flag + 'align': align}) # Partition alignment - def __create_part_to_image(self,device, parttype, fstype, start, size): + def __create_part_to_image(self, device, parttype, fstype, start, size): # Start is included to the size so we need to substract one from the end. end = start+size-1 - msger.debug("Added '%s' part at %d of size %d" % (parttype,start,end)) + msger.debug("Added '%s' part at Sector %d with size %d sectors" % + (parttype, start, end)) part_cmd = [self.parted, "-s", device, "unit", "s", "mkpart", parttype] if fstype: part_cmd.extend([fstype]) @@ -123,22 +130,52 @@ class PartitionedMount(Mount): def __format_disks(self): msger.debug("Assigning partitions to disks") - mbr_sector_skipped = False - + # Go through partitions in the order they are added in .ks file for n in range(len(self.partitions)): p = self.partitions[n] if not self.disks.has_key(p['disk']): raise MountError("No disk %s for partition %s" % (p['disk'], p['mountpoint'])) - if not mbr_sector_skipped: - # This hack is used to remove one sector from the first partition, - # that is the used to the MBR. - p['size'] -= 1 - mbr_sector_skipped = True - + # Get the disk where the partition is located d = self.disks[p['disk']] d['numpart'] += 1 + + # alignment in sectors + align_sectors = None + # if first partition then we need to skip the first sector + # where the MBR is located, if the alignment isn't set + # See: https://wiki.linaro.org/WorkingGroups/Kernel/Projects/FlashCardSurvey + if d['numpart'] == 1: + if p['align'] and p['align'] > 0: + align_sectors = p['align'] * 1024 / self.sector_size + else: + align_sectors = MBR_SECTOR_LEN + elif p['align']: + # If not first partition and we do have alignment set we need + # to align the partition. + # FIXME: This leaves a empty spaces to the disk. To fill the + # gaps we could enlargea the previous partition? + + # Calc how much the alignment is off. + align_sectors = d['offset'] % (p['align'] * 1024 / self.sector_size) + # We need to move forward to the next alignment point + align_sectors = (p['align'] * 1024 / self.sector_size) - align_sectors + + if align_sectors: + if p['align'] and p['align'] > 0: + msger.debug("Realignment for %s%s with %s sectors, original" + " offset %s, target alignment is %sK." % + (p['disk'], d['numpart'], align_sectors, + d['offset'], p['align'])) + # p['size'] already converted in secctors + if p['size'] <= align_sectors: + raise MountError("Partition for %s is too small to handle " + "the alignment change." % p['mountpoint']) + + # increase the offset so we actually start the partition on right alignment + d['offset'] += align_sectors + if d['numpart'] > 3: # Increase allocation of extended partition to hold this partition d['extended'] += p['size'] @@ -151,7 +188,10 @@ class PartitionedMount(Mount): p['start'] = d['offset'] d['offset'] += p['size'] d['partitions'].append(n) - msger.debug("Assigned %s to %s%d at %d at size %d" % (p['mountpoint'], p['disk'], p['num'], p['start'], p['size'])) + msger.debug("Assigned %s to %s%d at Sector %d with size %d sectors " + "/ %d bytes." % (p['mountpoint'], p['disk'], p['num'], + p['start'], p['size'], + p['size'] * self.sector_size)) if self.skipformat: msger.debug("Skipping disk format, because skipformat flag is set.") -- 2.7.4