sd_fusing.py: Invoke ioctl to reread partitions directly 81/311581/3
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 22 May 2024 12:57:56 +0000 (14:57 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 22 May 2024 21:46:48 +0000 (23:46 +0200)
This commit drops blockdev(8) in favor for invoking ioctl(2) directly,
to be able to catch EBUSY errors that happen to occur due to not yet
known kernel/udev timinig issue.

Change-Id: I105c445f9fdb3d1d2eee7ffd2de3f7ad04920f13
Signed-off-by: Karol Lewandowski <k.lewandowsk@samsung.com>
scripts/tizen/sd_fusing.py

index 3b58d748906a27e546a55ed96850fe995ae6c003..e7f580dad0bdfffb7bc853afa685df1295c3341a 100755 (executable)
@@ -5,6 +5,7 @@ from functools import reduce
 import argparse
 import atexit
 import errno
+import fcntl
 import logging
 import os
 import re
@@ -14,6 +15,7 @@ import subprocess
 import sys
 import tarfile
 import tempfile
+import time
 
 __version__ = "1.0.4"
 
@@ -23,6 +25,7 @@ File = ""
 Yes = False
 
 LOGGING_NOTICE = int((logging.INFO + logging.WARNING) / 2)
+BLKRRPART = 4703 # from linux/fs.h
 
 class DebugFormatter(logging.Formatter):
     def format(self, record):
@@ -790,15 +793,32 @@ def mkpart(args, target):
         logging.error(f"New partition table:\n" + str(target.label))
         sys.exit(1)
 
+    # Invoke ioctl directly as blockdev sometimes fails with EBUSY for no known reason (udev/kernel timing issue?)
+    wait_secs = 2
     logging.debug("Requesting kernel to re-read partition table:\n" + str(target.label))
-    argv = ['blockdev', '--rereadpt', Device]
-    logging.debug(" ".join(argv))
-    proc = subprocess.run(argv,
-                          stdout=None,
-                          stderr=None)
-    if proc.returncode != 0:
-        logging.error(f"Failed to request kernel to reread partition table on {Device}. (Insufficient permissions?)")
+    rereadpt_ok = False
+    rereadpt_err = f"Failed to request kernel to re-read partition table on {Device}"
+    for i in range(2):
+        try:
+            with os.open(Device, os.O_RDWR) as fd:
+                fcntl.ioctl(fd, BLKRRPART)
+                rereadpt_ok = True
+        except OSError as e:
+            if e.errno == errno.EBUSY:
+                logging.error(f"{rereadpt_err}: {e.strerror}. Retrying after {wait_secs}")
+                time.sleep(wait_secs)
+                continue
+            else:
+                logging.error(f"{rereadpt_err}: {e.strerror}")
+                sys.exit(1)
+    if not rereadpt_ok:
+        logging.error(f"{rereadpt_err}")
         sys.exit(1)
+    else:
+        logging.notice(f"Successfully re-read partition table on {Device}")
+
+    # Wait a bit to ensure new layout has propagated to userspace
+    time.sleep(wait_secs)
 
     if target.bootcode:
         logging.debug("Writing bootcode\n")