Patrick Williams | 56b44a9 | 2024-01-19 08:49:29 -0600 | [diff] [blame] | 1 | From 34f4321dfce28697f830639260076e60d765698b Mon Sep 17 00:00:00 2001 |
| 2 | From: Trevor Woerner <twoerner@gmail.com> |
| 3 | Date: Fri, 12 Jan 2024 01:16:19 -0500 |
| 4 | Subject: [PATCH 2/3] CLI.py: fix block device udev race condition |
| 5 | |
| 6 | We are encouraged to add a udev rule to change a block device's |
| 7 | bdi/max_ratio to '1' and queue/scheduler to 'none', which I did. |
| 8 | So 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 | |
| 15 | The strange part is that sometimes it doesn't report a problem and |
| 16 | sometimes it does, even if the block device is left plugged in continuously |
| 17 | between multiple bmaptool invocations. |
| 18 | |
| 19 | In all of my tests the bdi/max_ratio is always okay, but the |
| 20 | queue/scheduler would sometimes be reported as being the default scheduler, |
| 21 | not the one the udev rule was setting (none). Yet no matter how many times |
| 22 | I would read the file outside of bmaptool it always would be set to the |
| 23 | correct scheduler. |
| 24 | |
| 25 | It turns out that opening a block device in "wb+" mode, which is what |
| 26 | bmaptool is doing at one point, causes the block device to act as though |
| 27 | it was just inserted, giving it the default settings, then causing udev to |
| 28 | trigger to switch it to the requested settings. However, if udev doesn't |
| 29 | finish before bmaptool reads the scheduler value there's a chance it will |
| 30 | read the pre-udev value, not the post-udev value, even though the block |
| 31 | device was never physically removed and re-inserted. |
| 32 | |
| 33 | bmaptool was opening every file, then checking for block devices and |
| 34 | if found, closing then re-opening the block devices via a special |
| 35 | block-opening helper function. This patch re-organizes the code to only |
| 36 | open block devices once using the special block-opening helper function |
| 37 | that does not open block devices in "wb+" mode. |
| 38 | |
| 39 | Upstream-Status: Submitted [https://github.com/intel/bmap-tools/pull/130] |
| 40 | Signed-off-by: Trevor Woerner <twoerner@gmail.com> |
| 41 | --- |
| 42 | bmaptools/CLI.py | 14 +++++++------- |
| 43 | 1 file changed, 7 insertions(+), 7 deletions(-) |
| 44 | |
| 45 | diff --git a/bmaptools/CLI.py b/bmaptools/CLI.py |
| 46 | index 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 | -- |
| 82 | 2.43.0.76.g1a87c842ece3 |
| 83 | |