Repository: archlinux/archinstall

Issue:
Synchronize with udev before lsblk when appropriate
The following is from the _DESCRIPTION_ section of [lsblk(8)](https://man.archlinux.org/man/lsblk.8).

> Note that **lsblk** might be executed in time when **udev** does not have all information about recently added or modified devices yet. In this case it is recommended to use **udevadm settle** before **lsblk** to synchronize with udev.

Accordingly, `udevadm settle` should be used before `lslbk` in the scenario below.

https://github.com/archlinux/archinstall/blob/613bec6562c4d67c4c93d443e6d7e93fdb41ba66/archinstall/lib/disk/device_handler.py#L310-L319

Utilizing synchronization with udev should supplant these retires and sleeps.

https://github.com/archlinux/archinstall/blob/613bec6562c4d67c4c93d443e6d7e93fdb41ba66/archinstall/lib/disk/device_handler.py#L390-L392

https://github.com/archlinux/archinstall/blob/613bec6562c4d67c4c93d443e6d7e93fdb41ba66/archinstall/lib/disk/device_model.py#L1113-L1128


Discussion:

Resolving patch:
diff --git a/archinstall/lib/disk/device_handler.py b/archinstall/lib/disk/device_handler.py
--- a/archinstall/lib/disk/device_handler.py
+++ b/archinstall/lib/disk/device_handler.py
@@ -2,7 +2,6 @@
 
 import json
 import os
-import time
 import logging
 from pathlib import Path
 from typing import List, Dict, Any, Optional, TYPE_CHECKING
@@ -316,6 +315,9 @@ def format(
 			else:
 				self._perform_formatting(part_mod.safe_fs_type, part_mod.safe_dev_path)
 
+			# synchronize with udev before using lsblk
+			SysCommand('udevadm settle')
+
 			lsblk_info = self._fetch_part_info(part_mod.safe_dev_path)
 
 			part_mod.partn = lsblk_info.partn
@@ -384,19 +386,7 @@ def _setup_partition(
 		part_mod.dev_path = Path(partition.path)
 
 	def _fetch_part_info(self, path: Path) -> LsblkInfo:
-		attempts = 3
-		lsblk_info: Optional[LsblkInfo] = None
-
-		for attempt_nr in range(attempts):
-			time.sleep(attempt_nr + 1)
-			lsblk_info = get_lsblk_info(path)
-
-			if lsblk_info.partn and lsblk_info.partuuid and lsblk_info.uuid:
-				break
-
-		if not lsblk_info:
-			debug(f'Unable to get partition information: {path}')
-			raise DiskError(f'Unable to get partition information: {path}')
+		lsblk_info = get_lsblk_info(path)
 
 		if not lsblk_info.partn:
 			debug(f'Unable to determine new partition number: {path}\n{lsblk_info}')
diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py
--- a/archinstall/lib/disk/device_model.py
+++ b/archinstall/lib/disk/device_model.py
@@ -3,7 +3,6 @@
 import dataclasses
 import json
 import math
-import time
 import uuid
 from dataclasses import dataclass, field
 from enum import Enum
@@ -1103,39 +1102,34 @@ def _clean_field(name: str, clean_type: CleanType) -> str:
 			return name.replace('_percentage', '%').replace('_', '-')
 
 
-def _fetch_lsblk_info(dev_path: Optional[Union[Path, str]] = None, retry: int = 3) -> List[LsblkInfo]:
+def _fetch_lsblk_info(dev_path: Optional[Union[Path, str]] = None) -> List[LsblkInfo]:
 	fields = [_clean_field(f, CleanType.Lsblk) for f in LsblkInfo.fields()]
-	lsblk_fields = ','.join(fields)
-
-	if not dev_path:
-		dev_path = ''
-
-	for retry_attempt in range(retry + 1):
-		try:
-			result = SysCommand(f'lsblk --json -b -o+{lsblk_fields} {dev_path}').decode()
-			break
-		except SysCallError as err:
-			# Get the output minus the message/info from lsblk if it returns a non-zero exit code.
-			if err.worker:
-				err_str = err.worker.decode()
-				debug(f'Error calling lsblk: {err_str}')
-			else:
-				raise err
+	cmd = ['lsblk', '--json', '--bytes', '--output', '+' + ','.join(fields)]
+
+	if dev_path:
+		cmd.append(str(dev_path))
 
-			if retry_attempt == retry:
-				raise err
+	try:
+		result = SysCommand(cmd).decode()
+	except SysCallError as err:
+		# Get the output minus the message/info from lsblk if it returns a non-zero exit code.
+		if err.worker:
+			err_str = err.worker.decode()
+			debug(f'Error calling lsblk: {err_str}')
 
-			time.sleep(1)
+		if dev_path:
+			raise DiskError(f'Failed to read disk "{dev_path}" with lsblk')
+
+		raise err
 
 	try:
 		block_devices = json.loads(result)
-		blockdevices = block_devices['blockdevices']
-		return [LsblkInfo.from_json(device) for device in blockdevices]
 	except json.decoder.JSONDecodeError as err:
 		error(f"Could not decode lsblk JSON: {result}")
 		raise err
 
-	raise DiskError(f'Failed to read disk "{dev_path}" with lsblk')
+	blockdevices = block_devices['blockdevices']
+	return [LsblkInfo.from_json(device) for device in blockdevices]
 
 
 def get_lsblk_info(dev_path: Union[Path, str]) -> LsblkInfo:


Test patch: