This is just various things that ended up in my working tree around another set that isn't ready yet.
--- pyanaconda/storage/deviceaction.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/pyanaconda/storage/deviceaction.py b/pyanaconda/storage/deviceaction.py index b16573a..617d8b2 100644 --- a/pyanaconda/storage/deviceaction.py +++ b/pyanaconda/storage/deviceaction.py @@ -288,7 +288,10 @@ class ActionDestroyDevice(DeviceAction): # Make sure libparted does not keep cached info for this device # and returns it when we create a new device with the same name if self.device.partedDevice: - self.device.partedDevice.removeFromCache() + try: + self.device.partedDevice.removeFromCache() + except Exception: + pass
def requires(self, action): """ Return True if self requires action.
Some of the highlights:
We weren't setting self.originalFormat correctly when implicitly setting the btrfs format.
Also, we didn't have any code to discern subvolumes when parsing /etc/fstab.
We were passing volume id as volume path/name when populating the device tree.
Lastly, we were clobbering the subvol= mount option when mounting a btrfs subvolume to check it for existing roots. --- pyanaconda/storage/__init__.py | 12 +++++++----- pyanaconda/storage/devices.py | 35 ++++++++++++++++++++++++----------- pyanaconda/storage/devicetree.py | 32 +++++++++++++++++++++++++++++--- pyanaconda/storage/formats/fs.py | 4 ++++ 4 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index 4efd4a9..1ad5b97 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -2683,8 +2683,9 @@ def findExistingInstallations(devicetree): log.warning("setup of %s failed: %s" % (device.name, e)) continue
+ options = device.format.options + ",ro" try: - device.format.mount(options="ro", mountpoint=ROOT_PATH) + device.format.mount(options=options, mountpoint=ROOT_PATH) except Exception as e: log.warning("mount of %s as %s failed: %s" % (device.name, device.format.type, @@ -2766,17 +2767,18 @@ def parseFSTab(devicetree, chroot=None): for line in f.readlines(): # strip off comments (line, pound, comment) = line.partition("#") - fields = line.split(None, 3) + fields = line.split(None, 4)
- if len(fields) < 4: + if len(fields) < 5: continue
- (devspec, mountpoint, fstype, rest) = fields + (devspec, mountpoint, fstype, options, rest) = fields
# find device in the tree device = devicetree.resolveDevice(devspec, cryptTab=cryptTab, - blkidTab=blkidTab) + blkidTab=blkidTab, + options=options)
if device is None: continue diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py index 6b979e8..8c2713b 100644 --- a/pyanaconda/storage/devices.py +++ b/pyanaconda/storage/devices.py @@ -3943,19 +3943,31 @@ class BTRFSDevice(StorageDevice): def _temp_dir_prefix(self): return "btrfs-tmp.%s" % self.id
- def _do_temp_mount(self): + def _do_temp_mount(self, orig=False): if self.format.status or not self.exists: return
tmpdir = tempfile.mkdtemp(prefix=self._temp_dir_prefix) - self.format.mount(mountpoint=tmpdir) + if orig: + fmt = self.originalFormat + else: + fmt = self.format + + fmt.mount(mountpoint=tmpdir)
def _undo_temp_mount(self): - if self.format.status: - mountpoint = self.format._mountpoint - if os.path.basename(mountpoint).startswith(self._temp_dir_prefix): - self.format.unmount() - os.rmdir(mountpoint) + if getattr(self.format, "_mountpoint", None): + fmt = self.format + elif getattr(self.originalFormat, "_mountpoint", None): + fmt = self.originalFormat + else: + return + + mountpoint = fmt._mountpoint + + if os.path.basename(mountpoint).startswith(self._temp_dir_prefix): + fmt.unmount() + os.rmdir(mountpoint)
@property def path(self): @@ -3990,6 +4002,7 @@ class BTRFSVolumeDevice(BTRFSDevice): label=label, volUUID=self.uuid, device=self.path) + self.originalFormat = self.format
label = getattr(self.format, "label", None) if label: @@ -4058,7 +4071,7 @@ class BTRFSVolumeDevice(BTRFSDevice): subvols = [] self.setup(orig=True) try: - self._do_temp_mount() + self._do_temp_mount(orig=True) except FSError as e: log.debug("btrfs temp mount failed: %s" % e) return subvols @@ -4127,10 +4140,10 @@ class BTRFSSubVolumeDevice(BTRFSDevice):
def _destroy(self): log_method_call(self, self.name, status=self.status) - self.volume._do_temp_mount() - mountpoint = self.volume.format._mountpoint + self.volume._do_temp_mount(orig=True) + mountpoint = self.volume.originalFormat._mountpoint if not mountpoint: raise RuntimeError("btrfs subvol destroy requires mounted volume") btrfs.delete_subvolume(mountpoint, self.name) - self.volume._removeSubVolume() + self.volume._removeSubVolume(self.name) self.volume._undo_temp_mount() diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py index ae69be2..cd45cf6 100644 --- a/pyanaconda/storage/devicetree.py +++ b/pyanaconda/storage/devicetree.py @@ -1529,11 +1529,12 @@ class DeviceTree(object): if vol_path in [sv.name for sv in btrfs_dev.subvolumes]: continue fmt = getFormat("btrfs", device=btrfs_dev.path, exists=True, - mountopts="subvol=%d" % vol_id) + mountopts="subvol=%s" % vol_path) subvol = BTRFSSubVolumeDevice(vol_path, vol_id=vol_id, format=fmt, - parents=[btrfs_dev]) + parents=[btrfs_dev], + exists=True) self._addDevice(subvol)
def handleUdevDeviceFormat(self, info, device): @@ -2148,7 +2149,7 @@ class DeviceTree(object): """ Return a list of a device's children. """ return [c for c in self._devices if device in c.parents]
- def resolveDevice(self, devspec, blkidTab=None, cryptTab=None): + def resolveDevice(self, devspec, blkidTab=None, cryptTab=None, options=None): # find device in the tree device = None if devspec.startswith("UUID="): @@ -2232,6 +2233,31 @@ class DeviceTree(object): lv = "%s-%s" % (vg_name, lv_name) device = self.getDeviceByName(lv)
+ def get_opt_val(opt_name, options): + for opt in options.split(","): + if "=" not in opt: + continue + + name, val = opt.split("=") + if name == opt_name: + return val.strip() + + # check mount options for btrfs volumes in case it's a subvol + if device and device.type == "btrfs volume" and options: + attr = None + if "subvol=" in options: + attr = "name" + val = get_opt_val("subvol", options) + elif "subvolid=" in options: + attr = "vol_id" + val = get_opt_val("subvolid", options) + + if attr and val: + for subvol in device.subvolumes: + if getattr(subvol, attr, None) == val: + device = subvol + break + if device: log.debug("resolved '%s' to '%s' (%s)" % (devspec, device.name, device.type)) else: diff --git a/pyanaconda/storage/formats/fs.py b/pyanaconda/storage/formats/fs.py index 248dd9c..f94606b 100644 --- a/pyanaconda/storage/formats/fs.py +++ b/pyanaconda/storage/formats/fs.py @@ -1123,6 +1123,10 @@ class BTRFS(FS): # filesystem creation is done in storage.devicelibs.btrfs.create_volume pass
+ def destroy(self, *args, **kwargs): + # filesystem creation is done in storage.devicelibs.btrfs.delete_volume + pass + def setup(self, *args, **kwargs): log_method_call(self, type=self.mountType, device=self.device, mountpoint=self.mountpoint)
On Wed, Jul 25, 2012 at 04:48:27PM -0500, David Lehman wrote:
def get_opt_val(opt_name, options):for opt in options.split(","):if "=" not in opt:continuename, val = opt.split("=")if name == opt_name:return val.strip()
This is probably useful enough that it belongs in iutil.
--- pyanaconda/kickstart.py | 8 ++++---- pyanaconda/storage/__init__.py | 15 +++------------ pyanaconda/storage/devices.py | 14 +++++++------- pyanaconda/storage/partitioning.py | 10 ++++------ 4 files changed, 18 insertions(+), 29 deletions(-)
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py index e6eafc5..7e2022a 100644 --- a/pyanaconda/kickstart.py +++ b/pyanaconda/kickstart.py @@ -651,7 +651,7 @@ class LogVolData(commands.logvol.F17_LogVolData):
request = storage.newLV(format=format, name=self.name, - vg=vg, + parents=[vg], size=self.size, grow=self.grow, maxsize=self.maxSizeMB, @@ -990,12 +990,12 @@ class PartitionData(commands.partition.F17_PartData):
should_clear = storage.shouldClear(disk) if disk and (disk.partitioned or should_clear): - kwargs["disks"] = [disk] + kwargs["parents"] = [disk] break elif disk: raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified unpartitioned disk %s in partition command" % self.disk)
- if not kwargs["disks"]: + if not kwargs["parents"]: raise KickstartValueError, formatErrorMsg(self.lineno, msg="Specified nonexistent disk %s in partition command" % self.disk)
kwargs["grow"] = self.grow @@ -1300,7 +1300,7 @@ class VolGroupData(commands.volgroup.FC16_VolGroupData): elif self.vgname in [vg.name for vg in storage.vgs]: raise KickstartValueError(formatErrorMsg(self.lineno, msg="The volume group name "%s" is already in use." % self.vgname)) else: - request = storage.newVG(pvs=pvs, + request = storage.newVG(parents=pvs, name=self.vgname, peSize=self.pesize/1024.0)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index 1ad5b97..38424b7 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -1080,13 +1080,6 @@ class Storage(object): None), **kwargs.pop("fmt_args", {}))
- if kwargs.has_key("disks"): - parents = kwargs.pop("disks") - if isinstance(parents, Device): - kwargs["parents"] = [parents] - else: - kwargs["parents"] = parents - if kwargs.has_key("name"): name = kwargs.pop("name") else: @@ -1115,7 +1108,7 @@ class Storage(object):
def newVG(self, *args, **kwargs): """ Return a new LVMVolumeGroupDevice instance. """ - pvs = kwargs.pop("pvs", []) + pvs = kwargs.pop("parents", []) for pv in pvs: if pv not in self.devices: raise ValueError("pv is not in the device tree") @@ -1139,9 +1132,7 @@ class Storage(object):
def newLV(self, *args, **kwargs): """ Return a new LVMLogicalVolumeDevice instance. """ - if kwargs.has_key("vg"): - vg = kwargs.pop("vg") - + vg = kwargs.get("parents")[0] mountpoint = kwargs.pop("mountpoint", None) if kwargs.has_key("fmt_type"): kwargs["format"] = getFormat(kwargs.pop("fmt_type"), @@ -1162,7 +1153,7 @@ class Storage(object): if name in self.names: raise ValueError("name already in use")
- return LVMLogicalVolumeDevice(name, vg, *args, **kwargs) + return LVMLogicalVolumeDevice(name, *args, **kwargs)
def newBTRFS(self, *args, **kwargs): """ Return a new BTRFSVolumeDevice or BRFSSubVolumeDevice. """ diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py index 8c2713b..8552179 100644 --- a/pyanaconda/storage/devices.py +++ b/pyanaconda/storage/devices.py @@ -1964,7 +1964,7 @@ class LVMVolumeGroupDevice(DMDevice): _type = "lvmvg" _packages = ["lvm2"]
- def __init__(self, name, parents, size=None, free=None, + def __init__(self, name, parents=None, size=None, free=None, peSize=None, peCount=None, peFree=None, pvCount=None, uuid=None, exists=False, sysfsPath=''): """ Create a LVMVolumeGroupDevice instance. @@ -2387,7 +2387,7 @@ class LVMLogicalVolumeDevice(DMDevice): _resizable = True _packages = ["lvm2"]
- def __init__(self, name, vgdev, size=None, uuid=None, + def __init__(self, name, parents=None, size=None, uuid=None, stripes=1, logSize=0, snapshotSpace=0, format=None, exists=False, sysfsPath='', grow=None, maxsize=None, percent=None, @@ -2418,15 +2418,15 @@ class LVMLogicalVolumeDevice(DMDevice): percent -- percent of VG space to take
""" - if isinstance(vgdev, list): - if len(vgdev) != 1: + if isinstance(parents, list): + if len(parents) != 1: raise ValueError("constructor requires a single LVMVolumeGroupDevice instance") - elif not isinstance(vgdev[0], LVMVolumeGroupDevice): + elif not isinstance(parents[0], LVMVolumeGroupDevice): raise ValueError("constructor requires a LVMVolumeGroupDevice instance") - elif not isinstance(vgdev, LVMVolumeGroupDevice): + elif not isinstance(parents, LVMVolumeGroupDevice): raise ValueError("constructor requires a LVMVolumeGroupDevice instance") DMDevice.__init__(self, name, size=size, format=format, - sysfsPath=sysfsPath, parents=vgdev, + sysfsPath=sysfsPath, parents=parents, exists=exists)
self.singlePVerr = ("%(mountpoint)s is restricted to a single " diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py index 62e0c14..48967c8 100644 --- a/pyanaconda/storage/partitioning.py +++ b/pyanaconda/storage/partitioning.py @@ -87,7 +87,7 @@ def _scheduleImplicitPartitions(storage, disks): part = storage.newPartition(fmt_type=fmt_type, fmt_args=fmt_args, grow=True, - disks=[disk]) + parents=[disk]) storage.createDevice(part) devs.append(part)
@@ -171,7 +171,7 @@ def _schedulePartitions(storage, disks): grow=request.grow, maxsize=request.maxSize, mountpoint=request.mountpoint, - disks=disks, + parents=disks, weight=request.weight)
# schedule the device for creation @@ -199,12 +199,10 @@ def _scheduleVolumes(storage, devs): new_container = storage.newVG new_volume = storage.newLV format_name = "lvmpv" - parent_kw = "pvs" else: new_container = storage.newBTRFS new_volume = storage.newBTRFS format_name = "btrfs" - parent_kw = "parents"
if storage.encryptedAutoPart: pvs = [] @@ -219,7 +217,7 @@ def _scheduleVolumes(storage, devs): pvs = devs
# create a vg containing all of the autopart pvs - container = new_container(**{parent_kw: pvs}) + container = new_container(parents=pvs) storage.createDevice(container)
# @@ -258,7 +256,7 @@ def _scheduleVolumes(storage, devs): kwargs = {"mountpoint": request.mountpoint, "fmt_type": request.fstype} if lv: - kwargs.update({"vg": container, + kwargs.update({"parents": [container], "grow": request.grow, "maxsize": request.maxSize, "size": request.size,
On Wed, Jul 25, 2012 at 04:48:28PM -0500, David Lehman wrote:
def newLV(self, *args, **kwargs): """ Return a new LVMLogicalVolumeDevice instance. """
if kwargs.has_key("vg"):vg = kwargs.pop("vg")
vg = kwargs.get("parents")[0]
Should probably protect against parents not being set.
--- pyanaconda/storage/__init__.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index 38424b7..5bf1845 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -2696,6 +2696,9 @@ def findExistingInstallations(devicetree): name = "%s Linux %s for %s" % (product, version, arch)
(mounts, swaps) = parseFSTab(devicetree, chroot=ROOT_PATH) + 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()
--- pyanaconda/storage/devicetree.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/pyanaconda/storage/devicetree.py b/pyanaconda/storage/devicetree.py index cd45cf6..0ecbb95 100644 --- a/pyanaconda/storage/devicetree.py +++ b/pyanaconda/storage/devicetree.py @@ -354,6 +354,7 @@ class DeviceTree(object): # don't include "req%d" partition names if ((newdev.type != "partition" or not newdev.name.startswith("req")) and + newdev.type != "btrfs volume" and newdev.name not in self.names): self.names.append(newdev.name) log.info("added %s %s (id %d) to device tree" % (newdev.type,
This is handled by the bootloader ksdata execute method. --- pyanaconda/ui/gui/spokes/storage.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py index 23b0977..6e5df44 100644 --- a/pyanaconda/ui/gui/spokes/storage.py +++ b/pyanaconda/ui/gui/spokes/storage.py @@ -319,12 +319,6 @@ class StorageSpoke(NormalSpoke, StorageChecker): # user may have set up before now. self.storage.config.clearNonExistent = self.data.autopart.autopart
- # Pick the first disk to be the destination device for the bootloader. - # This appears to be the minimum amount of configuration required to - # make autopart happy with the bootloader settings. - if not self.data.bootloader.bootDrive: - self.data.bootloader.bootDrive = self.storage.bootloader.disks[0].name - def execute(self): doKickstartStorage(self.storage, self.data, self.instclass) self.run()
--- pyanaconda/storage/devicelibs/crypto.py | 2 ++ pyanaconda/storage/devices.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/pyanaconda/storage/devicelibs/crypto.py b/pyanaconda/storage/devicelibs/crypto.py index ee57322..35c813f 100644 --- a/pyanaconda/storage/devicelibs/crypto.py +++ b/pyanaconda/storage/devicelibs/crypto.py @@ -29,6 +29,8 @@ from ..errors import * import gettext _ = lambda x: gettext.ldgettext("anaconda", x)
+LUKS_METADATA_SIZE = 2.0 # MB + # Keep the character set size a power of two to make sure all characters are # equally likely GENERATED_PASSPHRASE_CHARSET = ("0123456789" diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py index 8552179..c99c3c2 100644 --- a/pyanaconda/storage/devices.py +++ b/pyanaconda/storage/devices.py @@ -105,6 +105,7 @@ from devicelibs import lvm from devicelibs import dm from devicelibs import loop from devicelibs import btrfs +from devicelibs import crypto import parted import _ped import block @@ -1934,8 +1935,7 @@ class LUKSDevice(DMCryptDevice): @property def size(self): if not self.exists or not self.partedDevice: - # the LUKS metadata area is 2MB - size = float(self.slave.size) - 2.0 + size = float(self.slave.size) - crypto.LUKS_METADATA_SIZE else: size = self.partedDevice.getSize() return size
--- pyanaconda/storage/partitioning.py | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py index 48967c8..e9c06f6 100644 --- a/pyanaconda/storage/partitioning.py +++ b/pyanaconda/storage/partitioning.py @@ -1269,7 +1269,7 @@ class Chunk(object): def sortRequests(self): pass
- def growRequests(self): + def growRequests(self, uniform=False): """ Calculate growth amounts for requests in this chunk. """ log.debug("Chunk.growRequests: %r" % self)
@@ -1285,17 +1285,22 @@ class Chunk(object): while not self.done and self.pool and last_pool != self.pool: last_pool = self.pool # to keep from getting stuck self.base = new_base + if uniform: + growth = last_pool / self.remaining + log.debug("%d requests and %d (%dMB) left in chunk" % (self.remaining, self.pool, self.lengthToSize(self.pool))) for p in self.requests: if p.done: continue
- # Each request is allocated free units from the pool - # based on the relative _base_ sizes of the remaining - # growable requests. - share = p.base / float(self.base) - growth = int(share * last_pool) # truncate, don't round + if not uniform: + # Each request is allocated free units from the pool + # based on the relative _base_ sizes of the remaining + # growable requests. + share = p.base / float(self.base) + growth = int(share * last_pool) # truncate, don't round + p.growth += growth self.pool -= growth log.debug("adding %d (%dMB) to %d (%s)" %
--- pyanaconda/ui/gui/TODO | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/pyanaconda/ui/gui/TODO b/pyanaconda/ui/gui/TODO index 1eccc6b..e7f2444 100644 --- a/pyanaconda/ui/gui/TODO +++ b/pyanaconda/ui/gui/TODO @@ -28,6 +28,8 @@ Fedora 18 - In custom storage, it'd be really nice to be able to drag entries from old roots into the "New Fedora" root as a way of saying "Use this device with the same mountpoint in the new system." +- We're probably going to need to update the auto-generated names of container + devices any time the user updates the hostname.
Beyond ======
anaconda-patches@lists.fedorahosted.org