sd_fusing.py: Invoke ioctl to reread partitions directly 81/311581/10
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 22 May 2024 12:57:56 +0000 (14:57 +0200)
committerJaehoon Chung <jh80.chung@samsung.com>
Fri, 31 May 2024 04:20:08 +0000 (04:20 +0000)
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.

This commit also drops sfdisk --no-reread flag, which affects issuing
ioctl to reread partition table _before_ actual repartitioning.  ioctl
to reread partition table after writing changes is invoked unconditionally
and can't be disabled.

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

index a564c2f..8aafc8a 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"
 
@@ -24,6 +26,7 @@ Yes = False
 SuperDelivered = False
 
 LOGGING_NOTICE = int((logging.INFO + logging.WARNING) / 2)
+BLKRRPART = 4703 # from linux/fs.h
 
 class DebugFormatter(logging.Formatter):
     def format(self, record):
@@ -780,7 +783,7 @@ def mkpart(args, target):
             sys.exit(1)
 
     logging.debug("New partition table:\n" + str(target.label))
-    argv = ['sfdisk', '--no-reread', '--wipe-partitions', 'always', Device]
+    argv = ['sfdisk', '--wipe-partitions', 'always', Device]
     logging.debug(" ".join(argv))
     proc = subprocess.run(argv,
                           stdout=None,
@@ -791,15 +794,29 @@ 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 = 3
     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(5):
+        try:
+            with open(Device, "wb") as f:
+                fcntl.ioctl(f.fileno(), BLKRRPART)
+                rereadpt_ok = True
+                break
+        except OSError as e:
+            if e.errno == errno.EBUSY:
+                logging.error(f"{rereadpt_err}: {e.strerror}. Retrying after {wait_secs} seconds")
+                time.sleep(wait_secs)
+            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}")
 
     if target.bootcode:
         logging.debug("Writing bootcode\n")