|
1 | 1 | # |
2 | 2 | # Copyright(c) 2019-2021 Intel Corporation |
3 | 3 | # Copyright(c) 2024 Huawei Technologies Co., Ltd. |
| 4 | +# Copyright(c) 2026 Unvertical |
4 | 5 | # SPDX-License-Identifier: BSD-3-Clause |
5 | 6 | # |
6 | 7 |
|
7 | 8 | import type_def.size as size |
8 | 9 | from core.test_run import TestRun |
| 10 | +from connection.utils.output import CmdException |
9 | 11 | from test_tools.common.linux_command import LinuxCommand |
10 | 12 |
|
11 | 13 |
|
| 14 | +# TODO: Remove it when it's fixed in uutils. |
| 15 | +# |
| 16 | +# The uutils coreutils `dd` (the default `dd` on some recent distros, e.g. |
| 17 | +# Ubuntu 26.04) does not page-align its O_DIRECT buffer to bdev block size. |
| 18 | +# As a result iflag=direct / oflag=direct transfers are unreliable. |
| 19 | +# On kernel 7.0 there is a strict BIO alignment check, which makes I/O |
| 20 | +# fail, sometimes in very nasty ways, especially in bio-based block device |
| 21 | +# drivers. |
| 22 | +# |
| 23 | +# As a temporary solution, fall back to gnu-coreutils. |
| 24 | +_gnu_dd_binary = {} |
| 25 | + |
| 26 | + |
| 27 | +def _resolve_gnu_dd(): |
| 28 | + executor = TestRun.executor |
| 29 | + cached = _gnu_dd_binary.get(id(executor)) |
| 30 | + if cached: |
| 31 | + return cached |
| 32 | + |
| 33 | + output = None |
| 34 | + for candidate in ("dd", "gnudd"): |
| 35 | + output = executor.run(f"{candidate} --version") |
| 36 | + version = f"{output.stdout}\n{output.stderr}".lower() |
| 37 | + if output.exit_code == 0 and "coreutils" in version and "uutils" not in version: |
| 38 | + _gnu_dd_binary[id(executor)] = candidate |
| 39 | + return candidate |
| 40 | + |
| 41 | + raise CmdException( |
| 42 | + "GNU dd not found. The system 'dd' is not GNU coreutils (likely a uutils " |
| 43 | + "reimplementation, which mis-aligns O_DIRECT buffers) and no 'gnudd' binary " |
| 44 | + "is available. Install the GNU coreutils package on the DUT (e.g. " |
| 45 | + "'gnu-coreutils', which provides the 'gnudd' binary).", |
| 46 | + output, |
| 47 | + ) |
| 48 | + |
| 49 | + |
12 | 50 | class Dd(LinuxCommand): |
13 | 51 | def __init__(self): |
14 | | - LinuxCommand.__init__(self, TestRun.executor, 'dd') |
| 52 | + LinuxCommand.__init__(self, TestRun.executor, _resolve_gnu_dd()) |
15 | 53 |
|
16 | 54 | def block_size(self, value: size.Size): |
17 | 55 | return self.set_param('bs', int(value.get_value())) |
|
0 commit comments