diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
index 3197914..5f8f0c7 100644
--- a/pyanaconda/constants.py
+++ b/pyanaconda/constants.py
@@ -31,25 +31,6 @@ DISPATCH_FORWARD = 1
 DISPATCH_DEFAULT = None
 DISPATCH_WAITING = 2
 
-# different types of partition requests
-# REQUEST_PREEXIST is a placeholder for a pre-existing partition on the system
-# REQUEST_NEW is a request for a partition which will be automatically
-#              created based on various constraints on size, drive, etc
-# REQUEST_RAID is a request for a raid device
-# REQUEST_PROTECTED is a preexisting partition which can't change
-#              (harddrive install, harddrive with the isos on it)
-#
-REQUEST_PREEXIST = 1
-REQUEST_NEW = 2
-REQUEST_RAID = 4
-REQUEST_PROTECTED = 8
-REQUEST_VG = 16 # volume group
-REQUEST_LV = 32 # logical volume
-
-# XXX this is made up and used by the size spinner; should just be set with
-# a callback
-MAX_PART_SIZE = 1024*1024*1024
-
 # install key related constants
 SKIP_KEY = -50
 
@@ -64,8 +45,6 @@ productArch = product.productArch
 bugzillaUrl = product.bugUrl
 isFinal = product.isFinal
 
-lvmErrorOutput = "/tmp/lvmout"
-
 exceptionText = _("An unhandled exception has occurred.  This "
                   "is most likely a bug.  Please save a copy of "
                   "the detailed exception and file a bug report")
diff --git a/pyanaconda/errors.py b/pyanaconda/errors.py
index 0bb6237..8b13789 100644
--- a/pyanaconda/errors.py
+++ b/pyanaconda/errors.py
@@ -1,162 +1 @@
-#
-# errors.py: exception classes used throughout anaconda
-#
-# Copyright (C) 2002, 2007, 2008  Red Hat, Inc.  All rights reserved.
-#
-# 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 2 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/>.
-#
-# Author(s): Peter Jones <pjones@redhat.com>
-#            Chris Lumens <clumens@redhat.com>
-#            Matt Wilson <msw@redhat.com>
-#            Jeremy Katz <katzj@redhat.com>
-#            Mike Fulbright <msf@redhat.com>
-#
 
