Fix dual-booting (#1250)
# Fixes * Optimized partition lookups * Fixed re-use of partition UUID's * `BlockDevice().get_partition()` now supports looking up both `PARTUUID` and `UUID` for a partition under itself * Partitions listed in `--disk-layout` that doesn't have a PARTUUID/UUID should no longer cause an exception, but instead logs a warning and they will simply be ignored * `Filesystem().add_partition()` now handles `DiskError` raised by `partition.part_uuid` * Fixed issue on normal partitions where the device was not properly frozen in `lambda` calls, meaning two or more mount-points shared the same `device_instance`. * Lowered global `DISK_RETRY_ATTEMPTS` to 5, as the timeouts are linear *(`range(DISK_RETRY_ATTEMPTS) * DISK_TIMEOUTS`)*
This commit is contained in:
parent
870da403e7
commit
9b3db344ab
|
|
@ -289,19 +289,27 @@ class BlockDevice:
|
||||||
def flush_cache(self) -> None:
|
def flush_cache(self) -> None:
|
||||||
self.part_cache = {}
|
self.part_cache = {}
|
||||||
|
|
||||||
def get_partition(self, uuid :str) -> Partition:
|
def get_partition(self, uuid :Optional[str] = None, partuuid :Optional[str] = None) -> Partition:
|
||||||
count = 0
|
if not uuid and not partuuid:
|
||||||
while count < 5:
|
raise ValueError(f"BlockDevice.get_partition() requires either a UUID or a PARTUUID for lookups.")
|
||||||
for partition_uuid, partition in self.partitions.items():
|
|
||||||
if partition.part_uuid.lower() == uuid.lower():
|
for count in range(storage.get('DISK_RETRY_ATTEMPTS', 5)):
|
||||||
return partition
|
for partition_index, partition in self.partitions.items():
|
||||||
else:
|
try:
|
||||||
log(f"uuid {uuid} not found. Waiting for {count +1} time",level=logging.DEBUG)
|
if uuid and partition.uuid.lower() == uuid.lower():
|
||||||
time.sleep(float(storage['arguments'].get('disk-sleep', 0.2)))
|
return partition
|
||||||
count += 1
|
elif partuuid and partition.part_uuid.lower() == partuuid.lower():
|
||||||
else:
|
return partition
|
||||||
log(f"Could not find {uuid} in disk after 5 retries",level=logging.INFO)
|
except DiskError as error:
|
||||||
print(f"Cache: {self.part_cache}")
|
# Most likely a blockdevice that doesn't support or use UUID's
|
||||||
print(f"Partitions: {self.partitions.items()}")
|
# (like Microsoft recovery partition)
|
||||||
print(f"UUID: {[uuid]}")
|
log(f"Could not get UUID/PARTUUID of {partition}: {error}", level=logging.DEBUG, fg="gray")
|
||||||
raise DiskError(f"New partition {uuid} never showed up after adding new partition on {self}")
|
pass
|
||||||
|
|
||||||
|
log(f"uuid {uuid} or {partuuid} not found. Waiting {storage.get('DISK_TIMEOUTS', 1) * count}s for next attempt",level=logging.DEBUG)
|
||||||
|
time.sleep(storage.get('DISK_TIMEOUTS', 1) * count)
|
||||||
|
|
||||||
|
log(f"Could not find {uuid}/{partuuid} in disk after 5 retries", level=logging.INFO)
|
||||||
|
log(f"Cache: {self.part_cache}")
|
||||||
|
log(f"Partitions: {self.partitions.items()}")
|
||||||
|
raise DiskError(f"New partition {uuid}/{partuuid} never showed up after adding new partition on {self}")
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,9 @@ class Filesystem:
|
||||||
print(_("Re-using partition instance: {}").format(partition_instance))
|
print(_("Re-using partition instance: {}").format(partition_instance))
|
||||||
partition['device_instance'] = partition_instance
|
partition['device_instance'] = partition_instance
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"{self}.load_layout() doesn't know how to continue without a new partition definition or a UUID ({partition.get('PARTUUID')}) on the device ({self.blockdevice.get_partition(uuid=partition.get('PARTUUID'))}).")
|
log(f"{self}.load_layout() doesn't know how to work without 'wipe' being set or UUID ({partition.get('PARTUUID')}) was given and found.", fg="yellow", level=logging.WARNING)
|
||||||
|
continue
|
||||||
|
# raise ValueError(f"{self}.load_layout() doesn't know how to continue without a new partition definition or a UUID ({partition.get('PARTUUID')}) on the device ({self.blockdevice.get_partition(uuid=partition.get('PARTUUID'))}).")
|
||||||
|
|
||||||
if partition.get('filesystem', {}).get('format', False):
|
if partition.get('filesystem', {}).get('format', False):
|
||||||
|
|
||||||
|
|
@ -206,7 +208,12 @@ class Filesystem:
|
||||||
def add_partition(self, partition_type :str, start :str, end :str, partition_format :Optional[str] = None) -> Partition:
|
def add_partition(self, partition_type :str, start :str, end :str, partition_format :Optional[str] = None) -> Partition:
|
||||||
log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)
|
log(f'Adding partition to {self.blockdevice}, {start}->{end}', level=logging.INFO)
|
||||||
|
|
||||||
previous_partition_uuids = {partition.part_uuid for partition in self.blockdevice.partitions.values()}
|
previous_partuuids = []
|
||||||
|
for partition in self.blockdevice.partitions.values():
|
||||||
|
try:
|
||||||
|
previous_partuuids.append(partition.part_uuid)
|
||||||
|
except DiskError:
|
||||||
|
pass
|
||||||
|
|
||||||
if self.mode == MBR:
|
if self.mode == MBR:
|
||||||
if len(self.blockdevice.partitions) > 3:
|
if len(self.blockdevice.partitions) > 3:
|
||||||
|
|
@ -220,36 +227,41 @@ class Filesystem:
|
||||||
log(f"Adding partition using the following parted command: {parted_string}", level=logging.DEBUG)
|
log(f"Adding partition using the following parted command: {parted_string}", level=logging.DEBUG)
|
||||||
|
|
||||||
if self.parted(parted_string):
|
if self.parted(parted_string):
|
||||||
count = 0
|
for count in range(storage.get('DISK_RETRY_ATTEMPTS', 3)):
|
||||||
while count < 10:
|
self.partprobe()
|
||||||
new_uuid = None
|
|
||||||
new_uuid_set = (previous_partition_uuids ^ {partition.part_uuid for partition in self.blockdevice.partitions.values()})
|
|
||||||
|
|
||||||
if len(new_uuid_set) > 0:
|
new_partition_uuids = []
|
||||||
new_uuid = new_uuid_set.pop()
|
for partition in self.blockdevice.partitions.values():
|
||||||
|
|
||||||
if new_uuid:
|
|
||||||
try:
|
try:
|
||||||
return self.blockdevice.get_partition(new_uuid)
|
new_partition_uuids.append(partition.part_uuid)
|
||||||
|
except DiskError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
new_partuuid_set = (set(previous_partuuids) ^ set(new_partition_uuids))
|
||||||
|
|
||||||
|
print(previous_partuuids, new_partition_uuids, new_partuuid_set)
|
||||||
|
|
||||||
|
if len(new_partuuid_set) and (new_partuuid := new_partuuid_set.pop()):
|
||||||
|
try:
|
||||||
|
return self.blockdevice.get_partition(partuuid=new_partuuid)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
log(f'Blockdevice: {self.blockdevice}', level=logging.ERROR, fg="red")
|
log(f'Blockdevice: {self.blockdevice}', level=logging.ERROR, fg="red")
|
||||||
log(f'Partitions: {self.blockdevice.partitions}', level=logging.ERROR, fg="red")
|
log(f'Partitions: {self.blockdevice.partitions}', level=logging.ERROR, fg="red")
|
||||||
log(f'Partition set: {new_uuid_set}', level=logging.ERROR, fg="red")
|
log(f'Partition set: {new_partuuid_set}', level=logging.ERROR, fg="red")
|
||||||
log(f'New UUID: {[new_uuid]}', level=logging.ERROR, fg="red")
|
log(f'New UUID: {[new_partuuid]}', level=logging.ERROR, fg="red")
|
||||||
log(f'get_partition(): {self.blockdevice.get_partition}', level=logging.ERROR, fg="red")
|
log(f'get_partition(): {self.blockdevice.get_partition}', level=logging.ERROR, fg="red")
|
||||||
raise err
|
raise err
|
||||||
else:
|
else:
|
||||||
count += 1
|
log(f"Could not get UUID for partition. Waiting {storage.get('DISK_TIMEOUTS', 1) * count}s before retrying.",level=logging.DEBUG)
|
||||||
log(f"Could not get UUID for partition. Waiting before retry attempt {count} of 10 ...",level=logging.DEBUG)
|
time.sleep(storage.get('DISK_TIMEOUTS', 1) * count)
|
||||||
time.sleep(float(storage['arguments'].get('disk-sleep', 0.2)))
|
|
||||||
else:
|
else:
|
||||||
log("Add partition is exiting due to excessive wait time", level=logging.ERROR, fg="red")
|
log("Add partition is exiting due to excessive wait time", level=logging.ERROR, fg="red")
|
||||||
raise DiskError(f"New partition never showed up after adding new partition on {self}.")
|
raise DiskError(f"New partition never showed up after adding new partition on {self}.")
|
||||||
|
|
||||||
# TODO: This should never be able to happen
|
# TODO: This should never be able to happen
|
||||||
log(f"Could not find the new PARTUUID after adding the partition.", level=logging.ERROR, fg="red")
|
log(f"Could not find the new PARTUUID after adding the partition.", level=logging.ERROR, fg="red")
|
||||||
log(f"Previous partitions: {previous_partition_uuids}", level=logging.ERROR, fg="red")
|
log(f"Previous partitions: {previous_partuuids}", level=logging.ERROR, fg="red")
|
||||||
log(f"New partitions: {(previous_partition_uuids ^ {partition.part_uuid for partition in self.blockdevice.partitions.values()})}", level=logging.ERROR, fg="red")
|
log(f"New partitions: {(previous_partuuids ^ {partition.part_uuid for partition in self.blockdevice.partitions.values()})}", level=logging.ERROR, fg="red")
|
||||||
raise DiskError(f"Could not add partition using: {parted_string}")
|
raise DiskError(f"Could not add partition using: {parted_string}")
|
||||||
|
|
||||||
def set_name(self, partition: int, name: str) -> bool:
|
def set_name(self, partition: int, name: str) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ class Partition:
|
||||||
|
|
||||||
except SysCallError as error:
|
except SysCallError as error:
|
||||||
# Not mounted anywhere most likely
|
# Not mounted anywhere most likely
|
||||||
log(f"Could not locate mount information for {self.path}: {error}", level=logging.DEBUG)
|
log(f"Could not locate mount information for {self.path}: {error}", level=logging.DEBUG, fg="grey")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
@ -216,7 +216,7 @@ class Partition:
|
||||||
if not self.partprobe():
|
if not self.partprobe():
|
||||||
raise DiskError(f"Could not perform partprobe on {self.device_path}")
|
raise DiskError(f"Could not perform partprobe on {self.device_path}")
|
||||||
|
|
||||||
time.sleep(max(0.1, storage['DISK_TIMEOUTS'] * i))
|
time.sleep(storage.get('DISK_TIMEOUTS', 1) * i)
|
||||||
|
|
||||||
partuuid = self._safe_uuid
|
partuuid = self._safe_uuid
|
||||||
if partuuid:
|
if partuuid:
|
||||||
|
|
|
||||||
|
|
@ -314,9 +314,11 @@ class Installer:
|
||||||
|
|
||||||
if partition.get('filesystem',{}).get('mount_options',[]):
|
if partition.get('filesystem',{}).get('mount_options',[]):
|
||||||
mount_options = ','.join(partition['filesystem']['mount_options'])
|
mount_options = ','.join(partition['filesystem']['mount_options'])
|
||||||
mount_queue[mountpoint] = lambda target=f"{self.target}{mountpoint}", options=mount_options: partition['device_instance'].mount(target, options)
|
mount_queue[mountpoint] = lambda instance=partition['device_instance'], target=f"{self.target}{mountpoint}", options=mount_options: instance.mount(target, options)
|
||||||
else:
|
else:
|
||||||
mount_queue[mountpoint] = lambda target=f"{self.target}{mountpoint}": partition['device_instance'].mount(target)
|
mount_queue[mountpoint] = lambda instance=partition['device_instance'], target=f"{self.target}{mountpoint}": instance.mount(target)
|
||||||
|
|
||||||
|
log(f"Using mount order: {list(sorted(mount_queue.items(), key=lambda item: item[0]))}", level=logging.INFO, fg="white")
|
||||||
|
|
||||||
# We mount everything by sorting on the mountpoint itself.
|
# We mount everything by sorting on the mountpoint itself.
|
||||||
for mountpoint, frozen_func in sorted(mount_queue.items(), key=lambda item: item[0]):
|
for mountpoint, frozen_func in sorted(mount_queue.items(), key=lambda item: item[0]):
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ storage: Dict[str, Any] = {
|
||||||
'MOUNT_POINT': '/mnt/archinstall',
|
'MOUNT_POINT': '/mnt/archinstall',
|
||||||
'ENC_IDENTIFIER': 'ainst',
|
'ENC_IDENTIFIER': 'ainst',
|
||||||
'DISK_TIMEOUTS' : 1, # seconds
|
'DISK_TIMEOUTS' : 1, # seconds
|
||||||
'DISK_RETRY_ATTEMPTS' : 20, # RETRY_ATTEMPTS * DISK_TIMEOUTS is used in disk operations
|
'DISK_RETRY_ATTEMPTS' : 5, # RETRY_ATTEMPTS * DISK_TIMEOUTS is used in disk operations
|
||||||
'CMD_LOCALE':{'LC_ALL':'C'}, # default locale for execution commands. Can be overriden with set_cmd_locale()
|
'CMD_LOCALE':{'LC_ALL':'C'}, # default locale for execution commands. Can be overriden with set_cmd_locale()
|
||||||
'CMD_LOCALE_DEFAULT':{'LC_ALL':'C'}, # should be the same as the former. Not be used except in reset_cmd_locale()
|
'CMD_LOCALE_DEFAULT':{'LC_ALL':'C'}, # should be the same as the former. Not be used except in reset_cmd_locale()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue