From 7f0358bd53916b4a8e3d59ff0e1f7488b7ca42d8 Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Wed, 18 Jul 2012 17:29:15 -0500
Subject: [PATCH 04/16] Add support for creating btrfs in the custom storage
 spoke.

---
 pyanaconda/ui/gui/spokes/custom.py |   85 ++++++++++++++++++++++++++++++++++--
 1 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 5932659..f66842f 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -51,6 +51,9 @@ from pyanaconda.ui.gui.categories.storage import StorageCategory
 
 from gi.repository import Gtk
 
+import logging
+log = logging.getLogger("anaconda")
+
 __all__ = ["CustomPartitioningSpoke"]
 
 new_install_name = _("New %s %s Installation") % (productName, productVersion)
@@ -455,25 +458,99 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
              mountpoint in self.storage.mountpoints.keys():
             return
 
-        if not size:
+        log.info("UI: create new %s %s" % (size, mountpoint))
+
+        # nothing in storage uses Size, so convert to float now
+        if size:
+            size = float(size.convertTo(spec="mb"))
+        else:
             # no size specified, so use the default size
             size = None
 
-        if self.data.autopart.type == AUTOPART_TYPE_PLAIN:
+        # swap can't be on btrfs.
+        # /boot* must be on partition or md
+        if (self.data.autopart.type == AUTOPART_TYPE_PLAIN or
+            (self.data.autopart.type == AUTOPART_TYPE_BTRFS and
+             fstype == "swap") or
+            (mountpoint and mountpoint.startswith("/boot"))):
+            log.info("UI: using a partition")
             # create a partition for this new filesystem
-            size_mb = float(size.convertTo(spec="mb"))
-            device = self.storage.newPartition(size=size_mb,
+            device = self.storage.newPartition(size=size,
                                                fmt_type=fstype,
                                                mountpoint=mountpoint)
             self.storage.createDevice(device)
             try:
                 doPartitioning(self.storage)
             except StorageError as e:
+                log.error("UI: failed to allocate new partition: %s" % e)
                 actions = self.storage.devicetree.findActions(device=device)
                 for a in reversed(actions):
                     self.storage.devicetree.cancelAction(a)
             else:
                 self._do_refresh()
+                self._updateSpaceDisplay()
+        elif self.data.autopart.type == AUTOPART_TYPE_BTRFS:
+            log.info("UI: using a btrfs subvolume")
+            # see if we've already created a btrfs volume
+            container = None
+            for c in self.storage.btrfsVolumes:
+                if not c.exists:
+                    container = c
+                    break
+
+            # XXX for now we are ignoring raid
+
+            # if we have a container, we need to grow it
+            # figure out this device's space needs based on it and the container
+            if container:
+                log.debug("UI: found a btrfs volume with %d subvolumes" % len(container.subvolumes))
+                new_size = container.size + size
+                # this is always rounding down
+                member_size = int(new_size / len(container.parents))
+                log.debug("setting member device size to %d" % member_size)
+                for member in container.parents:
+                    # btrfs members can only be partitions
+                    # FIXME: grab the slave if the member is a DMCryptDevice
+                    member.req_base_size = member_size
+            else:
+                log.debug("UI: going to create a btrfs volume")
+                # if we don't have a container we need to create member devices
+                # and then create the container itself
+                # figure out this devices's space needs
+                usable_disks = set(self.storage.disks) & set(self.storage.partitioned)
+                member_size = size / len(usable_disks)
+                members = []
+                for disk in usable_disks:
+                    member = self.storage.newPartition(parents=[disk],
+                                                       size=member_size,
+                                                       fmt_type="btrfs")
+                    self.storage.createDevice(member)
+                    members.append(member)
+
+            try:
+                doPartitioning(self.storage)
+            except StorageError as e:
+                log.error("UI: failed to allocate new members: %s" % e)
+                for device in members:
+                    actions = self.storage.devicetree.findActions(device=device)
+                    for a in reversed(actions):
+                        self.storage.devicetree.cancelAction(a)
+                # FIXME: revert container to its original state
+                return
+
+            if not container:
+                log.debug("UI: creating new btrfs volume")
+                container = self.storage.newBTRFS(parents=members)
+                self.storage.createDevice(container)
+
+            # add the new device to the container
+            log.debug("UI: creating new btrfs subvolume")
+            device = self.storage.newBTRFS(subvol=True,
+                                           parents=[container],
+                                           mountpoint=mountpoint)
+            self.storage.createDevice(device)
+            self._do_refresh()
+            self._updateSpaceDisplay()
 
     def _destroy_device(self, device):
         # if this device has parents with no other children, remove them too
-- 
1.7.7.6