-import string
-import os
-from constants import lvmErrorOutput
-
-# Exceptions for use in lvm operations.
-
-class LvmError(Exception):
-    """An error occurred with lvm."""
-    def __init__(self, command, name=None):
-        self.command = command
-        self.name = name
-        self.log = self.getLvmOutput()
-
-    def getLvmOutput(self):
-        if not os.access(lvmErrorOutput, os.R_OK):
-            return ""
-        f = open(lvmErrorOutput, "r")
-        lines = reduce(lambda x,y: x + [string.strip(y),], f.readlines(), [])
-        lines = string.join(reduce(lambda x,y: x + ["   %s" % (y,)], \
-                                    lines, []), "\n")
-        return lines
-
-    def __str__(self):
-        s = ""
-        if not self.name is None:
-            s = " for device %s" % (self.name,)
-        return "%s failed%s\nLog:\n%s" % (self.command, s, self.log)
-
-class LVCreateError(LvmError):
-    def __init__(self, vgname, lvname, size):
-        self.vgname = vgname
-        self.lvname = lvname
-        self.size = size
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "lvcreate of %d Megabyte lv \"%s\" on vg \"%s\" failed\n" \
-               "Log:\n%s" % ( \
-            self.size, self.lvname, self.vgname, self.log)
-
-class LVRemoveError(LvmError):
-    def __init__(self, vgname, lvname):
-        self.vgname = vgname
-        self.lvname = lvname
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "lvremove of lv \"%s\" from vg \"%s\" failed\nLog:\n%s" % ( \
-            self.lvname, self.vgname, self.log)
-
-class LVResizeError(LvmError):
-    def __init__(self, vgname, lvname):
-        self.vgname = vgname
-        self.lvname = lvname
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "lvresize of lv \"%s\" from vg \"%s\" failed\nLog:\n%s" % ( \
-            self.lvname, self.vgname, self.log)
-
-class VGCreateError(LvmError):
-    def __init__(self, vgname, PESize, nodes):
-        self.vgname = vgname
-        self.PESize = PESize
-        self.nodes = nodes
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        nodes = string.join(self.nodes, ' ')
-        return "vgcreate failed creating vg \"%s\" (PESize=%dkB) on PVs: %s\n" \
-               "Log:\n%s" % ( \
-            self.vgname, self.PESize, nodes, self.log)
-
-class VGRemoveError(LvmError):
-    def __init__(self, vgname):
-        self.vgname = vgname
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "vgremove of vg \"%s\" failed\nLog:\n%s" % ( \
-            self.vgname, self.log)
-
-class PVRemoveError(LvmError):
-    def __init__(self, pvname):
-        self.pvname = pvname
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "pvremove of pv \"%s\" failed\nLog:\n%s" % ( \
-            self.pvname, self.log)
-
-class PVCreateError(LvmError):
-    def __init__(self, pvname):
-        self.pvname = pvname
-        self.log = self.getLvmOutput()
-
-    def __str__(self):
-        return "pvcreate of pv \"%s\" failed\nLog:\n%s" % ( \
-            self.pvname, self.log)
-
-# Exceptions for use in partitioning.
-
-class PartitioningError(Exception):
-    """A critical error which must be resolved to continue the installation."""
-    def __init__(self, message=""):
-        self.message = str(message)
-
-    def __str__ (self):
-        return self.message
-
-class PartitioningWarning(Exception):
-    """A warning which may be ignored and still complete the installation."""
-    def __init__(self, message=""):
-        self.message = str(message)
-
-    def __str__ (self):
-        return self.message
-
-class LabelError(Exception):
-    """The device could not be labeled."""
-    def __init__(self, message=""):
-        self.message = str(message)
-
-    def __str__(self):
-        return self.message
-
-# Exceptions for use in package selection.
-
-class NoSuchGroup(Exception):
-    def __init__ (self, value):
-        self.value = value
-
-    def __str__ (self):
-        return self.value
-
-class DispatchError(RuntimeError):
-    pass
diff --git a/pyanaconda/installclass.py b/pyanaconda/installclass.py
index 0d784f2..90a2991 100644
--- a/pyanaconda/installclass.py
+++ b/pyanaconda/installclass.py
@@ -87,19 +87,19 @@ class BaseInstallClass(object):
 		 "sshd",
 		 "language",
 		 "keyboard",
-                 "filtertype",
-                 "filter",
+#                 "filtertype",
+#                 "filter",
                  "storageinit",
-                 "findrootparts",
-		 "betanag",
-                 "cleardiskssel",
+#                 "findrootparts",
+#		 "betanag",
+#                 "cleardiskssel",
                  "parttype",
                  "autopartitionexecute",
 		 "storagedone",
 		 "bootloader",
-		 "network",
-		 "timezone",
-		 "accounts",
+#		 "network",
+#		 "timezone",
+#		 "accounts",
                  "reposetup",
                  "basepkgsel",
 		 "tasksel",
diff --git a/pyanaconda/iw/partition_dialog_gui.py b/pyanaconda/iw/partition_dialog_gui.py
index f19d2ea..85270f3 100644
--- a/pyanaconda/iw/partition_dialog_gui.py
+++ b/pyanaconda/iw/partition_dialog_gui.py
@@ -35,6 +35,26 @@ from pyanaconda.partIntfHelpers import *
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
 
+def max_part_size(storage, request):
+    max_size = 0
+
+    if request.req_start_sector is not None:
+        max_len = request.req_end_sector - request.req_start_sector + 1
+        sector_size = request.req_disks[0].format.partedDevice.sectorSize
+        max_size = (max_len * sector_size) / (1024.0 * 1024.0)
+    else:
+        disks = request.req_disks
+        if not disks:
+            disks = storage.partitioned[:]
+
+        for disk in disks:
+            sector_size = disk.format.partedDevice.sectorSize
+            max_sectors = disk.format.partedDisk.maxPartitionLength
+            max_size = max(max_size,
+                           (max_sectors * sector_size)/(1024.0 * 1024.0))
+
+    return max_size
+
 class PartitionEditor:
     def sizespinchangedCB(self, widget, fillmaxszsb):
 	size = widget.get_value_as_int()
