Skip to content

Commit 9c5034a

Browse files
authored
Merge pull request #1359 from sjg20/disk
udisks2: Be more tolerant of device-startup time
2 parents cecb82f + 6ab5163 commit 9c5034a

2 files changed

Lines changed: 52 additions & 14 deletions

File tree

labgrid/driver/usbstoragedriver.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class USBStorageDriver(Driver):
4545
)
4646
WAIT_FOR_MEDIUM_TIMEOUT = 10.0 # s
4747
WAIT_FOR_MEDIUM_SLEEP = 0.5 # s
48+
MOUNT_RETRIES = 5
4849

4950
def __attrs_post_init__(self):
5051
super().__attrs_post_init__()
@@ -77,15 +78,19 @@ def write_files(self, sources, target, partition, target_is_directory=True):
7778
Args:
7879
sources (List[str]): path(s) to the file(s) to be copied to the bound USB storage
7980
partition.
80-
target (str): target directory or file to copy to
81+
target (PurePath): target directory or file to copy to
8182
partition (int): mount the specified partition or None to mount the whole disk
8283
target_is_directory (bool): Whether target is a directory
84+
85+
Raises:
86+
Exception if anything goes wrong
8387
"""
88+
self._wait_for_medium(partition)
8489

8590
self._start_wrapper()
8691

8792
self.devpath = self._get_devpath(partition)
88-
mount_path = self.proxy.mount(self.devpath)
93+
mount_path = self.proxy.mount(self.devpath, self.MOUNT_RETRIES)
8994

9095
try:
9196
# (pathlib.PurePath(...) / "/") == "/", so we turn absolute paths into relative
@@ -222,10 +227,14 @@ def get_size(self, partition=None):
222227
getting the size of the root device (defaults to None)
223228
224229
Returns:
225-
int: size in bytes
230+
int: size in bytes, or 0 if the partition is not found
226231
"""
227232
args = ["cat", f"/sys/class/block/{self._get_devpath(partition)[5:]}/size"]
228-
size = subprocess.check_output(self.storage.command_prefix + args)
233+
try:
234+
size = subprocess.check_output(self.storage.command_prefix + args)
235+
except subprocess.CalledProcessError:
236+
# while the medium is getting ready, the file does not yet exist
237+
return 0
229238
try:
230239
return int(size) * 512
231240
except ValueError:

labgrid/util/agents/udisks2.py

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,32 @@ class UDisks2Device:
1515
def __init__(self, devpath):
1616
self._logger = logging.getLogger("Device: ")
1717
self.devpath = devpath
18-
client = UDisks.Client.new_sync(None)
18+
self.fs = None
19+
20+
def _setup(self):
21+
"""Try to find the devpath
1922
23+
Raises:
24+
ValueError: no udisks2 device or no filesystem found on devpath
25+
"""
26+
client = UDisks.Client.new_sync(None)
2027
manager = client.get_object_manager()
2128
for obj in manager.get_objects():
2229
block = obj.get_block()
2330
if not block:
2431
continue
2532

2633
device_path = block.get_cached_property("Device").get_bytestring().decode('utf-8')
27-
if device_path == devpath:
34+
if device_path == self.devpath:
2835
self.fs = obj.get_filesystem()
2936
if self.fs is None:
30-
raise ValueError(f"no filesystem found on {devpath}")
37+
raise ValueError(f"no filesystem found on {self.devpath}")
3138

3239
return
3340

34-
raise ValueError(f"No udisks2 device found for {devpath}")
41+
raise ValueError(f"No udisks2 device found for {self.devpath}")
3542

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

3946
try:
@@ -83,17 +90,39 @@ def unmount(self, lazy=False):
8390

8491
_devs = {}
8592

86-
def _get_udisks2_dev(devpath):
93+
def _get_udisks2_dev(devpath, retries):
94+
"""Try to get the udisks2 device
95+
96+
Args:
97+
devpath (str): Device name
98+
retries (int): Number of retries to allow
99+
100+
Raises:
101+
ValueError: Failed to obtain the device (e.g. does not exist)
102+
"""
87103
if devpath not in _devs:
88-
_devs[devpath] = UDisks2Device(devpath=devpath)
104+
dev = UDisks2Device(devpath=devpath)
105+
while True:
106+
try:
107+
dev._setup()
108+
break
109+
except ValueError as exc:
110+
if 'No udisks2 device' not in str(exc) or not retries:
111+
raise
112+
retries -= 1
113+
dev._logger.warning('udisks2: Retrying %s...', devpath)
114+
time.sleep(1)
115+
116+
# Success, so record the new device
117+
_devs[devpath] = dev
89118
return _devs[devpath]
90119

91-
def handle_mount(devpath):
92-
dev = _get_udisks2_dev(devpath)
120+
def handle_mount(devpath, retries=0):
121+
dev = _get_udisks2_dev(devpath, retries)
93122
return dev.mount()
94123

95124
def handle_unmount(devpath, lazy=False):
96-
dev = _get_udisks2_dev(devpath)
125+
dev = _get_udisks2_dev(devpath, 0)
97126
return dev.unmount(lazy=lazy)
98127

99128
methods = {

0 commit comments

Comments
 (0)