Deleting a parted.Device causes parted to close its rw fd for the device, which triggers a change uevent on that device, which could in turn trigger any number of actions via udev rules. One example is when we reset a Blivet instance: All devices are deleted, including their parted.Device instances, which triggers a change uevent for every device. In response to these events, mdadm's udev rules activate all arrays on those devices. Activating devices -- even indirectly -- without cause, is not acceptable behavior for a storage library.
This also adds a trailing comma to 1-tuples in variable_copy arguments. In my testing, ('foo') is the string 'foo' -- not a tuple with lone element 'foo'.
(cherry picked from commit 73d9c995c8d46f1aa248d1ade3bbb1838653b6b0)
Resolves: rhbz#1069597 --- blivet/deviceaction.py | 9 ---- blivet/devices/btrfs.py | 3 ++ blivet/devices/container.py | 3 ++ blivet/devices/device.py | 2 +- blivet/devices/disk.py | 14 ++---- blivet/devices/dm.py | 3 +- blivet/devices/file.py | 9 ++++ blivet/devices/lib.py | 3 ++ blivet/devices/luks.py | 6 +-- blivet/devices/md.py | 19 ++++---- blivet/devices/nfs.py | 3 ++ blivet/devices/nodev.py | 2 + blivet/devices/partition.py | 41 +++++++++-------- blivet/devices/storage.py | 107 +++++++++++++++++++++----------------------- blivet/devicetree.py | 15 +++---- blivet/platform.py | 10 +++-- tests/storagetestcase.py | 5 +-- 17 files changed, 124 insertions(+), 130 deletions(-)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index a8cd489..bc7c1a0 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -28,7 +28,6 @@ from .util import get_current_entropy from .devices import StorageDevice from .devices import PartitionDevice, LVMLogicalVolumeDevice from .formats import getFormat, luks -from .storage_log import log_exception_info from parted import partitionFlag, PARTITION_LBA from .i18n import _, N_ from .callbacks import CreateFormatPreData, CreateFormatPostData @@ -344,14 +343,6 @@ class ActionDestroyDevice(DeviceAction): super(ActionDestroyDevice, self).execute(callbacks=None) self.device.destroy()
- # 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: - try: - self.device.partedDevice.removeFromCache() - except Exception: # pylint: disable=broad-except - log_exception_info(fmt_str="failed to remove info for device %s from libparted cache", fmt_args=[self.device]) - def requires(self, action): """ Return True if self requires action.
diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py index 8e47708..eeb203f 100644 --- a/blivet/devices/btrfs.py +++ b/blivet/devices/btrfs.py @@ -61,6 +61,9 @@ class BTRFSDevice(StorageDevice): self.sysfsPath = self.parents[0].sysfsPath log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
+ def updateSize(self): + pass + def _postCreate(self): super(BTRFSDevice, self)._postCreate() self.format.exists = True diff --git a/blivet/devices/container.py b/blivet/devices/container.py index d8a1379..6e5683e 100644 --- a/blivet/devices/container.py +++ b/blivet/devices/container.py @@ -200,3 +200,6 @@ class ContainerDevice(StorageDevice):
if member in self.parents: self.parents.remove(member) + + def updateSize(self): + pass diff --git a/blivet/devices/device.py b/blivet/devices/device.py index 498fef4..1824f8c 100644 --- a/blivet/devices/device.py +++ b/blivet/devices/device.py @@ -99,7 +99,7 @@ class Device(util.ObjectID): """ return util.variable_copy(self, memo, omit=('_raidSet', 'node'), - shallow=('_partedDevice', '_partedPartition')) + shallow=('_partedPartition',))
def __repr__(self): s = ("%(type)s instance (%(id)s) --\n" diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py index 6a9a91a..d17e975 100644 --- a/blivet/devices/disk.py +++ b/blivet/devices/disk.py @@ -27,6 +27,7 @@ import block from .. import errors from .. import util from ..flags import flags +from ..size import Size from ..storage_log import log_method_call from .. import udev
@@ -89,8 +90,7 @@ class DiskDevice(StorageDevice):
def __repr__(self): s = StorageDevice.__repr__(self) - s += (" removable = %(removable)s partedDevice = %(partedDevice)r" % - {"removable": self.removable, "partedDevice": self.partedDevice}) + s += (" removable = %(removable)s" % {"removable": self.removable}) return s
@property @@ -98,23 +98,15 @@ class DiskDevice(StorageDevice): if flags.testing: return True
- if not self.partedDevice: - return False - # Some drivers (cpqarray <blegh>) make block device nodes for # controllers with no disks attached and then report a 0 size, # treat this as no media present - return self.partedDevice.getLength(unit="B") != 0 + return self.exists and self.currentSize > Size(0)
@property def description(self): return self.model
- @property - def size(self): - """ The disk's size """ - return super(DiskDevice, self).size - def _preDestroy(self): """ Destroy the device. """ log_method_call(self, self.name, status=self.status) diff --git a/blivet/devices/dm.py b/blivet/devices/dm.py index 57314bd..9326786 100644 --- a/blivet/devices/dm.py +++ b/blivet/devices/dm.py @@ -34,6 +34,7 @@ import logging log = logging.getLogger("blivet")
from .storage import StorageDevice +from .lib import LINUX_SECTOR_SIZE
class DMDevice(StorageDevice): """ A device-mapper device """ @@ -181,7 +182,7 @@ class DMLinearDevice(DMDevice): """ Open, or set up, a device. """ log_method_call(self, self.name, orig=orig, status=self.status, controllable=self.controllable) - slave_length = self.slave.partedDevice.length + slave_length = self.slave.currentSize / LINUX_SECTOR_SIZE dm.dm_create_linear(self.name, self.slave.path, slave_length, self.dmUuid)
diff --git a/blivet/devices/file.py b/blivet/devices/file.py index da231c5..7aaf011 100644 --- a/blivet/devices/file.py +++ b/blivet/devices/file.py @@ -21,6 +21,7 @@ #
import os +import stat
from .. import util from ..storage_log import log_method_call @@ -80,6 +81,14 @@ class FileDevice(StorageDevice):
return os.path.normpath("%s%s" % (root, self.name))
+ def _getSize(self): + size = self._size + if self.exists and os.path.exists(self.path): + st = os.stat(self.path) + size = Size(st[stat.ST_SIZE]) + + return size + def _preSetup(self, orig=False): if self.format and self.format.exists and not self.format.status: self.format.device = self.path diff --git a/blivet/devices/lib.py b/blivet/devices/lib.py index c4996db..979dd6e 100644 --- a/blivet/devices/lib.py +++ b/blivet/devices/lib.py @@ -20,6 +20,9 @@ # from .. import errors from .. import udev +from ..size import Size + +LINUX_SECTOR_SIZE = Size(512)
def get_device_majors(): majors = {} diff --git a/blivet/devices/luks.py b/blivet/devices/luks.py index f02cd28..197926f 100644 --- a/blivet/devices/luks.py +++ b/blivet/devices/luks.py @@ -22,8 +22,6 @@ # device backend modules from ..devicelibs import crypto
-from ..size import Size - import logging log = logging.getLogger("blivet")
@@ -63,10 +61,10 @@ class LUKSDevice(DMCryptDevice):
@property def size(self): - if not self.exists or not self.partedDevice: + if not self.exists: size = self.slave.size - crypto.LUKS_METADATA_SIZE else: - size = Size(self.partedDevice.getLength(unit="B")) + size = self.currentSize return size
def _postCreate(self): diff --git a/blivet/devices/md.py b/blivet/devices/md.py index 8ce7854..33d91b5 100644 --- a/blivet/devices/md.py +++ b/blivet/devices/md.py @@ -28,7 +28,6 @@ from .. import util from ..flags import flags from ..storage_log import log_method_call from .. import udev -from ..size import Size from ..i18n import P_
import logging @@ -81,15 +80,15 @@ class MDRaidArrayDevice(ContainerDevice): self._memberDevices = 0 # the number of active (non-spare) members self._totalDevices = 0 # the total number of members
+ if level == "container": + self._type = "mdcontainer" + self.level = level + super(MDRaidArrayDevice, self).__init__(name, fmt=fmt, uuid=uuid, exists=exists, size=size, parents=parents, sysfsPath=sysfsPath)
- if level == "container": - self._type = "mdcontainer" - self.level = level - # For new arrays check if we have enough members if (not exists and parents and len(parents) < self.level.min_members): for dev in self.parents: @@ -196,7 +195,7 @@ class MDRaidArrayDevice(ContainerDevice): if self.type == "mdbiosraidarray": return self._size
- if not self.exists or not self.partedDevice: + if not self.exists or not self.mediaPresent: try: size = self.level.get_size([d.size for d in self.devices], self.memberDevices, @@ -207,11 +206,15 @@ class MDRaidArrayDevice(ContainerDevice): size = 0 log.debug("non-existent RAID %s size == %s", self.level, size) else: - size = Size(self.partedDevice.getLength(unit="B")) + size = self.currentSize log.debug("existing RAID %s size == %s", self.level, size)
return size
+ def updateSize(self): + # pylint: disable=bad-super-call + super(ContainerDevice, self).updateSize() + @property def description(self): if self.type == "mdcontainer": @@ -561,7 +564,7 @@ class MDRaidArrayDevice(ContainerDevice): elif flags.testing: return True else: - return self.partedDevice is not None + return super(MDRaidArrayDevice, self).mediaPresent
@property def model(self): diff --git a/blivet/devices/nfs.py b/blivet/devices/nfs.py index 513a11c..da00114 100644 --- a/blivet/devices/nfs.py +++ b/blivet/devices/nfs.py @@ -69,6 +69,9 @@ class NFSDevice(StorageDevice, NetworkStorageDevice): """ Destroy the device. """ log_method_call(self, self.name, status=self.status)
+ def updateSize(self): + pass + @classmethod def isNameValid(cls, name): # Override StorageDevice.isNameValid to allow / diff --git a/blivet/devices/nodev.py b/blivet/devices/nodev.py index a66636c..1aee5d3 100644 --- a/blivet/devices/nodev.py +++ b/blivet/devices/nodev.py @@ -69,6 +69,8 @@ class NoDevice(StorageDevice): log_method_call(self, self.name, status=self.status) self._preDestroy()
+ def udpateSize(self): + pass
class TmpFSDevice(NoDevice): """ A nodev device for a tmpfs filesystem. """ diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py index 2701572..18add66 100644 --- a/blivet/devices/partition.py +++ b/blivet/devices/partition.py @@ -125,6 +125,12 @@ class PartitionDevice(StorageDevice):
self._bootable = False
+ # FIXME: Validate partType, but only if this is a new partition + # Otherwise, overwrite it with the partition's type. + self._partType = None + self._partedPartition = None + self._origPath = None + StorageDevice.__init__(self, name, fmt=fmt, size=size, major=major, minor=minor, exists=exists, sysfsPath=sysfsPath, parents=parents) @@ -134,13 +140,6 @@ class PartitionDevice(StorageDevice): self.req_disks = list(self.parents) self.parents = []
- # FIXME: Validate partType, but only if this is a new partition - # Otherwise, overwrite it with the partition's type. - self._partType = None - self._partedPartition = None - self._origPath = None - self._currentSize = 0 - # FIXME: Validate size, but only if this is a new partition. # For existing partitions we will get the size from # parted. @@ -529,7 +528,6 @@ class PartitionDevice(StorageDevice): return
self._size = Size(self.partedPartition.getLength(unit="B")) - self._currentSize = self._size self.targetSize = self._size
self._partType = self.partedPartition.type @@ -592,7 +590,6 @@ class PartitionDevice(StorageDevice): DeviceFormat(device=self.path, exists=True).destroy()
StorageDevice._postCreate(self) - self._currentSize = Size(self.partedPartition.getLength(unit="B"))
def create(self): """ Create the device. """ @@ -661,7 +658,7 @@ class PartitionDevice(StorageDevice): end=geometry.end)
self.disk.format.commit() - self._currentSize = Size(partition.getLength(unit="B")) + self.updateSize()
def _preDestroy(self): StorageDevice._preDestroy(self) @@ -728,12 +725,16 @@ class PartitionDevice(StorageDevice): return size
def _setSize(self, newsize): - """ Set the device's size (for resize, not creation). + """ Set the device's size. + + Most devices have two scenarios for setting a size:
- Arguments: + 1) set actual/current size + 2) set target for resize
- newsize -- the new size + Partitions have a third scenario:
+ 3) update size of an allocated-but-non-existent partition """ log_method_call(self, self.name, status=self.status, size=self._size, newsize=newsize) @@ -746,6 +747,12 @@ class PartitionDevice(StorageDevice): self.req_size = newsize self.req_base_size = newsize
+ if self.exists: + super(PartitionDevice, self)._setSize(newsize) + return + + # the rest is for changing the size of an allocated-but-not-existing + # partition, which I'm not sure is advisable if newsize > self.disk.size: raise ValueError("partition size would exceed disk size")
@@ -829,14 +836,6 @@ class PartitionDevice(StorageDevice): unalignedMax = min(maxFormatSize, maxPartSize) if maxFormatSize else maxPartSize return self.alignTargetSize(unalignedMax)
- @property - def currentSize(self): - if self.exists: - return self._currentSize - else: - return 0 - - @property def resizable(self): return super(PartitionDevice, self).resizable and \ self.disk.type != 'dasd' diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py index 73ba645..6128886 100644 --- a/blivet/devices/storage.py +++ b/blivet/devices/storage.py @@ -22,8 +22,6 @@
import os import copy -import parted -import _ped import pyudev
from .. import errors @@ -38,6 +36,7 @@ import logging log = logging.getLogger("blivet")
from .device import Device +from .lib import LINUX_SECTOR_SIZE
class StorageDevice(Device): """ A generic storage device. @@ -105,7 +104,11 @@ class StorageDevice(Device): Device.__init__(self, name, parents=parents)
self._format = None + + # The size will be overridden by a call to updateSize at the end of this + # method for existing and active devices. self._size = Size(util.numeric_type(size)) + self._currentSize = self._size if self.exists else Size(0) self.major = util.numeric_type(major) self.minor = util.numeric_type(minor) self._serial = serial @@ -123,16 +126,8 @@ class StorageDevice(Device):
self.deviceLinks = []
- if self.exists and flags.testing and not self._size: - def read_int_from_sys(path): - return int(open(path).readline().strip()) - - device_root = "/sys/class/block/%s" % self.name - if os.path.exists("%s/queue" % device_root): - sector_size = read_int_from_sys("%s/queue/logical_block_size" - % device_root) - size = read_int_from_sys("%s/size" % device_root) - self._size = Size(size * sector_size) + if self.exists and self.status: + self.updateSize()
self._orig_size = self._size
@@ -199,26 +194,6 @@ class StorageDevice(Device): """ True if this device, or any it requires, is encrypted. """ return self._encrypted or any(p.encrypted for p in self.parents)
- def _getPartedDevicePath(self): - return self.path - - @property - def partedDevice(self): - devicePath = self._getPartedDevicePath() - if self.exists and self.status and not self._partedDevice: - log.debug("looking up parted Device: %s", devicePath) - - # We aren't guaranteed to be able to get a device. In - # particular, built-in USB flash readers show up as devices but - # do not always have any media present, so parted won't be able - # to find a device. - try: - self._partedDevice = parted.Device(path=devicePath) - except (_ped.IOException, _ped.DeviceException): - pass - - return self._partedDevice - @property def raw_device(self): """ The device itself, or when encrypted, the backing device. """ @@ -281,12 +256,12 @@ class StorageDevice(Device): " format = %(format)s\n" " major = %(major)s minor = %(minor)s exists = %(exists)s" " protected = %(protected)s\n" - " sysfs path = %(sysfs)s partedDevice = %(partedDevice)s\n" + " sysfs path = %(sysfs)s\n" " target size = %(targetSize)s path = %(path)s\n" " format args = %(formatArgs)s originalFormat = %(origFmt)s" % {"uuid": self.uuid, "format": self.format, "size": self.size, "major": self.major, "minor": self.minor, "exists": self.exists, - "sysfs": self.sysfsPath, "partedDevice": self.partedDevice, + "sysfs": self.sysfsPath, "targetSize": self.targetSize, "path": self.path, "protected": self.protected, "formatArgs": self.formatArgs, "origFmt": self.originalFormat.type}) @@ -410,9 +385,10 @@ class StorageDevice(Device): def _postSetup(self): """ Perform post-setup operations. """ udev.settle() - # we always probe since the device may not be set up when we want - # information about it - self._size = self.currentSize + self.updateSysfsPath() + # the device may not be set up when we want information about it + if self._size == Size(0): + self.updateSize()
# # teardown @@ -487,9 +463,7 @@ class StorageDevice(Device): udev.settle()
# make sure that targetSize is updated to reflect the actual size - if self.resizable: - self._partedDevice = None - self._targetSize = self.currentSize + self.updateSize()
# # destroy @@ -535,12 +509,6 @@ class StorageDevice(Device):
def _getSize(self): """ Get the device's size, accounting for pending changes. """ - if self.exists and not self.mediaPresent: - return 0 - - if self.exists and self.partedDevice: - self._size = self.currentSize - size = self._size if self.exists and self.resizable: size = self.targetSize @@ -548,19 +516,41 @@ class StorageDevice(Device): return size
def _setSize(self, newsize): - """ Set the device's size to a new value. """ + """ Set the device's size to a new value. + + This is not adequate to set up a resize as it does not set a new + target size for the device. + """ if not isinstance(newsize, Size): raise ValueError("new size must of type Size")
- if self.maxSize and newsize > self.maxSize: + # only calculate these once + max_size = self.maxSize + min_size = self.minSize + if max_size and newsize > max_size: raise errors.DeviceError("device cannot be larger than %s" % - (self.maxSize,), self.name) + max_size, self.name) + elif min_size and newsize < min_size: + raise errors.DeviceError("device cannot be smaller than %s" % + min_size, self.name) + self._size = newsize
size = property(lambda x: x._getSize(), lambda x, y: x._setSize(y), doc="The device's size, accounting for pending changes")
+ def readCurrentSize(self): + log_method_call(self, exists=self.exists, path=self.path, + sysfsPath=self.sysfsPath) + size = Size(0) + if self.exists and os.path.exists(self.path) and \ + os.path.isdir(self.sysfsPath): + blocks = int(util.get_sysfs_attr(self.sysfsPath, "size")) + size = Size(blocks * LINUX_SECTOR_SIZE) + + return size + @property def currentSize(self): """ The device's actual size, generally the size discovered by using @@ -569,12 +559,17 @@ class StorageDevice(Device):
If the device does not exist, then the actual size is 0. """ - size = 0 - if self.exists and self.partedDevice: - size = Size(self.partedDevice.getLength(unit="B")) - elif self.exists: - size = self._size - return size + if self._currentSize == Size(0): + self._currentSize = self.readCurrentSize() + return self._currentSize + + def updateSize(self): + """ Update size, currentSize, and targetSize to actual size. """ + self._currentSize = Size(0) + new_size = self.currentSize + self._size = new_size + self._targetSize = new_size # bypass setter checks + log.debug("updated %s size to %s (%s)", self.name, self.size, new_size)
@property def minSize(self): @@ -658,8 +653,6 @@ class StorageDevice(Device):
@property def model(self): - if not self._model: - self._model = getattr(self.partedDevice, "model", "") return self._model
@property diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 70b95f1..a70d7b9 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1085,6 +1085,7 @@ class DeviceTree(object): device = diskType(name, major=udev.device_get_major(info), minor=udev.device_get_minor(info), + model=udev.device_get_model(info), sysfsPath=sysfs_path, **kwargs)
if diskType == DASDDevice: @@ -1203,9 +1204,7 @@ class DeviceTree(object): # The first step is to either look up or create the device # if device: - # we successfully looked up the device. skip to format handling. - # first, grab the parted.Device while it's active - _unused = device.partedDevice + pass elif udev.device_is_loop(info): log.info("%s is a loop device", name) device = self.addUdevLoopDevice(info) @@ -1529,6 +1528,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath() + lv_device.updateSize() lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name) @@ -1871,15 +1871,10 @@ class DeviceTree(object): kwargs["name"] = "luks-%s" % uuid elif format_type in formats.mdraid.MDRaidMember._udevTypes: # mdraid - try: - kwargs["mdUuid"] = udev.device_get_md_uuid(info) - except KeyError: - log.warning("mdraid member %s has no md uuid", name) - # reset the uuid to the member-specific value # this will be None for members of v0 metadata arrays - kwargs["uuid"] = udev.device_get_md_device_uuid(info) - + kwargs["uuid"] = info.get("ID_FS_UUID_SUB") + kwargs["mdUuid"] = uuid kwargs["biosraid"] = udev.device_is_biosraid_member(info) elif format_type == "LVM2_member": # lvm diff --git a/blivet/platform.py b/blivet/platform.py index 1376ffd..ad048b9 100644 --- a/blivet/platform.py +++ b/blivet/platform.py @@ -125,10 +125,12 @@ class Platform(object): if flags.testing: return self.defaultDiskLabelType
+ parted_device = parted.Device(path=device.path) + # if there's a required type for this device type, use that - labelType = self.requiredDiskLabelType(device.partedDevice.type) + labelType = self.requiredDiskLabelType(parted_device.type) log.debug("required disklabel type for %s (%s) is %s", - device.name, device.partedDevice.type, labelType) + device.name, parted_device.type, labelType) if not labelType: # otherwise, use the first supported type for this platform # that is large enough to address the whole device @@ -136,8 +138,8 @@ class Platform(object): log.debug("default disklabel type for %s is %s", device.name, labelType) for lt in self.diskLabelTypes: - l = parted.freshDisk(device=device.partedDevice, ty=lt) - if l.maxPartitionStartSector > device.partedDevice.length: + l = parted.freshDisk(device=parted_device, ty=lt) + if l.maxPartitionStartSector > parted_device.length: labelType = lt log.debug("selecting %s disklabel for %s based on size", labelType, device.name) diff --git a/tests/storagetestcase.py b/tests/storagetestcase.py index 615e727..8293818 100644 --- a/tests/storagetestcase.py +++ b/tests/storagetestcase.py @@ -66,10 +66,7 @@ class StorageTestCase(unittest.TestCase): device = device_class(*args, **kwargs)
if exists: - # set up mock parted.Device w/ correct size - device._partedDevice = Mock() - device._partedDevice.getLength = Mock(return_value=int(device.size.convertTo(spec="B"))) - device._partedDevice.sectorSize = 512 + device._currentSize = kwargs.get("size")
if isinstance(device, blivet.devices.PartitionDevice): #if exists:
On Fri, 2015-06-26 at 16:54 -0500, David Lehman wrote:
Deleting a parted.Device causes parted to close its rw fd for the device, which triggers a change uevent on that device, which could in turn trigger any number of actions via udev rules. One example is when we reset a Blivet instance: All devices are deleted, including their parted.Device instances, which triggers a change uevent for every device. In response to these events, mdadm's udev rules activate all arrays on those devices. Activating devices -- even indirectly -- without cause, is not acceptable behavior for a storage library.
This also adds a trailing comma to 1-tuples in variable_copy arguments. In my testing, ('foo') is the string 'foo' -- not a tuple with lone element 'foo'.
(cherry picked from commit 73d9c995c8d46f1aa248d1ade3bbb1838653b6b0)
Resolves: rhbz#1069597
blivet/deviceaction.py | 9 ---- blivet/devices/btrfs.py | 3 ++ blivet/devices/container.py | 3 ++ blivet/devices/device.py | 2 +- blivet/devices/disk.py | 14 ++---- blivet/devices/dm.py | 3 +- blivet/devices/file.py | 9 ++++ blivet/devices/lib.py | 3 ++ blivet/devices/luks.py | 6 +-- blivet/devices/md.py | 19 ++++---- blivet/devices/nfs.py | 3 ++ blivet/devices/nodev.py | 2 + blivet/devices/partition.py | 41 +++++++++-------- blivet/devices/storage.py | 107 +++++++++++++++++++++----------------------- blivet/devicetree.py | 15 +++---- blivet/platform.py | 10 +++-- tests/storagetestcase.py | 5 +-- 17 files changed, 124 insertions(+), 130 deletions(-)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index a8cd489..bc7c1a0 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -28,7 +28,6 @@ from .util import get_current_entropy from .devices import StorageDevice from .devices import PartitionDevice, LVMLogicalVolumeDevice from .formats import getFormat, luks -from .storage_log import log_exception_info from parted import partitionFlag, PARTITION_LBA from .i18n import _, N_ from .callbacks import CreateFormatPreData, CreateFormatPostData @@ -344,14 +343,6 @@ class ActionDestroyDevice(DeviceAction): super(ActionDestroyDevice, self).execute(callbacks=None) self.device.destroy()
# Make sure libparted does not keep cached info for this device# and returns it when we create a new device with the same nameif self.device.partedDevice:try:self.device.partedDevice.removeFromCache()except Exception: # pylint: disable=broad-exceptlog_exception_info(fmt_str="failed to remove info for device %s from libparted cache", fmt_args=[self.device])- def requires(self, action): """ Return True if self requires action.
diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py index 8e47708..eeb203f 100644 --- a/blivet/devices/btrfs.py +++ b/blivet/devices/btrfs.py @@ -61,6 +61,9 @@ class BTRFSDevice(StorageDevice): self.sysfsPath = self.parents[0].sysfsPath log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
- def updateSize(self):
pass- def _postCreate(self): super(BTRFSDevice, self)._postCreate() self.format.exists = True
diff --git a/blivet/devices/container.py b/blivet/devices/container.py index d8a1379..6e5683e 100644 --- a/blivet/devices/container.py +++ b/blivet/devices/container.py @@ -200,3 +200,6 @@ class ContainerDevice(StorageDevice):
if member in self.parents: self.parents.remove(member)
- def updateSize(self):
passdiff --git a/blivet/devices/device.py b/blivet/devices/device.py index 498fef4..1824f8c 100644 --- a/blivet/devices/device.py +++ b/blivet/devices/device.py @@ -99,7 +99,7 @@ class Device(util.ObjectID): """ return util.variable_copy(self, memo, omit=('_raidSet', 'node'),
shallow=('_partedDevice', '_partedPartition'))
shallow=('_partedPartition',))def __repr__(self): s = ("%(type)s instance (%(id)s) --\n"
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py index 6a9a91a..d17e975 100644 --- a/blivet/devices/disk.py +++ b/blivet/devices/disk.py @@ -27,6 +27,7 @@ import block from .. import errors from .. import util from ..flags import flags +from ..size import Size from ..storage_log import log_method_call from .. import udev
@@ -89,8 +90,7 @@ class DiskDevice(StorageDevice):
def __repr__(self): s = StorageDevice.__repr__(self)
s += (" removable = %(removable)s partedDevice = %(partedDevice)r" %{"removable": self.removable, "partedDevice": self.partedDevice})
s += (" removable = %(removable)s" % {"removable": self.removable}) return s@property
@@ -98,23 +98,15 @@ class DiskDevice(StorageDevice): if flags.testing: return True
if not self.partedDevice:return False# Some drivers (cpqarray <blegh>) make block device nodes for # controllers with no disks attached and then report a 0 size, # treat this as no media presentreturn self.partedDevice.getLength(unit="B") != 0
return self.exists and self.currentSize > Size(0)@property def description(self): return self.model
- @property
- def size(self):
""" The disk's size """return super(DiskDevice, self).size- def _preDestroy(self): """ Destroy the device. """ log_method_call(self, self.name, status=self.status)
diff --git a/blivet/devices/dm.py b/blivet/devices/dm.py index 57314bd..9326786 100644 --- a/blivet/devices/dm.py +++ b/blivet/devices/dm.py @@ -34,6 +34,7 @@ import logging log = logging.getLogger("blivet")
from .storage import StorageDevice +from .lib import LINUX_SECTOR_SIZE
class DMDevice(StorageDevice): """ A device-mapper device """ @@ -181,7 +182,7 @@ class DMLinearDevice(DMDevice): """ Open, or set up, a device. """ log_method_call(self, self.name, orig=orig, status=self.status, controllable=self.controllable)
slave_length = self.slave.partedDevice.length
slave_length = self.slave.currentSize / LINUX_SECTOR_SIZE dm.dm_create_linear(self.name, self.slave.path, slave_length, self.dmUuid)diff --git a/blivet/devices/file.py b/blivet/devices/file.py index da231c5..7aaf011 100644 --- a/blivet/devices/file.py +++ b/blivet/devices/file.py @@ -21,6 +21,7 @@ #
import os +import stat
from .. import util from ..storage_log import log_method_call @@ -80,6 +81,14 @@ class FileDevice(StorageDevice):
return os.path.normpath("%s%s" % (root, self.name))
- def _getSize(self):
size = self._sizeif self.exists and os.path.exists(self.path):st = os.stat(self.path)size = Size(st[stat.ST_SIZE])return size- def _preSetup(self, orig=False): if self.format and self.format.exists and not self.format.status: self.format.device = self.path
diff --git a/blivet/devices/lib.py b/blivet/devices/lib.py index c4996db..979dd6e 100644 --- a/blivet/devices/lib.py +++ b/blivet/devices/lib.py @@ -20,6 +20,9 @@ # from .. import errors from .. import udev +from ..size import Size
+LINUX_SECTOR_SIZE = Size(512)
def get_device_majors(): majors = {} diff --git a/blivet/devices/luks.py b/blivet/devices/luks.py index f02cd28..197926f 100644 --- a/blivet/devices/luks.py +++ b/blivet/devices/luks.py @@ -22,8 +22,6 @@ # device backend modules from ..devicelibs import crypto
-from ..size import Size
import logging log = logging.getLogger("blivet")
@@ -63,10 +61,10 @@ class LUKSDevice(DMCryptDevice):
@property def size(self):
if not self.exists or not self.partedDevice:
if not self.exists: size = self.slave.size - crypto.LUKS_METADATA_SIZE else:
size = Size(self.partedDevice.getLength(unit="B"))
size = self.currentSize return sizedef _postCreate(self):
diff --git a/blivet/devices/md.py b/blivet/devices/md.py index 8ce7854..33d91b5 100644 --- a/blivet/devices/md.py +++ b/blivet/devices/md.py @@ -28,7 +28,6 @@ from .. import util from ..flags import flags from ..storage_log import log_method_call from .. import udev -from ..size import Size from ..i18n import P_
import logging @@ -81,15 +80,15 @@ class MDRaidArrayDevice(ContainerDevice): self._memberDevices = 0 # the number of active (non-spare) members self._totalDevices = 0 # the total number of members
if level == "container":self._type = "mdcontainer"self.level = levelsuper(MDRaidArrayDevice, self).__init__(name, fmt=fmt, uuid=uuid, exists=exists, size=size, parents=parents, sysfsPath=sysfsPath)
if level == "container":self._type = "mdcontainer"self.level = level
This chunk comes from a different commit and is unrelated to the rest of this commit, I think.
# For new arrays check if we have enough members if (not exists and parents and len(parents) < self.level.min_members): for dev in self.parents:@@ -196,7 +195,7 @@ class MDRaidArrayDevice(ContainerDevice): if self.type == "mdbiosraidarray": return self._size
if not self.exists or not self.partedDevice:
if not self.exists or not self.mediaPresent: try: size = self.level.get_size([d.size for d in self.devices], self.memberDevices,@@ -207,11 +206,15 @@ class MDRaidArrayDevice(ContainerDevice): size = 0 log.debug("non-existent RAID %s size == %s", self.level, size) else:
size = Size(self.partedDevice.getLength(unit="B"))
size = self.currentSize log.debug("existing RAID %s size == %s", self.level, size) return sizedef updateSize(self):
# pylint: disable=bad-super-callsuper(ContainerDevice, self).updateSize()@property def description(self): if self.type == "mdcontainer":
@@ -561,7 +564,7 @@ class MDRaidArrayDevice(ContainerDevice): elif flags.testing: return True else:
return self.partedDevice is not None
return super(MDRaidArrayDevice, self).mediaPresent@property def model(self):
diff --git a/blivet/devices/nfs.py b/blivet/devices/nfs.py index 513a11c..da00114 100644 --- a/blivet/devices/nfs.py +++ b/blivet/devices/nfs.py @@ -69,6 +69,9 @@ class NFSDevice(StorageDevice, NetworkStorageDevice): """ Destroy the device. """ log_method_call(self, self.name, status=self.status)
- def updateSize(self):
pass- @classmethod def isNameValid(cls, name): # Override StorageDevice.isNameValid to allow /
diff --git a/blivet/devices/nodev.py b/blivet/devices/nodev.py index a66636c..1aee5d3 100644 --- a/blivet/devices/nodev.py +++ b/blivet/devices/nodev.py @@ -69,6 +69,8 @@ class NoDevice(StorageDevice): log_method_call(self, self.name, status=self.status) self._preDestroy()
- def udpateSize(self):
passclass TmpFSDevice(NoDevice): """ A nodev device for a tmpfs filesystem. """ diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py index 2701572..18add66 100644 --- a/blivet/devices/partition.py +++ b/blivet/devices/partition.py @@ -125,6 +125,12 @@ class PartitionDevice(StorageDevice):
self._bootable = False
# FIXME: Validate partType, but only if this is a new partition# Otherwise, overwrite it with the partition's type.self._partType = Noneself._partedPartition = Noneself._origPath = NoneStorageDevice.__init__(self, name, fmt=fmt, size=size, major=major, minor=minor, exists=exists, sysfsPath=sysfsPath, parents=parents)@@ -134,13 +140,6 @@ class PartitionDevice(StorageDevice): self.req_disks = list(self.parents) self.parents = []
# FIXME: Validate partType, but only if this is a new partition# Otherwise, overwrite it with the partition's type.self._partType = Noneself._partedPartition = Noneself._origPath = Noneself._currentSize = 0# FIXME: Validate size, but only if this is a new partition. # For existing partitions we will get the size from # parted.@@ -529,7 +528,6 @@ class PartitionDevice(StorageDevice): return
self._size = Size(self.partedPartition.getLength(unit="B"))
self._currentSize = self._size self.targetSize = self._size self._partType = self.partedPartition.type@@ -592,7 +590,6 @@ class PartitionDevice(StorageDevice): DeviceFormat(device=self.path, exists=True).destroy()
StorageDevice._postCreate(self)
self._currentSize = Size(self.partedPartition.getLength(unit="B"))def create(self): """ Create the device. """
@@ -661,7 +658,7 @@ class PartitionDevice(StorageDevice): end=geometry.end)
self.disk.format.commit()
self._currentSize = Size(partition.getLength(unit="B"))
self.updateSize()def _preDestroy(self): StorageDevice._preDestroy(self)
@@ -728,12 +725,16 @@ class PartitionDevice(StorageDevice): return size
def _setSize(self, newsize):
""" Set the device's size (for resize, not creation).
""" Set the device's size.Most devices have two scenarios for setting a size:
Arguments:
1) set actual/current size2) set target for resize
newsize -- the new size
Partitions have a third scenario:3) update size of an allocated-but-non-existent partition """ log_method_call(self, self.name, status=self.status, size=self._size, newsize=newsize)@@ -746,6 +747,12 @@ class PartitionDevice(StorageDevice): self.req_size = newsize self.req_base_size = newsize
if self.exists:super(PartitionDevice, self)._setSize(newsize)return# the rest is for changing the size of an allocated-but-not-existing# partition, which I'm not sure is advisable if newsize > self.disk.size: raise ValueError("partition size would exceed disk size")@@ -829,14 +836,6 @@ class PartitionDevice(StorageDevice): unalignedMax = min(maxFormatSize, maxPartSize) if maxFormatSize else maxPartSize return self.alignTargetSize(unalignedMax)
- @property
- def currentSize(self):
if self.exists:return self._currentSizeelse:return 0- @property def resizable(self): return super(PartitionDevice, self).resizable and \ self.disk.type != 'dasd'
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py index 73ba645..6128886 100644 --- a/blivet/devices/storage.py +++ b/blivet/devices/storage.py @@ -22,8 +22,6 @@
import os import copy -import parted -import _ped import pyudev
from .. import errors @@ -38,6 +36,7 @@ import logging log = logging.getLogger("blivet")
from .device import Device +from .lib import LINUX_SECTOR_SIZE
class StorageDevice(Device): """ A generic storage device. @@ -105,7 +104,11 @@ class StorageDevice(Device): Device.__init__(self, name, parents=parents)
self._format = None
# The size will be overridden by a call to updateSize at the end of this# method for existing and active devices. self._size = Size(util.numeric_type(size))self._currentSize = self._size if self.exists else Size(0) self.major = util.numeric_type(major) self.minor = util.numeric_type(minor) self._serial = serial@@ -123,16 +126,8 @@ class StorageDevice(Device):
self.deviceLinks = []
if self.exists and flags.testing and not self._size:def read_int_from_sys(path):return int(open(path).readline().strip())device_root = "/sys/class/block/%s" % self.nameif os.path.exists("%s/queue" % device_root):sector_size = read_int_from_sys("%s/queue/logical_block_size"% device_root)size = read_int_from_sys("%s/size" % device_root)self._size = Size(size * sector_size)
if self.exists and self.status:self.updateSize() self._orig_size = self._size@@ -199,26 +194,6 @@ class StorageDevice(Device): """ True if this device, or any it requires, is encrypted. """ return self._encrypted or any(p.encrypted for p in self.parents)
- def _getPartedDevicePath(self):
return self.path- @property
- def partedDevice(self):
devicePath = self._getPartedDevicePath()if self.exists and self.status and not self._partedDevice:log.debug("looking up parted Device: %s", devicePath)# We aren't guaranteed to be able to get a device. In# particular, built-in USB flash readers show up as devices but# do not always have any media present, so parted won't be able# to find a device.try:self._partedDevice = parted.Device(path=devicePath)except (_ped.IOException, _ped.DeviceException):passreturn self._partedDevice- @property def raw_device(self): """ The device itself, or when encrypted, the backing device. """
@@ -281,12 +256,12 @@ class StorageDevice(Device): " format = %(format)s\n" " major = %(major)s minor = %(minor)s exists = %(exists)s" " protected = %(protected)s\n"
" sysfs path = %(sysfs)s partedDevice = %(partedDevice)s\n"
" sysfs path = %(sysfs)s\n" " target size = %(targetSize)s path = %(path)s\n" " format args = %(formatArgs)s originalFormat = %(origFmt)s" % {"uuid": self.uuid, "format": self.format, "size": self.size, "major": self.major, "minor": self.minor, "exists": self.exists,
"sysfs": self.sysfsPath, "partedDevice": self.partedDevice,
"sysfs": self.sysfsPath, "targetSize": self.targetSize, "path": self.path, "protected": self.protected, "formatArgs": self.formatArgs, "origFmt": self.originalFormat.type})@@ -410,9 +385,10 @@ class StorageDevice(Device): def _postSetup(self): """ Perform post-setup operations. """ udev.settle()
# we always probe since the device may not be set up when we want# information about itself._size = self.currentSize
self.updateSysfsPath()# the device may not be set up when we want information about itif self._size == Size(0):self.updateSize()# # teardown
@@ -487,9 +463,7 @@ class StorageDevice(Device): udev.settle()
# make sure that targetSize is updated to reflect the actual size
if self.resizable:self._partedDevice = Noneself._targetSize = self.currentSize
self.updateSize()# # destroy
@@ -535,12 +509,6 @@ class StorageDevice(Device):
def _getSize(self): """ Get the device's size, accounting for pending changes. """
if self.exists and not self.mediaPresent:return 0if self.exists and self.partedDevice:self._size = self.currentSizesize = self._size if self.exists and self.resizable: size = self.targetSize@@ -548,19 +516,41 @@ class StorageDevice(Device): return size
def _setSize(self, newsize):
""" Set the device's size to a new value. """
""" Set the device's size to a new value.This is not adequate to set up a resize as it does not set a newtarget size for the device.""" if not isinstance(newsize, Size): raise ValueError("new size must of type Size")
if self.maxSize and newsize > self.maxSize:
# only calculate these oncemax_size = self.maxSizemin_size = self.minSizeif max_size and newsize > max_size: raise errors.DeviceError("device cannot be larger than %s" %
(self.maxSize,), self.name)
max_size, self.name)elif min_size and newsize < min_size:raise errors.DeviceError("device cannot be smaller than %s" %min_size, self.name)self._size = newsizesize = property(lambda x: x._getSize(), lambda x, y: x._setSize(y), doc="The device's size, accounting for pending changes")
def readCurrentSize(self):
log_method_call(self, exists=self.exists, path=self.path,sysfsPath=self.sysfsPath)size = Size(0)if self.exists and os.path.exists(self.path) and \os.path.isdir(self.sysfsPath):blocks = int(util.get_sysfs_attr(self.sysfsPath, "size"))size = Size(blocks * LINUX_SECTOR_SIZE)return size@property def currentSize(self): """ The device's actual size, generally the size discovered by using
@@ -569,12 +559,17 @@ class StorageDevice(Device):
If the device does not exist, then the actual size is 0. """
size = 0if self.exists and self.partedDevice:size = Size(self.partedDevice.getLength(unit="B"))elif self.exists:size = self._sizereturn size
if self._currentSize == Size(0):self._currentSize = self.readCurrentSize()return self._currentSizedef updateSize(self):
""" Update size, currentSize, and targetSize to actual size. """self._currentSize = Size(0)new_size = self.currentSizeself._size = new_sizeself._targetSize = new_size # bypass setter checkslog.debug("updated %s size to %s (%s)", self.name, self.size, new_size)@property def minSize(self):
@@ -658,8 +653,6 @@ class StorageDevice(Device):
@property def model(self):
if not self._model:self._model = getattr(self.partedDevice, "model", "") return self._model@property
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 70b95f1..a70d7b9 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1085,6 +1085,7 @@ class DeviceTree(object): device = diskType(name, major=udev.device_get_major(info), minor=udev.device_get_minor(info),
model=udev.device_get_model(info), sysfsPath=sysfs_path, **kwargs) if diskType == DASDDevice:@@ -1203,9 +1204,7 @@ class DeviceTree(object): # The first step is to either look up or create the device # if device:
# we successfully looked up the device. skip to format handling.# first, grab the parted.Device while it's active_unused = device.partedDevice
pass elif udev.device_is_loop(info): log.info("%s is a loop device", name) device = self.addUdevLoopDevice(info)@@ -1529,6 +1528,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath()
lv_device.updateSize() lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name)@@ -1871,15 +1871,10 @@ class DeviceTree(object): kwargs["name"] = "luks-%s" % uuid elif format_type in formats.mdraid.MDRaidMember._udevTypes: # mdraid
try:kwargs["mdUuid"] = udev.device_get_md_uuid(info)except KeyError:log.warning("mdraid member %s has no md uuid", name)# reset the uuid to the member-specific value # this will be None for members of v0 metadata arrayskwargs["uuid"] = udev.device_get_md_device_uuid(info)
kwargs["uuid"] = info.get("ID_FS_UUID_SUB")kwargs["mdUuid"] = uuid
This chunk also looks unrelated to the rest of the commit.
On 06/29/2015 08:39 AM, Vratislav Podzimek wrote:
On Fri, 2015-06-26 at 16:54 -0500, David Lehman wrote:
Deleting a parted.Device causes parted to close its rw fd for the device, which triggers a change uevent on that device, which could in turn trigger any number of actions via udev rules. One example is when we reset a Blivet instance: All devices are deleted, including their parted.Device instances, which triggers a change uevent for every device. In response to these events, mdadm's udev rules activate all arrays on those devices. Activating devices -- even indirectly -- without cause, is not acceptable behavior for a storage library.
This also adds a trailing comma to 1-tuples in variable_copy arguments. In my testing, ('foo') is the string 'foo' -- not a tuple with lone element 'foo'.
(cherry picked from commit 73d9c995c8d46f1aa248d1ade3bbb1838653b6b0)
Resolves: rhbz#1069597
blivet/deviceaction.py | 9 ---- blivet/devices/btrfs.py | 3 ++ blivet/devices/container.py | 3 ++ blivet/devices/device.py | 2 +- blivet/devices/disk.py | 14 ++---- blivet/devices/dm.py | 3 +- blivet/devices/file.py | 9 ++++ blivet/devices/lib.py | 3 ++ blivet/devices/luks.py | 6 +-- blivet/devices/md.py | 19 ++++---- blivet/devices/nfs.py | 3 ++ blivet/devices/nodev.py | 2 + blivet/devices/partition.py | 41 +++++++++-------- blivet/devices/storage.py | 107 +++++++++++++++++++++----------------------- blivet/devicetree.py | 15 +++---- blivet/platform.py | 10 +++-- tests/storagetestcase.py | 5 +-- 17 files changed, 124 insertions(+), 130 deletions(-)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index a8cd489..bc7c1a0 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -28,7 +28,6 @@ from .util import get_current_entropy from .devices import StorageDevice from .devices import PartitionDevice, LVMLogicalVolumeDevice from .formats import getFormat, luks -from .storage_log import log_exception_info from parted import partitionFlag, PARTITION_LBA from .i18n import _, N_ from .callbacks import CreateFormatPreData, CreateFormatPostData @@ -344,14 +343,6 @@ class ActionDestroyDevice(DeviceAction): super(ActionDestroyDevice, self).execute(callbacks=None) self.device.destroy()
# Make sure libparted does not keep cached info for this device# and returns it when we create a new device with the same nameif self.device.partedDevice:try:self.device.partedDevice.removeFromCache()except Exception: # pylint: disable=broad-exceptlog_exception_info(fmt_str="failed to remove info for device %s from libparted cache", fmt_args=[self.device])def requires(self, action): """ Return True if self requires action.diff --git a/blivet/devices/btrfs.py b/blivet/devices/btrfs.py index 8e47708..eeb203f 100644 --- a/blivet/devices/btrfs.py +++ b/blivet/devices/btrfs.py @@ -61,6 +61,9 @@ class BTRFSDevice(StorageDevice): self.sysfsPath = self.parents[0].sysfsPath log.debug("%s sysfsPath set to %s", self.name, self.sysfsPath)
- def updateSize(self):
passdef _postCreate(self): super(BTRFSDevice, self)._postCreate() self.format.exists = Truediff --git a/blivet/devices/container.py b/blivet/devices/container.py index d8a1379..6e5683e 100644 --- a/blivet/devices/container.py +++ b/blivet/devices/container.py @@ -200,3 +200,6 @@ class ContainerDevice(StorageDevice):
if member in self.parents: self.parents.remove(member)
- def updateSize(self):
passdiff --git a/blivet/devices/device.py b/blivet/devices/device.py index 498fef4..1824f8c 100644 --- a/blivet/devices/device.py +++ b/blivet/devices/device.py @@ -99,7 +99,7 @@ class Device(util.ObjectID): """ return util.variable_copy(self, memo, omit=('_raidSet', 'node'),
shallow=('_partedDevice', '_partedPartition'))
shallow=('_partedPartition',)) def __repr__(self): s = ("%(type)s instance (%(id)s) --\n"diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py index 6a9a91a..d17e975 100644 --- a/blivet/devices/disk.py +++ b/blivet/devices/disk.py @@ -27,6 +27,7 @@ import block from .. import errors from .. import util from ..flags import flags +from ..size import Size from ..storage_log import log_method_call from .. import udev
@@ -89,8 +90,7 @@ class DiskDevice(StorageDevice):
def __repr__(self): s = StorageDevice.__repr__(self)
s += (" removable = %(removable)s partedDevice = %(partedDevice)r" %{"removable": self.removable, "partedDevice": self.partedDevice})
s += (" removable = %(removable)s" % {"removable": self.removable}) return s @property@@ -98,23 +98,15 @@ class DiskDevice(StorageDevice): if flags.testing: return True
if not self.partedDevice:return False# Some drivers (cpqarray <blegh>) make block device nodes for # controllers with no disks attached and then report a 0 size, # treat this as no media presentreturn self.partedDevice.getLength(unit="B") != 0
return self.exists and self.currentSize > Size(0) @property def description(self): return self.model
- @property
- def size(self):
""" The disk's size """return super(DiskDevice, self).sizedef _preDestroy(self): """ Destroy the device. """ log_method_call(self, self.name, status=self.status)diff --git a/blivet/devices/dm.py b/blivet/devices/dm.py index 57314bd..9326786 100644 --- a/blivet/devices/dm.py +++ b/blivet/devices/dm.py @@ -34,6 +34,7 @@ import logging log = logging.getLogger("blivet")
from .storage import StorageDevice +from .lib import LINUX_SECTOR_SIZE
class DMDevice(StorageDevice): """ A device-mapper device """ @@ -181,7 +182,7 @@ class DMLinearDevice(DMDevice): """ Open, or set up, a device. """ log_method_call(self, self.name, orig=orig, status=self.status, controllable=self.controllable)
slave_length = self.slave.partedDevice.length
slave_length = self.slave.currentSize / LINUX_SECTOR_SIZE dm.dm_create_linear(self.name, self.slave.path, slave_length, self.dmUuid)diff --git a/blivet/devices/file.py b/blivet/devices/file.py index da231c5..7aaf011 100644 --- a/blivet/devices/file.py +++ b/blivet/devices/file.py @@ -21,6 +21,7 @@ #
import os +import stat
from .. import util from ..storage_log import log_method_call @@ -80,6 +81,14 @@ class FileDevice(StorageDevice):
return os.path.normpath("%s%s" % (root, self.name))
- def _getSize(self):
size = self._sizeif self.exists and os.path.exists(self.path):st = os.stat(self.path)size = Size(st[stat.ST_SIZE])return sizedef _preSetup(self, orig=False): if self.format and self.format.exists and not self.format.status: self.format.device = self.pathdiff --git a/blivet/devices/lib.py b/blivet/devices/lib.py index c4996db..979dd6e 100644 --- a/blivet/devices/lib.py +++ b/blivet/devices/lib.py @@ -20,6 +20,9 @@ # from .. import errors from .. import udev +from ..size import Size
+LINUX_SECTOR_SIZE = Size(512)
def get_device_majors(): majors = {} diff --git a/blivet/devices/luks.py b/blivet/devices/luks.py index f02cd28..197926f 100644 --- a/blivet/devices/luks.py +++ b/blivet/devices/luks.py @@ -22,8 +22,6 @@ # device backend modules from ..devicelibs import crypto
-from ..size import Size
- import logging log = logging.getLogger("blivet")
@@ -63,10 +61,10 @@ class LUKSDevice(DMCryptDevice):
@property def size(self):
if not self.exists or not self.partedDevice:
if not self.exists: size = self.slave.size - crypto.LUKS_METADATA_SIZE else:
size = Size(self.partedDevice.getLength(unit="B"))
size = self.currentSize return size def _postCreate(self):diff --git a/blivet/devices/md.py b/blivet/devices/md.py index 8ce7854..33d91b5 100644 --- a/blivet/devices/md.py +++ b/blivet/devices/md.py @@ -28,7 +28,6 @@ from .. import util from ..flags import flags from ..storage_log import log_method_call from .. import udev -from ..size import Size from ..i18n import P_
import logging @@ -81,15 +80,15 @@ class MDRaidArrayDevice(ContainerDevice): self._memberDevices = 0 # the number of active (non-spare) members self._totalDevices = 0 # the total number of members
if level == "container":self._type = "mdcontainer"self.level = levelsuper(MDRaidArrayDevice, self).__init__(name, fmt=fmt, uuid=uuid, exists=exists, size=size, parents=parents, sysfsPath=sysfsPath)
if level == "container":self._type = "mdcontainer"self.level = levelThis chunk comes from a different commit and is unrelated to the rest of this commit, I think.
It's a followup to the original commit. The StorageDevice constructor now calls the size setter, which needs to know which type of md array it is.
# For new arrays check if we have enough members if (not exists and parents and len(parents) < self.level.min_members): for dev in self.parents:@@ -196,7 +195,7 @@ class MDRaidArrayDevice(ContainerDevice): if self.type == "mdbiosraidarray": return self._size
if not self.exists or not self.partedDevice:
if not self.exists or not self.mediaPresent: try: size = self.level.get_size([d.size for d in self.devices], self.memberDevices,@@ -207,11 +206,15 @@ class MDRaidArrayDevice(ContainerDevice): size = 0 log.debug("non-existent RAID %s size == %s", self.level, size) else:
size = Size(self.partedDevice.getLength(unit="B"))
size = self.currentSize log.debug("existing RAID %s size == %s", self.level, size) return sizedef updateSize(self):
# pylint: disable=bad-super-callsuper(ContainerDevice, self).updateSize()@property def description(self): if self.type == "mdcontainer":@@ -561,7 +564,7 @@ class MDRaidArrayDevice(ContainerDevice): elif flags.testing: return True else:
return self.partedDevice is not None
return super(MDRaidArrayDevice, self).mediaPresent @property def model(self):diff --git a/blivet/devices/nfs.py b/blivet/devices/nfs.py index 513a11c..da00114 100644 --- a/blivet/devices/nfs.py +++ b/blivet/devices/nfs.py @@ -69,6 +69,9 @@ class NFSDevice(StorageDevice, NetworkStorageDevice): """ Destroy the device. """ log_method_call(self, self.name, status=self.status)
- def updateSize(self):
pass@classmethod def isNameValid(cls, name): # Override StorageDevice.isNameValid to allow /diff --git a/blivet/devices/nodev.py b/blivet/devices/nodev.py index a66636c..1aee5d3 100644 --- a/blivet/devices/nodev.py +++ b/blivet/devices/nodev.py @@ -69,6 +69,8 @@ class NoDevice(StorageDevice): log_method_call(self, self.name, status=self.status) self._preDestroy()
def udpateSize(self):
passclass TmpFSDevice(NoDevice): """ A nodev device for a tmpfs filesystem. """
diff --git a/blivet/devices/partition.py b/blivet/devices/partition.py index 2701572..18add66 100644 --- a/blivet/devices/partition.py +++ b/blivet/devices/partition.py @@ -125,6 +125,12 @@ class PartitionDevice(StorageDevice):
self._bootable = False
# FIXME: Validate partType, but only if this is a new partition# Otherwise, overwrite it with the partition's type.self._partType = Noneself._partedPartition = Noneself._origPath = NoneStorageDevice.__init__(self, name, fmt=fmt, size=size, major=major, minor=minor, exists=exists, sysfsPath=sysfsPath, parents=parents)@@ -134,13 +140,6 @@ class PartitionDevice(StorageDevice): self.req_disks = list(self.parents) self.parents = []
# FIXME: Validate partType, but only if this is a new partition# Otherwise, overwrite it with the partition's type.self._partType = Noneself._partedPartition = Noneself._origPath = Noneself._currentSize = 0# FIXME: Validate size, but only if this is a new partition. # For existing partitions we will get the size from # parted.@@ -529,7 +528,6 @@ class PartitionDevice(StorageDevice): return
self._size = Size(self.partedPartition.getLength(unit="B"))
self._currentSize = self._size self.targetSize = self._size self._partType = self.partedPartition.type@@ -592,7 +590,6 @@ class PartitionDevice(StorageDevice): DeviceFormat(device=self.path, exists=True).destroy()
StorageDevice._postCreate(self)
self._currentSize = Size(self.partedPartition.getLength(unit="B")) def create(self): """ Create the device. """@@ -661,7 +658,7 @@ class PartitionDevice(StorageDevice): end=geometry.end)
self.disk.format.commit()
self._currentSize = Size(partition.getLength(unit="B"))
self.updateSize() def _preDestroy(self): StorageDevice._preDestroy(self)@@ -728,12 +725,16 @@ class PartitionDevice(StorageDevice): return size
def _setSize(self, newsize):
""" Set the device's size (for resize, not creation).
""" Set the device's size.Most devices have two scenarios for setting a size:
Arguments:
1) set actual/current size2) set target for resize
newsize -- the new size
Partitions have a third scenario:3) update size of an allocated-but-non-existent partition """ log_method_call(self, self.name, status=self.status, size=self._size, newsize=newsize)@@ -746,6 +747,12 @@ class PartitionDevice(StorageDevice): self.req_size = newsize self.req_base_size = newsize
if self.exists:super(PartitionDevice, self)._setSize(newsize)return# the rest is for changing the size of an allocated-but-not-existing# partition, which I'm not sure is advisable if newsize > self.disk.size: raise ValueError("partition size would exceed disk size")@@ -829,14 +836,6 @@ class PartitionDevice(StorageDevice): unalignedMax = min(maxFormatSize, maxPartSize) if maxFormatSize else maxPartSize return self.alignTargetSize(unalignedMax)
- @property
- def currentSize(self):
if self.exists:return self._currentSizeelse:return 0- @property def resizable(self): return super(PartitionDevice, self).resizable and \ self.disk.type != 'dasd'
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py index 73ba645..6128886 100644 --- a/blivet/devices/storage.py +++ b/blivet/devices/storage.py @@ -22,8 +22,6 @@
import os import copy -import parted -import _ped import pyudev
from .. import errors @@ -38,6 +36,7 @@ import logging log = logging.getLogger("blivet")
from .device import Device +from .lib import LINUX_SECTOR_SIZE
class StorageDevice(Device): """ A generic storage device. @@ -105,7 +104,11 @@ class StorageDevice(Device): Device.__init__(self, name, parents=parents)
self._format = None
# The size will be overridden by a call to updateSize at the end of this# method for existing and active devices. self._size = Size(util.numeric_type(size))self._currentSize = self._size if self.exists else Size(0) self.major = util.numeric_type(major) self.minor = util.numeric_type(minor) self._serial = serial@@ -123,16 +126,8 @@ class StorageDevice(Device):
self.deviceLinks = []
if self.exists and flags.testing and not self._size:def read_int_from_sys(path):return int(open(path).readline().strip())device_root = "/sys/class/block/%s" % self.nameif os.path.exists("%s/queue" % device_root):sector_size = read_int_from_sys("%s/queue/logical_block_size"% device_root)size = read_int_from_sys("%s/size" % device_root)self._size = Size(size * sector_size)
if self.exists and self.status:self.updateSize() self._orig_size = self._size@@ -199,26 +194,6 @@ class StorageDevice(Device): """ True if this device, or any it requires, is encrypted. """ return self._encrypted or any(p.encrypted for p in self.parents)
- def _getPartedDevicePath(self):
return self.path- @property
- def partedDevice(self):
devicePath = self._getPartedDevicePath()if self.exists and self.status and not self._partedDevice:log.debug("looking up parted Device: %s", devicePath)# We aren't guaranteed to be able to get a device. In# particular, built-in USB flash readers show up as devices but# do not always have any media present, so parted won't be able# to find a device.try:self._partedDevice = parted.Device(path=devicePath)except (_ped.IOException, _ped.DeviceException):passreturn self._partedDevice@property def raw_device(self): """ The device itself, or when encrypted, the backing device. """@@ -281,12 +256,12 @@ class StorageDevice(Device): " format = %(format)s\n" " major = %(major)s minor = %(minor)s exists = %(exists)s" " protected = %(protected)s\n"
" sysfs path = %(sysfs)s partedDevice = %(partedDevice)s\n"
" sysfs path = %(sysfs)s\n" " target size = %(targetSize)s path = %(path)s\n" " format args = %(formatArgs)s originalFormat = %(origFmt)s" % {"uuid": self.uuid, "format": self.format, "size": self.size, "major": self.major, "minor": self.minor, "exists": self.exists,
"sysfs": self.sysfsPath, "partedDevice": self.partedDevice,
"sysfs": self.sysfsPath, "targetSize": self.targetSize, "path": self.path, "protected": self.protected, "formatArgs": self.formatArgs, "origFmt": self.originalFormat.type})@@ -410,9 +385,10 @@ class StorageDevice(Device): def _postSetup(self): """ Perform post-setup operations. """ udev.settle()
# we always probe since the device may not be set up when we want# information about itself._size = self.currentSize
self.updateSysfsPath()# the device may not be set up when we want information about itif self._size == Size(0):self.updateSize() # # teardown@@ -487,9 +463,7 @@ class StorageDevice(Device): udev.settle()
# make sure that targetSize is updated to reflect the actual size
if self.resizable:self._partedDevice = Noneself._targetSize = self.currentSize
self.updateSize() # # destroy@@ -535,12 +509,6 @@ class StorageDevice(Device):
def _getSize(self): """ Get the device's size, accounting for pending changes. """
if self.exists and not self.mediaPresent:return 0if self.exists and self.partedDevice:self._size = self.currentSizesize = self._size if self.exists and self.resizable: size = self.targetSize@@ -548,19 +516,41 @@ class StorageDevice(Device): return size
def _setSize(self, newsize):
""" Set the device's size to a new value. """
""" Set the device's size to a new value.This is not adequate to set up a resize as it does not set a newtarget size for the device.""" if not isinstance(newsize, Size): raise ValueError("new size must of type Size")
if self.maxSize and newsize > self.maxSize:
# only calculate these oncemax_size = self.maxSizemin_size = self.minSizeif max_size and newsize > max_size: raise errors.DeviceError("device cannot be larger than %s" %
(self.maxSize,), self.name)
max_size, self.name)elif min_size and newsize < min_size:raise errors.DeviceError("device cannot be smaller than %s" %min_size, self.name)self._size = newsize size = property(lambda x: x._getSize(), lambda x, y: x._setSize(y), doc="The device's size, accounting for pending changes")def readCurrentSize(self):
log_method_call(self, exists=self.exists, path=self.path,sysfsPath=self.sysfsPath)size = Size(0)if self.exists and os.path.exists(self.path) and \os.path.isdir(self.sysfsPath):blocks = int(util.get_sysfs_attr(self.sysfsPath, "size"))size = Size(blocks * LINUX_SECTOR_SIZE)return size@property def currentSize(self): """ The device's actual size, generally the size discovered by using@@ -569,12 +559,17 @@ class StorageDevice(Device):
If the device does not exist, then the actual size is 0. """
size = 0if self.exists and self.partedDevice:size = Size(self.partedDevice.getLength(unit="B"))elif self.exists:size = self._sizereturn size
if self._currentSize == Size(0):self._currentSize = self.readCurrentSize()return self._currentSizedef updateSize(self):
""" Update size, currentSize, and targetSize to actual size. """self._currentSize = Size(0)new_size = self.currentSizeself._size = new_sizeself._targetSize = new_size # bypass setter checkslog.debug("updated %s size to %s (%s)", self.name, self.size, new_size) @property def minSize(self):@@ -658,8 +653,6 @@ class StorageDevice(Device):
@property def model(self):
if not self._model:self._model = getattr(self.partedDevice, "model", "") return self._model @propertydiff --git a/blivet/devicetree.py b/blivet/devicetree.py index 70b95f1..a70d7b9 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1085,6 +1085,7 @@ class DeviceTree(object): device = diskType(name, major=udev.device_get_major(info), minor=udev.device_get_minor(info),
model=udev.device_get_model(info), sysfsPath=sysfs_path, **kwargs) if diskType == DASDDevice:@@ -1203,9 +1204,7 @@ class DeviceTree(object): # The first step is to either look up or create the device # if device:
# we successfully looked up the device. skip to format handling.# first, grab the parted.Device while it's active_unused = device.partedDevice
pass elif udev.device_is_loop(info): log.info("%s is a loop device", name) device = self.addUdevLoopDevice(info)@@ -1529,6 +1528,7 @@ class DeviceTree(object):
if lv_device.status: lv_device.updateSysfsPath()
lv_device.updateSize() lv_info = udev.get_device(lv_device.sysfsPath) if not lv_info: log.error("failed to get udev data for lv %s", lv_device.name)@@ -1871,15 +1871,10 @@ class DeviceTree(object): kwargs["name"] = "luks-%s" % uuid elif format_type in formats.mdraid.MDRaidMember._udevTypes: # mdraid
try:kwargs["mdUuid"] = udev.device_get_md_uuid(info)except KeyError:log.warning("mdraid member %s has no md uuid", name)# reset the uuid to the member-specific value # this will be None for members of v0 metadata arrayskwargs["uuid"] = udev.device_get_md_device_uuid(info)
kwargs["uuid"] = info.get("ID_FS_UUID_SUB")kwargs["mdUuid"] = uuidThis chunk also looks unrelated to the rest of the commit.
Hmm, yeah. I guess this is from a followup to something else. I'll split it out into a separate commit that uses the rebase as "Related" since we won't be able to detect any existing md raid without this.
David
Works for me, thanks for the clarifications.
mediaPresent indicates whether a device node is backed by readable/writeable media. It is generally only meaningful for root devices (devices with no parents). There are only a few instances in which this is relevant: cdrom/dvd, card readers, md containers, and some goofy raid hardware that creates a zero-size block device node. If you need a general- purpose property to tell you if a device is available for general use, what you want is the device's status attribute.
(cherry picked from commit 0d7c5749f4a48700ccfb2294fcaa7feab9e7dd49)
Related: rhbz#1069597 --- blivet/devices/device.py | 5 ----- blivet/devices/md.py | 5 ----- blivet/devices/storage.py | 5 +++++ 3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/blivet/devices/device.py b/blivet/devices/device.py index 1824f8c..98db834 100644 --- a/blivet/devices/device.py +++ b/blivet/devices/device.py @@ -298,11 +298,6 @@ class Device(util.ObjectID):
return services
- @property - def mediaPresent(self): - """ True if this device contains usable media. """ - return True - @classmethod def isNameValid(cls, name): # pylint: disable=unused-argument """Is the device name valid for the device type?""" diff --git a/blivet/devices/md.py b/blivet/devices/md.py index 33d91b5..096975a 100644 --- a/blivet/devices/md.py +++ b/blivet/devices/md.py @@ -558,11 +558,6 @@ class MDRaidArrayDevice(ContainerDevice): # (the device node does not allow read / write calls) if self.type == "mdcontainer": return False - # BIOS RAID sets should show as present even when teared down - elif self.type == "mdbiosraidarray": - return True - elif flags.testing: - return True else: return super(MDRaidArrayDevice, self).mediaPresent
diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py index 6128886..b6ee4dc 100644 --- a/blivet/devices/storage.py +++ b/blivet/devices/storage.py @@ -582,6 +582,11 @@ class StorageDevice(Device): return self.alignTargetSize(self.format.maxSize) if self.resizable else self.currentSize
@property + def mediaPresent(self): + """ True if this device contains usable media. """ + return True + + @property def status(self): """ This device's status.
Also make sure _model and _vendor attrs are never set to None in the StorageDevice constructor.
(cherry picked from commit 067183942c97f432e739c979c4b1d7a9816eef06)
Related: rhbz#1069597 --- blivet/devices/disk.py | 2 +- blivet/devices/storage.py | 4 ++-- blivet/devicetree.py | 9 +++------ 3 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/blivet/devices/disk.py b/blivet/devices/disk.py index d17e975..3638f50 100644 --- a/blivet/devices/disk.py +++ b/blivet/devices/disk.py @@ -105,7 +105,7 @@ class DiskDevice(StorageDevice):
@property def description(self): - return self.model + return " ".join(s for s in (self.vendor, self.model) if s)
def _preDestroy(self): """ Destroy the device. """ diff --git a/blivet/devices/storage.py b/blivet/devices/storage.py index b6ee4dc..348eb65 100644 --- a/blivet/devices/storage.py +++ b/blivet/devices/storage.py @@ -112,8 +112,8 @@ class StorageDevice(Device): self.major = util.numeric_type(major) self.minor = util.numeric_type(minor) self._serial = serial - self._vendor = vendor - self._model = model + self._vendor = vendor or "" + self._model = model or "" self.bus = bus
self.protected = False diff --git a/blivet/devicetree.py b/blivet/devicetree.py index a70d7b9..915b94e 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1000,12 +1000,10 @@ class DeviceTree(object): serial = udev.device_get_serial(info) bus = udev.device_get_bus(info)
- # udev doesn't always provide a vendor. - vendor = udev.device_get_vendor(info) - if not vendor: - vendor = "" + vendor = util.get_sysfs_attr(sysfs_path, "device/vendor") + model = util.get_sysfs_attr(sysfs_path, "device/model")
- kwargs = { "serial": serial, "vendor": vendor, "bus": bus } + kwargs = { "serial": serial, "vendor": vendor, "model": model, "bus": bus } if udev.device_is_iscsi(info): diskType = iScsiDiskDevice initiator = udev.device_get_iscsi_initiator(info) @@ -1085,7 +1083,6 @@ class DeviceTree(object): device = diskType(name, major=udev.device_get_major(info), minor=udev.device_get_minor(info), - model=udev.device_get_model(info), sysfsPath=sysfs_path, **kwargs)
if diskType == DASDDevice:
anaconda-patches@lists.fedorahosted.org