@@ -65,7 +85,8 @@ class PartitionEditor:
 				      label=_("Fill all space _up "
 					      "to (MB):"))
 	maxsizeAdj = gtk.Adjustment(value = 1, lower = 1,
-				    upper = MAX_PART_SIZE, step_incr = 1)
+				    upper=max_part_size(self.storage, request),
+                                    step_incr = 1)
 	fillmaxszsb = gtk.SpinButton(maxsizeAdj, digits = 0)
 	fillmaxszsb.set_property('numeric', True)
 	fillunlimrb = gtk.RadioButton(group=fixedrb,
@@ -87,9 +108,13 @@ class PartitionEditor:
 	    fixedrb.set_active(1)
 
 	sizeoptiontable.attach(fixedrb, 0, 1, 0, 1)
-	sizeoptiontable.attach(fillmaxszrb, 0, 1, 1, 2)
-	sizeoptiontable.attach(fillmaxszsb, 1, 2, 1, 2)
-	sizeoptiontable.attach(fillunlimrb, 0, 1, 2, 3)
+
+        sizeoptiontable.attach(fillmaxszrb, 0, 1, 1, 2)
+        sizeoptiontable.attach(fillmaxszsb, 1, 2, 1, 2)
+        sizeoptiontable.attach(fillunlimrb, 0, 1, 2, 3)
+
+        if request.req_start_sector is not None:
+            sizeoptiontable.set_sensitive(0)
 
 	frame.add(sizeoptiontable)
 
@@ -203,6 +228,8 @@ class PartitionEditor:
                                                         maxsize=maxsize,
                                                         primary=primary,
                                                         format=format,
+                                                        start=self.origrequest.req_start_sector,
+                                                        end=self.origrequest.req_end_sector,
                                                         parents=disks,
                                                         weight=weight)
                 else:
@@ -471,9 +498,14 @@ class PartitionEditor:
             if restrictfs and 'mdmember' in restrictfs:
                 # do not preselect all available drives for new raid partitions
                 preselectAll = False
+
+            disallowed = [self.anaconda.updateSrc]
+            if self.origrequest.req_start_sector is not None:
+                disallowed.extend([d for d in self.storage.partitioned
+                                    if d not in self.origrequest.req_disks])
             self.driveview = createAllowedDrivesList(self.storage.partitioned,
                                                      req_disk_names,
-                                                     disallowDrives=[self.anaconda.updateSrc],
+                                                     disallowDrives=disallowed,
                                                      preselectAll=preselectAll)
             lbl.set_mnemonic_widget(self.driveview)
             sw = gtk.ScrolledWindow()
@@ -508,7 +540,9 @@ class PartitionEditor:
             lbl = createAlignedLabel(_("_Size (MB):"))
             maintable.attach(lbl, 0, 1, row, row + 1)
             sizeAdj = gtk.Adjustment(value = 1, lower = 1,
-                                     upper = MAX_PART_SIZE, step_incr = 1)
+                                     upper = max_part_size(self.storage,
+                                                           self.origrequest),
+                                     step_incr = 1)
             self.sizespin = gtk.SpinButton(sizeAdj, digits = 0)
             self.sizespin.set_property('numeric', True)
 
@@ -551,7 +585,8 @@ class PartitionEditor:
                 self.primonlycheckbutton.set_active(1)
 
             # only show if we have something other than primary
-            if self.storage.extendedPartitionsSupported():
+            if self.storage.extendedPartitionsSupported() and \
+               not self.origrequest.req_start_sector:
                 maintable.attach(self.primonlycheckbutton, 0, 2, row, row+1)
                 row = row + 1
 
