blob: ea2749a26432b06e0cbe02b7c62063f6fca9c5a1 [file] [log] [blame]
Patrick Williams56b44a92024-01-19 08:49:29 -06001From 34f4321dfce28697f830639260076e60d765698b Mon Sep 17 00:00:00 2001
2From: Trevor Woerner <twoerner@gmail.com>
3Date: Fri, 12 Jan 2024 01:16:19 -0500
4Subject: [PATCH 2/3] CLI.py: fix block device udev race condition
5
6We are encouraged to add a udev rule to change a block device's
7bdi/max_ratio to '1' and queue/scheduler to 'none', which I did.
8So I was surprised when, about 50% of the time, I kept seeing:
9
10 ...
11 bmaptool: info: failed to enable I/O optimization, expect suboptimal speed (reason: cannot switch to the 'none' I/O scheduler: 'bfq' in use. [Errno 13] Permission denied: '/sys/dev/block/8:160/queue/scheduler')
12 bmaptool: info: You may want to set these I/O optimizations through a udev rule like this:
13 ...
14
15The strange part is that sometimes it doesn't report a problem and
16sometimes it does, even if the block device is left plugged in continuously
17between multiple bmaptool invocations.
18
19In all of my tests the bdi/max_ratio is always okay, but the
20queue/scheduler would sometimes be reported as being the default scheduler,
21not the one the udev rule was setting (none). Yet no matter how many times
22I would read the file outside of bmaptool it always would be set to the
23correct scheduler.
24
25It turns out that opening a block device in "wb+" mode, which is what
26bmaptool is doing at one point, causes the block device to act as though
27it was just inserted, giving it the default settings, then causing udev to
28trigger to switch it to the requested settings. However, if udev doesn't
29finish before bmaptool reads the scheduler value there's a chance it will
30read the pre-udev value, not the post-udev value, even though the block
31device was never physically removed and re-inserted.
32
33bmaptool was opening every file, then checking for block devices and
34if found, closing then re-opening the block devices via a special
35block-opening helper function. This patch re-organizes the code to only
36open block devices once using the special block-opening helper function
37that does not open block devices in "wb+" mode.
38
39Upstream-Status: Submitted [https://github.com/intel/bmap-tools/pull/130]
40Signed-off-by: Trevor Woerner <twoerner@gmail.com>
41---
42 bmaptools/CLI.py | 14 +++++++-------
43 1 file changed, 7 insertions(+), 7 deletions(-)
44
45diff --git a/bmaptools/CLI.py b/bmaptools/CLI.py
46index 82303b7bc398..0a263f05cf43 100644
47--- a/bmaptools/CLI.py
48+++ b/bmaptools/CLI.py
49@@ -38,6 +38,7 @@ import tempfile
50 import traceback
51 import shutil
52 import io
53+import pathlib
54 from bmaptools import BmapCreate, BmapCopy, BmapHelpers, TransRead
55
56 VERSION = "3.7"
57@@ -440,17 +441,16 @@ def open_files(args):
58 # Try to open the destination file. If it does not exist, a new regular
59 # file will be created. If it exists and it is a regular file - it'll be
60 # truncated. If this is a block device, it'll just be opened.
61+ dest_is_blkdev = False
62 try:
63- dest_obj = open(args.dest, "wb+")
64+ if pathlib.Path(args.dest).is_block_device():
65+ dest_is_blkdev = True
66+ dest_obj = open_block_device(args.dest)
67+ else:
68+ dest_obj = open(args.dest, "wb+")
69 except IOError as err:
70 error_out("cannot open destination file '%s':\n%s", args.dest, err)
71
72- # Check whether the destination file is a block device
73- dest_is_blkdev = stat.S_ISBLK(os.fstat(dest_obj.fileno()).st_mode)
74- if dest_is_blkdev:
75- dest_obj.close()
76- dest_obj = open_block_device(args.dest)
77-
78 return (image_obj, dest_obj, bmap_obj, bmap_path, image_obj.size, dest_is_blkdev)
79
80
81--
822.43.0.76.g1a87c842ece3
83