diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index f6168c5..a4baf11 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -932,6 +932,7 @@ class Storage(object):
         if clearPartType is None:
             clearPartType = self.config.clearPartType
 
+        log.debug("getFreeSpace: disks=%s  clearPartType=%s"% ([d.name for d in disks], clearPartType))
         free = {}
         for disk in disks:
             should_clear = self.shouldClear(disk, clearPartType=clearPartType,
@@ -1874,6 +1875,9 @@ class Storage(object):
         disks = kwargs.get("disks")
         encrypted = kwargs.get("encrypted", self.data.autopart.encrypted)
 
+        # XXX temporary?
+        size = float(size.convertTo(spec="mb"))
+
         # md, btrfs
         raid_level = kwargs.get("level")
 
@@ -2926,11 +2930,11 @@ def findExistingInstallations(devicetree):
             name = "%s Linux %s for %s" % (product, version, arch)
 
         (mounts, swaps) = parseFSTab(devicetree, chroot=ROOT_PATH)
+        device.teardown()
         if not mounts and not swaps:
             # empty /etc/fstab. weird, but I've seen it happen.
             continue
         roots.append(Root(mounts=mounts, swaps=swaps, name=name))
-        device.teardown()
 
     return roots
 
diff --git a/pyanaconda/storage/size.py b/pyanaconda/storage/size.py
index eb3e2e4..d8e712e 100644
--- a/pyanaconda/storage/size.py
+++ b/pyanaconda/storage/size.py
@@ -131,7 +131,7 @@ class Size(Decimal):
             if type(bytes).__name__ in ["int", "long", "float", 'Decimal'] and bytes >= 0:
                 self = Decimal.__new__(cls, value=bytes)
             else:
-                raise SizeNotPositiveError("bytes= param must be >=0")
+                raise SizeNotPositiveError("bytes= param must be >=0: %s" % bytes)
         elif spec:
             self = Decimal.__new__(cls, value=_parseSpec(spec))
         else:
@@ -139,27 +139,29 @@ class Size(Decimal):
 
         return self
 
-    def __str__(self):
+    def __str__(self, context=None):
         return self.humanReadable()
 
     def __repr__(self):
         return "Size('%s')" % self
 
-    def __add__(self, other):
-        return Size(bytes=Decimal.__add__(self, other))
+    def __add__(self, other, context=None):
+        return Size(bytes=Decimal.__add__(self, other, context=context))
 
     # needed to make sum() work with Size arguments
-    def __radd__(self, other):
-        return Size(bytes=Decimal.__radd__(self, other))
+    def __radd__(self, other, context=None):
+        return Size(bytes=Decimal.__radd__(self, other, context=context))
 
-    def __sub__(self, other):
-        return Size(bytes=Decimal.__sub__(self, other))
+    def __sub__(self, other, context=None):
+        # subtraction is implemented using __add__ and negation, so we'll
+        # be getting passed a Size
+        return Decimal.__sub__(self, other, context=context)
 
-    def __mul__(self, other):
-        return Size(bytes=Decimal.__mul__(self, other))
+    def __mul__(self, other, context=None):
+        return Size(bytes=Decimal.__mul__(self, other, context=context))
 
-    def __div__(self, other):
-        return Size(bytes=Decimal.__div__(self, other))
+    def __div__(self, other, context=None):
+        return Size(bytes=Decimal.__div__(self, other, context=context))
 
     def _trimEnd(self, val):
         """ Internal method to trim trailing zeros. """
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 2bddb9d..3eb5098 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -36,6 +36,7 @@ from pykickstart.constants import *
 
 from pyanaconda.product import productName, productVersion
 from pyanaconda.storage.formats import device_formats
+from pyanaconda.storage.formats import getFormat
 from pyanaconda.storage.size import Size
 from pyanaconda.storage import Root
 from pyanaconda.storage.partitioning import doPartitioning
@@ -125,7 +126,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
 
         self._current_selector = None
         self._when_create_text = ""
-        self.ui_devices = []
+        self._ui_devices = []
         self._deleted_devices = []
         self._free_space = Size(bytes=0)
 
@@ -136,10 +137,11 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
                 # created here, destroyed here -> NOOP
                 continue
 
+            print "removing device %s" % removed.name
             device = self.storage.devicetree.getDeviceByName(removed.name)
             self.storage.destroyDevice(device)
 
-        for ui_device in self.ui_devices:
+        for ui_device in self._ui_devices:
             if ui_device.device_id is None:
                 # we're creating a device
 
@@ -149,6 +151,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
 
                 self.storage.newUIDevice(ui_device.create_type,
                                          ui_device.size,
+                                         mountpoint=ui_device.mountpoint,
+                                         fstype=ui_device.fstype,
                                          encrypted=ui_device.encrypted,
                                          level=ui_device.raid_level,
                                          disks=self.storage.disks)
@@ -246,10 +250,12 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
         totalFree = Size(bytes=0)
 
         freeDisks = self.storage.getFreeSpace(disks=self._clearpartDevices())
-        for tup in freeDisks.values():
-            for chunk in tup:
-                totalFree += chunk
+        for (disk_free, fs_free) in freeDisks.values():
+            # only show actual free space as free -- don't include space that
+            # could be gained by shrinking filesystems
+            totalFree += disk_free
 
+        print "setting free space to %s" % totalFree
         self._free_space = totalFree
 
     def _currentTotalSpace(self):
@@ -281,7 +287,8 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
 
     def refresh(self):
         NormalSpoke.refresh(self)
-        self.ui_devices = get_ui_devices(self.storage)
+        self._deleted_devices = []
+        self._ui_devices = get_ui_devices(self.storage)
         self._do_refresh()
 
         # update our free space number based on Storage
@@ -301,33 +308,38 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
 
         # set up a dict with name keys for the ui device list
         ui_device_dict = {}
-        for device in self.ui_devices:
+        for device in self._ui_devices:
             ui_device_dict[device.name] = device
 
+        import pprint
+        pprint.pprint("%s" % ui_device_dict)
+
         # We can only have one page expanded at a time.
         did_expand = False
 
         unused = [ui_device_dict[d.name] for d in self._unusedDevices()
                     if d.name in ui_device_dict and
                        ui_device_dict[d.name].device_id is not None]
-        new_devices = [d for d in self.ui_devices if d.device_id is None]
+        new_devices = [d for d in self._ui_devices if not d.exists]
+
+        pprint.pprint("unused: %s" % unused)
+        pprint.pprint("new_devices: %s" % new_devices)
 
-        roots = self.storage.roots[:]
         ui_roots = []
-        for root in roots:
+        for root in self.storage.roots:
             name = root.name
             swaps = []
             mounts = {}
             for (mountpoint, device) in root.mounts.items():
                 ui_device = ui_device_dict.get(device.name)
-                if not ui_device or ui_device.id is None:
+                if not ui_device or not ui_device.exists:
                     continue
 
                 mounts[mountpoint] = ui_device
 
             for device in root.swaps:
                 ui_device = ui_device_dict.get(device.name)
-                if not ui_device or ui_device.id is None:
+                if not ui_device or not ui_device.exists:
                     continue
 
                 swaps.append(ui_device)
@@ -373,7 +385,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             page.show_all()
             self._accordion.addPage(page, cb=self.on_page_clicked)
 
-            if not did_expand and getattr(self._current_selector, "_root", None) and root.name == self._current_selector._root.name:
+            if not did_expand:
                 did_expand = True
                 self._accordion.expandPage(root.name)
 
@@ -390,7 +402,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             page.show_all()
             self._accordion.addPage(page, cb=self.on_page_clicked)
 
-            if not did_expand and self._current_selector and self._current_selector._root is None:
+            if not did_expand:
                 did_expand = True
                 self._accordion.expandPage(page.pageTitle)
 
@@ -450,8 +462,9 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
         else:
             labelEntry.set_tooltip_text(_("This file system does not support labels."))
 
-        sizeSpinner.set_range(device.min_size, device.max_size)
-        sizeSpinner.set_value(device.size)
+        sizeSpinner.set_range(device.min_size.convertTo(spec="mb"),
+                              device.max_size.convertTo(spec="mb"))
+        sizeSpinner.set_value(device.size.convertTo(spec="mb"))
         sizeSpinner.set_sensitive(device.resizable)
 
         if sizeSpinner.get_sensitive():
@@ -505,7 +518,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
         # create a device of the default type, using any disks, with an
         # appropriate fstype and mountpoint
         mountpoint = dialog.mountpoint
-        size = dialog.size
+        size = min(dialog.size, self._free_space)
         fstype = self.storage.defaultFSType
         if mountpoint.lower() == "swap":
             fstype = "swap"
@@ -532,20 +545,24 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             device_class = UIPartition
 
         device = device_class(mountpoint=mountpoint, size=size, fstype=fstype)
-        self.ui_devices.append(device)
-        self._free_space -= Size(spec="%f MB" % device.disk_space)
+        self._ui_devices.append(device)
+        self._free_space -= device.disk_space
         self._do_refresh()
+        self._updateSpaceDisplay()
 
     def _destroy_device(self, device):
-        self.ui_devices.remove(device)
+        self._ui_devices.remove(device)
         self._deleted_devices.append(device)
 
-        if device.type == "Partition":
-            self._free_space += Size(spec="%f MB" % device.size)
+        # XXX This could be tricky. We don't want to count an LV's size twice
+        #     by counting it for the LV and again for the VG.
+        if not device.exists or device.type == "Partition":
+            print "destroy_device: space: %s  size: %s  free: %s" % (device.disk_space, device.size, self._free_space)
+            self._free_space += device.disk_space
 
         # if this device has parents with no other children, remove them too
         for parent in device.parents:
-            all_parents = [p for d in self.ui_devices for p in d.parents]
+            all_parents = [p for d in self._ui_devices for p in d.parents]
             if parent not in all_parents and parent.type != "Disk":
                 self._destroy_device(parent)
 
@@ -554,8 +571,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
             pass    # unused device
         elif device in root.swaps:
             root.swaps.remove(device)
-        elif hasattr(device.format, "mountpoint") and \
-             device in root.mounts.values():
+        elif device.mountpoint and device in root.mounts.values():
             mountpoints = [m for (m,d) in root.mounts.items() if d == device]
             for mountpoint in mountpoints:
                 root.mounts.pop(mountpoint)
@@ -586,7 +602,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
                 # schedule actions to delete the thing.
                 dialog = ConfirmDeleteDialog(self.data)
                 with enlightbox(self.window, dialog.window):
-                    dialog.refresh(getattr(device.format, "mountpoint", None), device.name)
+                    dialog.refresh(device.mountpoint, device.name)
                     rc = dialog.run()
 
                     if rc == 0:
@@ -705,7 +721,7 @@ class UIDevice(object):
 
     def __init__(self, size=None, mountpoint=None, fstype=None, name=None,
                  raid_level=None, parents=None, exists=False, encrypted=False,
-                 resizable=False, min_size=None, max_size=None,
+                 label=None, resizable=False, min_size=None, max_size=None,
                  device_id=None):
         self.size = size
         self.mountpoint = mountpoint
@@ -715,6 +731,7 @@ class UIDevice(object):
         self.parents = parents or []
         self.exists = exists
         self.encrypted = encrypted
+        self.label = label
 
         self.resizable = resizable
         self.min_size = min_size
@@ -722,6 +739,12 @@ class UIDevice(object):
 
         self.device_id = device_id
 
+        if self.min_size is None:
+            self.min_size = self.size
+
+        if self.max_size is None:
+            self.max_size = self.size
+
     @property
     def disk_space(self):
         space = self.size
@@ -852,17 +875,18 @@ def get_ui_devices(storage):
                     max_size = device.maxSize
 
             ui_device = ui_class(name=device.name,
-                                 size=device.size,
+                                 size=Size(spec="%f mb" % device.size),
                                  fstype=device.format.type,
                                  mountpoint=getattr(device.format,
                                                     "mountpoint", None),
                                  raid_level=raid_level,
                                  encrypted=encrypted,
+                                 label=getattr(device.format, "label", None),
                                  parents=parents,
                                  exists=exists,
                                  resizable=resizable,
-                                 min_size=min_size,
-                                 max_size=max_size,
+                                 min_size=Size(spec="%f mb" % min_size),
+                                 max_size=Size(spec="%f mb" % max_size),
                                  device_id=device.id)
             ui_devices.append(ui_device)
 
diff --git a/pyanaconda/ui/gui/spokes/lib/accordion.py b/pyanaconda/ui/gui/spokes/lib/accordion.py
index c2da71e..09b87e9 100644
--- a/pyanaconda/ui/gui/spokes/lib/accordion.py
+++ b/pyanaconda/ui/gui/spokes/lib/accordion.py
@@ -23,7 +23,6 @@ import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
 
 from pyanaconda.product import productName, productVersion
-from pyanaconda.storage.size import Size
 
 from gi.repository.AnacondaWidgets import MountpointSelector
 from gi.repository import Gtk
@@ -137,7 +136,7 @@ class Page(Gtk.Box):
 
     def addDevice(self, name, size, mountpoint, cb):
         selector = MountpointSelector()
-        selector = MountpointSelector(name, str(Size(spec="%s MB" % size)), mountpoint or "")
+        selector = MountpointSelector(name, str(size).upper(), mountpoint or "")
         selector.connect("button-press-event", self._onSelectorClicked, cb)
         selector.connect("key-release-event", self._onSelectorClicked, cb)
         selector.connect("focus-in-event", self._onSelectorClicked, cb)
@@ -182,7 +181,7 @@ class UnknownPage(Page):
 
     def addDevice(self, name, size, mountpoint, cb):
         selector = MountpointSelector()
-        selector = MountpointSelector(name, str(Size(spec="%s MB" % size)), mountpoint or "")
+        selector = MountpointSelector(name, str(size).upper(), mountpoint or "")
         selector.connect("button-press-event", self._onSelectorClicked, cb)
         selector.connect("key-release-event", self._onSelectorClicked, cb)
         selector.connect("focus-in-event", self._onSelectorClicked, cb)
