Skip to content

Commit

Permalink
Merge pull request #1359 from sjg20/disk
Browse files Browse the repository at this point in the history
udisks2: Be more tolerant of device-startup time
  • Loading branch information
Emantor committed Jun 26, 2024
2 parents cecb82f + 6ab5163 commit 9c5034a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 14 deletions.
17 changes: 13 additions & 4 deletions labgrid/driver/usbstoragedriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class USBStorageDriver(Driver):
)
WAIT_FOR_MEDIUM_TIMEOUT = 10.0 # s
WAIT_FOR_MEDIUM_SLEEP = 0.5 # s
MOUNT_RETRIES = 5

def __attrs_post_init__(self):
super().__attrs_post_init__()
Expand Down Expand Up @@ -77,15 +78,19 @@ def write_files(self, sources, target, partition, target_is_directory=True):
Args:
sources (List[str]): path(s) to the file(s) to be copied to the bound USB storage
partition.
target (str): target directory or file to copy to
target (PurePath): target directory or file to copy to
partition (int): mount the specified partition or None to mount the whole disk
target_is_directory (bool): Whether target is a directory
Raises:
Exception if anything goes wrong
"""
self._wait_for_medium(partition)

self._start_wrapper()

self.devpath = self._get_devpath(partition)
mount_path = self.proxy.mount(self.devpath)
mount_path = self.proxy.mount(self.devpath, self.MOUNT_RETRIES)

try:
# (pathlib.PurePath(...) / "/") == "/", so we turn absolute paths into relative
Expand Down Expand Up @@ -222,10 +227,14 @@ def get_size(self, partition=None):
getting the size of the root device (defaults to None)
Returns:
int: size in bytes
int: size in bytes, or 0 if the partition is not found
"""
args = ["cat", f"/sys/class/block/{self._get_devpath(partition)[5:]}/size"]
size = subprocess.check_output(self.storage.command_prefix + args)
try:
size = subprocess.check_output(self.storage.command_prefix + args)
except subprocess.CalledProcessError:
# while the medium is getting ready, the file does not yet exist
return 0
try:
return int(size) * 512
except ValueError:
Expand Down
49 changes: 39 additions & 10 deletions labgrid/util/agents/udisks2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,32 @@ class UDisks2Device:
def __init__(self, devpath):
self._logger = logging.getLogger("Device: ")
self.devpath = devpath
client = UDisks.Client.new_sync(None)
self.fs = None

def _setup(self):
"""Try to find the devpath
Raises:
ValueError: no udisks2 device or no filesystem found on devpath
"""
client = UDisks.Client.new_sync(None)
manager = client.get_object_manager()
for obj in manager.get_objects():
block = obj.get_block()
if not block:
continue

device_path = block.get_cached_property("Device").get_bytestring().decode('utf-8')
if device_path == devpath:
if device_path == self.devpath:
self.fs = obj.get_filesystem()
if self.fs is None:
raise ValueError(f"no filesystem found on {devpath}")
raise ValueError(f"no filesystem found on {self.devpath}")

return

raise ValueError(f"No udisks2 device found for {devpath}")
raise ValueError(f"No udisks2 device found for {self.devpath}")

def mount(self, readonly=False):
def mount(self, readonly=False, retries=0):
opts = GLib.Variant('a{sv}', {'options': GLib.Variant('s', 'ro' if readonly else 'rw')})

try:
Expand Down Expand Up @@ -83,17 +90,39 @@ def unmount(self, lazy=False):

_devs = {}

def _get_udisks2_dev(devpath):
def _get_udisks2_dev(devpath, retries):
"""Try to get the udisks2 device
Args:
devpath (str): Device name
retries (int): Number of retries to allow
Raises:
ValueError: Failed to obtain the device (e.g. does not exist)
"""
if devpath not in _devs:
_devs[devpath] = UDisks2Device(devpath=devpath)
dev = UDisks2Device(devpath=devpath)
while True:
try:
dev._setup()
break
except ValueError as exc:
if 'No udisks2 device' not in str(exc) or not retries:
raise
retries -= 1
dev._logger.warning('udisks2: Retrying %s...', devpath)
time.sleep(1)

# Success, so record the new device
_devs[devpath] = dev
return _devs[devpath]

def handle_mount(devpath):
dev = _get_udisks2_dev(devpath)
def handle_mount(devpath, retries=0):
dev = _get_udisks2_dev(devpath, retries)
return dev.mount()

def handle_unmount(devpath, lazy=False):
dev = _get_udisks2_dev(devpath)
dev = _get_udisks2_dev(devpath, 0)
return dev.unmount(lazy=lazy)

methods = {
Expand Down

0 comments on commit 9c5034a

Please sign in to comment.