From fd325eb075f2941e354498027e58886141969cd8 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 22 May 2024 14:57:56 +0200 Subject: [PATCH] sd_fusing.py: Invoke ioctl to reread partitions directly 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 --- sd_fusing.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/sd_fusing.py b/sd_fusing.py index a564c2f..8aafc8a 100755 --- a/sd_fusing.py +++ b/sd_fusing.py @@ -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") -- 2.34.1