diff --git a/pyanaconda/iw/partition_gui.py b/pyanaconda/iw/partition_gui.py
index c62d0a6..c9962d5 100644
--- a/pyanaconda/iw/partition_gui.py
+++ b/pyanaconda/iw/partition_gui.py
@@ -49,6 +49,7 @@ from pyanaconda.partIntfHelpers import *
 from pyanaconda.constants import *
 from partition_ui_helpers_gui import *
 from pyanaconda.storage.partitioning import doPartitioning
+from pyanaconda.storage.partitioning import addPartitionWithStartSector
 from pyanaconda.storage.devicelibs import lvm
 from pyanaconda.storage.devices import devicePathToName, PartitionDevice
 from pyanaconda.storage.devices import deviceNameToDiskByPath
@@ -414,7 +415,7 @@ class DiskStripeGraph(StripeGraph):
                 partName = devicePathToName(part.getDeviceNodeName())
                 o_part = self.storage.devicetree.getDeviceByName(partName)
             else:
-                o_part = None
+                o_part = (part.geometry.start, part.geometry.end)
 
             slice = Slice(stripe, partstr, stype, xoffset, xlength,
                     dcCB = self.dcCB, cCB = self.cCB, sel_col = sel_col,
@@ -1109,8 +1110,8 @@ class PartitionWindow(InstallWindow):
             return
 
         # The selected slice is a free slice if the object contained in it is
-        # None.
-        if sel_slice.obj != None:
+        # an int.
+        if not isinstance(sel_slice.obj, tuple):
             # This is not a free slice, we should call treeActivateCB
             return self.treeActivateCB()
         else:
@@ -1125,7 +1126,17 @@ class PartitionWindow(InstallWindow):
             stripe_dev = disp_stripe.obj
             if stripe_dev.partitioned:
                 tempformat = self.storage.defaultFSType
-                device = self.storage.newPartition(fmt_type=tempformat)
+
+                # Edit the partition here, but no growing.
+                # Add it directly instead of calling doPartitioning.
+                size = (stripe_dev.partedDevice.sectorSize * (sel_slice.obj[1] - sel_slice.obj[0] + 1)) / (1024.0 * 1024.0)
+                device = self.storage.newPartition(fmt_type=tempformat,
+                                                   size=size,
+                                                   parents=[stripe_dev])
+
+                device.req_start_sector = sel_slice.obj[0]
+                device.req_end_sector = sel_slice.obj[1]
+
                 self.editPartition(device, isNew = True)
 
             elif isinstance(stripe_dev, storage.LVMVolumeGroupDevice):
@@ -1641,10 +1652,19 @@ class PartitionWindow(InstallWindow):
             orig_device = copy.copy(device)
             actions = parteditor.run()
 
+            new_device = device
             for action in actions:
                 # XXX we should handle exceptions here
                 self.anaconda.storage.devicetree.registerAction(action)
 
+                # look up the new device from the create action
+                if device.req_start_sector and action.isCreate and action.isDevice and action.device.type == "partition":
+                    new_device = action.device
+
+            if device.req_start_sector and actions:
+                # add this partition now
+                addPartitionWithStartSector(new_device)
+
             if self.refresh(justRedraw=not actions):
                 # autopart failed -- cancel the actions and try to get
                 # back to previous state
diff --git a/pyanaconda/iw/partition_ui_helpers_gui.py b/pyanaconda/iw/partition_ui_helpers_gui.py
index 5a63d2c..4717cdf 100644
--- a/pyanaconda/iw/partition_ui_helpers_gui.py
+++ b/pyanaconda/iw/partition_ui_helpers_gui.py
@@ -158,7 +158,7 @@ def createAllowedDrivesStore(disks, reqdrives, drivelist, disallowDrives,
                               disk.description),
                              selected)
 
-    if len(disks) < 2:
+    if len(disks) - len(disallowDrives) < 2:
         drivelist.set_sensitive(False)
     else:
         drivelist.set_sensitive(True)
diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py
index a52e464..868644d 100644
--- a/pyanaconda/storage/devices.py
+++ b/pyanaconda/storage/devices.py
@@ -1085,6 +1085,7 @@ class PartitionDevice(StorageDevice):
                  size=None, grow=False, maxsize=None,
                  major=None, minor=None, bootable=None,
                  sysfsPath='', parents=None, exists=None,
+                 start=None, end=None,
                  partType=None, primary=False, weight=0):
         """ Create a PartitionDevice instance.
 
@@ -1123,6 +1124,8 @@ class PartitionDevice(StorageDevice):
         self.req_base_size = 0
         self.req_max_size = 0
         self.req_base_weight = 0
+        self.req_start_sector = None
+        self.req_end_sector = None
 
         self._bootable = False
 
@@ -1188,6 +1191,9 @@ class PartitionDevice(StorageDevice):
 
             self.req_base_weight = weight
 
+            self.req_start_sector = start
+            self.req_end_sector = end
+
     def __repr__(self):
         s = StorageDevice.__repr__(self)
         s += ("  grow = %(grow)s  max size = %(maxsize)s  bootable = %(bootable)s\n"
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py
index 339edec..7e4403d 100644
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -798,6 +798,53 @@ def removeNewPartitions(disks, partitions):
             log.debug("removing empty extended partition from %s" % disk.name)
             disk.format.partedDisk.removePartition(extended)
 
+def addPartitionWithStartSector(request):
+    """ Add a partition to disklabel given a starting sector.
+
+        If the partition has a req_start_sector it should also have a single
+        disk in req_disks and it should not be growable.
+
+        Return the partition we just added.
+    """
+    disk = request.req_disks[0]
+    disklabel = disk.format
+
+    if request.partedPartition:
+        if request.partedPartition in disklabel.partitions:
+            disklabel.removePartition(request.partedPartition)
+
+        request.partedPartition = None
+
+    # figure out the free region the geometry is in
+    free_list = getFreeRegions([disk])
+    free = None
+    for f in free_list:
+        if f.containsSector(request.req_start_sector):
+            free = f
+            break
+
+    if not free:
+        raise PartitioningError("Failed to identify free region on disk %s"
+                                "containing sector %d"
+                                % (disk.name, request.req_start_sector))
+
+    # figure out the partition type based on that and whatever else
+    # FIXME: for now, this is not aware of extended/logical partitions
+    if disklabel.partedDisk.primaryPartitionCount >= disklabel.partedDisk.maxPrimaryPartitionCount:
+        raise PartitioningError("I don't know or care about logical/extended partitions")
+
+    partition = addPartition(disklabel, free, parted.PARTITION_NORMAL,
+                             request.req_size)
+
+    # this one sets the name
+    request.partedPartition = partition
+    request.disk = disk
+
+    # parted modifies the partition in the process of adding it to
+    # the disk, so we need to grab the latest version...
+    partition = disklabel.partedDisk.getPartitionByPath(request.path)
+    request.partedPartition = partition
+
 def addPartition(disklabel, free, part_type, size):
     """ Return new partition after adding it to the specified disk.
 
@@ -953,6 +1000,7 @@ def doPartitioning(storage, bootloader=None):
 
     partitions = storage.partitions[:]
     for part in storage.partitions:
+        log.debug("partition %s ; start = %s" % (part.name, part.req_start_sector))
         part.req_bootable = False
 
         if part.exists or \
@@ -962,6 +1010,11 @@ def doPartitioning(storage, bootloader=None):
             partitions.remove(part)
             continue
 
+        if part.req_start_sector is not None:
+            # requests with a start sector have already been allocated
+            partitions.remove(part)
+            continue
+
         if not part.exists:
             # start over with flexible-size requests
             part.req_size = part.req_base_size
diff --git a/pyanaconda/yuminstall.py b/pyanaconda/yuminstall.py
index fdf17c6..1be15f4 100644
--- a/pyanaconda/yuminstall.py
+++ b/pyanaconda/yuminstall.py
@@ -18,7 +18,6 @@
 #
 
 from flags import flags
-from errors import *
 
 import ConfigParser
 import sys
