From a2204c305760f17e4d3797dbdab60180e2c14886 Mon Sep 17 00:00:00 2001 From: kernel-patches-daemon Date: Tue, 7 Jul 2026 08:33:46 +0000 Subject: [PATCH 1/6] adding ci files --- .github/dependabot.yml | 12 + .github/workflows/run-blktests.yml | 124 +++++++++++ CODE_OF_CONDUCT.md | 134 ++++++++++++ LICENSE | 339 +++++++++++++++++++++++++++++ LICENSES/GPL-2.0-or-later.txt | 339 +++++++++++++++++++++++++++++ README.md | 11 + 6 files changed, 959 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/run-blktests.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 LICENSE create mode 100644 LICENSES/GPL-2.0-or-later.txt create mode 100644 README.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..90e6b32b57671 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2026 Western Digital Corporation or its affiliates. +# +# Authors: Dennis Maisenbacher (dennis.maisenbacher@wdc.com) + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/run-blktests.yml b/.github/workflows/run-blktests.yml new file mode 100644 index 0000000000000..4413dc4e215d4 --- /dev/null +++ b/.github/workflows/run-blktests.yml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2025 Western Digital Corporation or its affiliates. +# +# Authors: Dennis Maisenbacher (dennis.maisenbacher@wdc.com) + +name: Run blktests + +on: + pull_request: + +concurrency: + group: ci-test-${{ github.ref_name }} + +env: + KERNEL_REF: "${{ github.event.pull_request.head.sha }}" + KERNEL_TREE: "https://github.com/${{ github.repository }}" + +#This workflow requires an actions-runner-controllers (ARC) to be active. +#The k8s cluster of this ARC needs KubeVirt to be installed. +jobs: + build-and-test-kernel: + #This step runs in a container in the k8s cluster + runs-on: arc-vm-linux-blktests + steps: + - name: Checkout blktests-ci + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 + with: + repository: linux-blktests/blktests-ci + path: blktests-ci + + - name: Build kernel and package it into a containerimage + run: | + cd blktests-ci/playbooks/roles/kernel-builder-k8s-job/templates + docker build \ + --build-arg KERNEL_TREE=${KERNEL_TREE} \ + --build-arg KERNEL_REF=${KERNEL_REF} \ + -t linux-kernel-containerdisk \ + -f Dockerfile.linux-kernel-containerdisk . 2>&1 | tee build.log + #Setting KERNEL_VERSION var which is latern needed for notifying the VM what kernel to pick up + cat build.log | grep KERNEL_VERSION | awk '{print $3}' | grep KERNEL_VERSION >> $GITHUB_ENV + + - name: Push the new Fedora containerimage with the freshly build kernel + run: | + docker tag linux-kernel-containerdisk registry-service.docker-registry.svc.cluster.local/linux-kernel-containerdisk:${KERNEL_VERSION} + docker push registry-service.docker-registry.svc.cluster.local/linux-kernel-containerdisk:${KERNEL_VERSION} + + - name: Run in VM + uses: ./blktests-ci/.github/actions/kubevirt-action + with: + host_devices: "nvme-wdc-zn540,nvme-wdc-sn640" + kernel_version: ${{ env.KERNEL_VERSION }} + vm_artifact_upload_dir: blktests/results + run_cmds: | + #Print VM debug info + uname -a + cat /etc/os-release + lsblk + + #Install build dependencies for blktests + sudo dnf install -y gcc \ + clang \ + make \ + util-linux \ + llvm \ + gawk \ + fio \ + udev \ + kmod \ + coreutils \ + gcc \ + gzip \ + e2fsprogs \ + xfsprogs \ + f2fs-tools \ + btrfs-progs \ + device-mapper-multipath \ + blktrace \ + kernel-headers \ + liburing \ + liburing-devel \ + nbd \ + device-mapper \ + ktls-utils \ + dosfstools \ + bc \ + libnl3-cli \ + cryptsetup \ + sg3_utils \ + pciutils \ + unzip \ + jq \ + nvme-cli \ + git \ + wget \ + pkgconf \ + libudev-devel + + git clone https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git + cd mdadm + git checkout d764c4829947923142a83251296d04edaee7d2f7 + make -j$(nproc) + sudo make install + + cd - + git clone https://github.com/linux-blktests/blktests.git + + cd blktests + git checkout ci + make + + #ATTENTION! This section formats all available NVMe devices. Be careful when changing the `runs-on` tag! + #This step runs in a VM with the previously compiled kernel in the k8s cluster + + ./contrib/run_ci https://github.com/linux-blktests/blktests-ci-conditions/raw/main + + # Mark blktests completion for KPD report + echo "KPD: blktests completed" + + # Output failures for KPD report + test -f all_failures && echo "KPD: Failures:" && cat all_failures + + test -f all_failures && exit 1 + exit 0 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..4edb70c22d479 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +opensource@wdc.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000..d159169d10508 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSES/GPL-2.0-or-later.txt b/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 0000000000000..d159169d10508 --- /dev/null +++ b/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000000000..339ce7da25ed4 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ + + +# blktests-kpd-ci +This is a collection of GitHub actions workflow scripts for Continuous +Integration (CI) of Linux kernel using blktests. The scripts are intended to be +triggered by [Kernel Patches Daemon](https://github.com/kernel-patches/kernel-patches-daemon). +To use the scripts, specify this repository and the main branch as "ci_repo" and +"ci_branch" parameters respectively in the Kernel Patches Daemon config file. From df1004a7d00d1614b9bc965dbb46ac391cc2139d Mon Sep 17 00:00:00 2001 From: Leonid Ravich Date: Tue, 30 Jun 2026 08:34:27 +0000 Subject: [PATCH 2/6] crypto: skcipher - add per-request data_unit_size Add a data_unit_size field to struct skcipher_request. When non-zero, the request covers cryptlen / data_unit_size data units that share one starting IV; per-unit IVs are derived from the request IV as a wide data-unit-number counter (the convention also used by blk-crypto for inline encryption). cryptlen must be a positive multiple of data_unit_size. The field is honoured by an skcipher that understands data units -- an instance of the dun(...) template (added next), or a driver that handles a whole multi-DU request natively. A plain skcipher ignores it, so the field is inert for every existing caller; the core en/decrypt path is unchanged. skcipher_request_set_tfm() and the on-stack request initialiser reset it to 0 so a reused request defaults to single-DU. Signed-off-by: Leonid Ravich --- include/crypto/skcipher.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index 4efe2ca8c4d10..1121be80cb536 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -31,6 +31,13 @@ struct scatterlist; /** * struct skcipher_request - Symmetric key cipher request * @cryptlen: Number of bytes to encrypt or decrypt + * @data_unit_size: Size in bytes of each data unit, or 0 for a + * single-data-unit request (the default). When non-zero, + * must be a multiple of the cipher block size, @cryptlen must + * be a positive multiple of it, and per-DU IVs are derived from + * @iv as a wide counter (the data-unit-number convention); the + * counter width and endianness are chosen by the consumer (e.g. + * the dun() template's second parameter). * @iv: Initialisation Vector * @src: Source SG list * @dst: Destination SG list @@ -39,6 +46,7 @@ struct scatterlist; */ struct skcipher_request { unsigned int cryptlen; + unsigned int data_unit_size; u8 *iv; @@ -225,6 +233,7 @@ struct lskcipher_alg { struct skcipher_request *name = \ (((struct skcipher_request *)__##name##_desc)->base.tfm = \ crypto_sync_skcipher_tfm((_tfm)), \ + ((struct skcipher_request *)__##name##_desc)->data_unit_size = 0, \ (void *)__##name##_desc) /** @@ -819,6 +828,8 @@ static inline void skcipher_request_set_tfm(struct skcipher_request *req, struct crypto_skcipher *tfm) { req->base.tfm = crypto_skcipher_tfm(tfm); + /* Reused requests default to single-data-unit. */ + req->data_unit_size = 0; } static inline void skcipher_request_set_sync_tfm(struct skcipher_request *req, @@ -937,5 +948,28 @@ static inline void skcipher_request_set_crypt( req->iv = iv; } +/** + * skcipher_request_set_data_unit_size() - submit as multiple data units + * @req: request handle + * @data_unit_size: data-unit size in bytes (a multiple of the cipher block + * size), or 0 to disable + * + * Process @req as @cryptlen / @data_unit_size data units sharing one starting + * @iv, with per-DU IVs derived by treating @iv as a wide counter (the data- + * unit-number convention). @cryptlen must be a positive multiple of + * @data_unit_size. This is honoured only by a tfm that understands data + * units -- an instance of the dun(...) template (which splits the request + * into one inner call per unit, with the counter endianness given as its + * second parameter), or a driver that consumes a whole multi-DU request + * natively, which rejects a request violating these constraints with -EINVAL. + * A plain skcipher ignores the field. + */ +static inline void +skcipher_request_set_data_unit_size(struct skcipher_request *req, + unsigned int data_unit_size) +{ + req->data_unit_size = data_unit_size; +} + #endif /* _CRYPTO_SKCIPHER_H */ From 5968e021f86179889bb27f86edcd68abdc2af6ab Mon Sep 17 00:00:00 2001 From: Leonid Ravich Date: Tue, 30 Jun 2026 08:34:28 +0000 Subject: [PATCH 3/6] crypto: dun - data-unit-number dispatch template Add a dun(...) skcipher template that wraps an inner skcipher whose IV is a wide data-unit-number counter (e.g. dun(xts(aes),le)). When the caller sets skcipher_request::data_unit_size, the template splits the request into cryptlen / data_unit_size sub-requests on the inner cipher, walking the IV +1 per unit. Each inner ->encrypt/->decrypt is a direct call, so only the outer dispatch into the crypto API is indirect -- the per-unit work is not. The second template parameter selects the counter endianness: dun(...,le) for a little-endian counter (dm-crypt plain64, blk-crypto inline encryption) and dun(...,be) for a big-endian one (dm-crypt plain64be). Those are the only two ways a per-unit IV relates to its neighbour by a +1 step; IV modes that are not such a counter are simply not wrapped. Like cryptd() and pcrypt(), dun() wraps an inner skcipher and changes only how the request is dispatched -- here, split across data units -- performing no cipher transform of its own. A dun() tfm exists solely for multi-DU dispatch, so a request with data_unit_size 0 is rejected with -EINVAL; a caller wanting plain single-DU encryption uses the inner skcipher. A hardware engine that consumes a whole multi-DU request in one pass registers its own dun(...) at a higher cra_priority and is selected automatically by the existing priority mechanism; no per-algorithm capability flag is needed. The generic template is sync-only (the split loop treats any non-zero inner return as terminal), so it resolves against a sync inner cipher (mask | CRYPTO_ALG_ASYNC); async is left to such native drivers. The inner IV must be a whole number of 64-bit limbs and no wider than 32 bytes: 16 covers xts(...), 32 covers the widest inline-encryption mode (Adiantum). Suggested-by: Herbert Xu Signed-off-by: Leonid Ravich --- crypto/Kconfig | 14 ++ crypto/Makefile | 1 + crypto/dun.c | 359 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 crypto/dun.c diff --git a/crypto/Kconfig b/crypto/Kconfig index f1e3721952731..b4dea7e7611be 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -728,6 +728,20 @@ config CRYPTO_XTS implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. +config CRYPTO_DUN + tristate "Data-unit-number (DUN) dispatch template" + select CRYPTO_SKCIPHER + select CRYPTO_MANAGER + help + dun(...) wraps an skcipher whose IV is a wide data-unit-number + counter (e.g. xts(aes)) and lets a caller submit several data units + sharing one starting IV in a single request, via + skcipher_request::data_unit_size. The counter endianness is the + second parameter: dun(xts(aes),le) or dun(xts(aes),be). The template + splits the request into one inner call per data unit; a hardware + driver may register a higher-priority dun(...) that handles the whole + request in one pass. The first user is dm-crypt. + endmenu menu "AEAD (authenticated encryption with associated data) ciphers" diff --git a/crypto/Makefile b/crypto/Makefile index 8386d55a9755e..87b7811cacf94 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_CRYPTO_CBC) += cbc.o obj-$(CONFIG_CRYPTO_CTS) += cts.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o +obj-$(CONFIG_CRYPTO_DUN) += dun.o obj-$(CONFIG_CRYPTO_CTR) += ctr.o obj-$(CONFIG_CRYPTO_XCTR) += xctr.o obj-$(CONFIG_CRYPTO_HCTR2) += hctr2.o diff --git a/crypto/dun.c b/crypto/dun.c new file mode 100644 index 0000000000000..4fcb81a025b95 --- /dev/null +++ b/crypto/dun.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dun: data-unit-number dispatch template for skcipher + * + * Wraps an inner skcipher (e.g. xts(aes)) and, when the caller sets + * skcipher_request::data_unit_size, splits the request into cryptlen / + * data_unit_size sub-requests, each unit's IV the previous one +1 -- the + * data-unit-number (DUN) convention. The second parameter selects the IV + * walk (see struct dun_mode): dun(xts(aes),le) or dun(xts(aes),be). + * + * Like cryptd()/pcrypt(), dun() only changes how a request is dispatched and + * performs no transform of its own; a native one-pass multi-DU driver wins by + * cra_priority. Callers that never set data_unit_size pay nothing. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Bounds the on-stack IV buffers: 16 covers xts(...), 32 covers Adiantum. */ +#define DUN_MAX_IVSIZE 32 + +/* + * A dun() mode is the rule for deriving each data unit's IV from the request's + * starting IV. @name is the template's second parameter; @iv_next advances the + * @ivsize-byte @iv in place to the next data unit. @ivsize_ok rejects IV sizes + * the walk can't handle. Add a row to dun_modes[] to support a new convention. + */ +struct dun_mode { + const char *name; + void (*iv_next)(u8 *iv, unsigned int ivsize); + bool (*ivsize_ok)(unsigned int ivsize); +}; + +struct dun_tfm_ctx { + struct crypto_skcipher *child; + const struct dun_mode *mode; +}; + +struct dun_inst_ctx { + struct crypto_skcipher_spawn spawn; + const struct dun_mode *mode; +}; + +struct dun_request_ctx { + /* Must be last; the child request is appended with its own reqsize. */ + struct skcipher_request subreq; +}; + +/* Little-endian counter: increment the IV per __le64 limb, low limb first. */ +static void dun_iv_next_le(u8 *iv, unsigned int ivsize) +{ + unsigned int i; + + for (i = 0; i < ivsize; i += sizeof(__le64)) { + __le64 limb; + u64 v; + + memcpy(&limb, iv + i, sizeof(limb)); + v = le64_to_cpu(limb) + 1; + limb = cpu_to_le64(v); + memcpy(iv + i, &limb, sizeof(limb)); + if (likely(v != 0)) + break; /* no carry into the next limb */ + } +} + +/* Big-endian counter: increment the IV byte-wise from the last byte. */ +static void dun_iv_next_be(u8 *iv, unsigned int ivsize) +{ + unsigned int i = ivsize; + + while (i--) { + if (likely(++iv[i])) + break; /* no carry into the next byte */ + } +} + +/* + * le requires this: it walks the IV in __le64 limbs, so the size must be a + * whole number of limbs. be increments byte-wise and would accept any size, + * but reuses the same check for a uniform value-space. + */ +static bool dun_ivsize_whole_limbs(unsigned int ivsize) +{ + return IS_ALIGNED(ivsize, sizeof(__le64)); +} + +static const struct dun_mode dun_modes[] = { + { "le", dun_iv_next_le, dun_ivsize_whole_limbs }, + { "be", dun_iv_next_be, dun_ivsize_whole_limbs }, +}; + +static const struct dun_mode *dun_find_mode(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dun_modes); i++) + if (!strcmp(name, dun_modes[i].name)) + return &dun_modes[i]; + return NULL; +} + +static int dun_setkey(struct crypto_skcipher *parent, const u8 *key, + unsigned int keylen) +{ + struct dun_tfm_ctx *ctx = crypto_skcipher_ctx(parent); + struct crypto_skcipher *child = ctx->child; + + crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + return crypto_skcipher_setkey(child, key, keylen); +} + +/* + * Run one inner ->crypt per data unit, walking the IV as a wide counter. + * @req->iv is never modified; the inner cipher only sees the iv_unit copy. + */ +static int dun_split(struct skcipher_request *req, + int (*crypt)(struct skcipher_request *)) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct dun_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + struct dun_request_ctx *rctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &rctx->subreq; + const unsigned int du = req->data_unit_size; + const unsigned int total = req->cryptlen; + const unsigned int ivsize = crypto_skcipher_ivsize(tfm); + const struct dun_mode *mode = ctx->mode; + bool inplace = req->src == req->dst; + struct scatter_walk src_walk, dst_walk; + struct scatterlist src_sg[2], dst_sg[2]; + u8 iv_ctr[DUN_MAX_IVSIZE]; + u8 iv_unit[DUN_MAX_IVSIZE]; + unsigned int off; + int err = 0; + + /* iv_ctr is the counter; iv_unit is a per-unit copy an inner may write + * back in place (e.g. xts, essiv), so the counter is never mutated. + */ + memcpy(iv_ctr, req->iv, ivsize); + + sg_init_table(src_sg, 2); + scatterwalk_start(&src_walk, req->src); + if (!inplace) { + sg_init_table(dst_sg, 2); + scatterwalk_start(&dst_walk, req->dst); + } + + skcipher_request_set_tfm(subreq, ctx->child); + skcipher_request_set_callback(subreq, skcipher_request_flags(req), + NULL, NULL); + + for (off = 0; off < total; off += du) { + struct scatterlist *s, *d; + + scatterwalk_get_sglist(&src_walk, src_sg); + scatterwalk_skip(&src_walk, du); + s = src_sg; + if (inplace) { + d = src_sg; + } else { + scatterwalk_get_sglist(&dst_walk, dst_sg); + scatterwalk_skip(&dst_walk, du); + d = dst_sg; + } + + memcpy(iv_unit, iv_ctr, ivsize); + skcipher_request_set_crypt(subreq, s, d, du, iv_unit); + err = crypt(subreq); + if (err) + break; + + mode->iv_next(iv_ctr, ivsize); + } + + return err; +} + +/* + * Validate a multi-DU request: non-zero cryptlen, and a data_unit_size that is + * set, a multiple of the block size, and divides cryptlen evenly. + */ +static int dun_check(struct skcipher_request *req) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + + if (!req->cryptlen || !req->data_unit_size || + !IS_ALIGNED(req->data_unit_size, crypto_skcipher_blocksize(tfm)) || + (req->cryptlen % req->data_unit_size)) + return -EINVAL; + return 0; +} + +static int dun_encrypt(struct skcipher_request *req) +{ + int err = dun_check(req); + + if (err) + return err; + return dun_split(req, crypto_skcipher_encrypt); +} + +static int dun_decrypt(struct skcipher_request *req) +{ + int err = dun_check(req); + + if (err) + return err; + return dun_split(req, crypto_skcipher_decrypt); +} + +static int dun_init_tfm(struct crypto_skcipher *tfm) +{ + struct skcipher_instance *inst = skcipher_alg_instance(tfm); + struct dun_inst_ctx *ictx = skcipher_instance_ctx(inst); + struct dun_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + struct crypto_skcipher *child; + + child = crypto_spawn_skcipher(&ictx->spawn); + if (IS_ERR(child)) + return PTR_ERR(child); + + ctx->child = child; + ctx->mode = ictx->mode; + crypto_skcipher_set_reqsize(tfm, + sizeof(struct dun_request_ctx) + + crypto_skcipher_reqsize(child)); + return 0; +} + +static void dun_exit_tfm(struct crypto_skcipher *tfm) +{ + struct dun_tfm_ctx *ctx = crypto_skcipher_ctx(tfm); + + crypto_free_skcipher(ctx->child); +} + +static void dun_free_instance(struct skcipher_instance *inst) +{ + struct dun_inst_ctx *ictx = skcipher_instance_ctx(inst); + + crypto_drop_skcipher(&ictx->spawn); + kfree(inst); +} + +static int dun_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct skcipher_alg_common *alg; + struct skcipher_instance *inst; + struct dun_inst_ctx *ictx; + const struct dun_mode *mode; + const char *cipher_name; + const char *mode_name; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask); + if (err) + return err; + + cipher_name = crypto_attr_alg_name(tb[1]); + if (IS_ERR(cipher_name)) + return PTR_ERR(cipher_name); + + /* Second parameter: the IV-walk mode (see dun_modes[]). */ + mode_name = crypto_attr_alg_name(tb[2]); + if (IS_ERR(mode_name)) + return PTR_ERR(mode_name); + mode = dun_find_mode(mode_name); + if (!mode) + return -EINVAL; + + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); + if (!inst) + return -ENOMEM; + ictx = skcipher_instance_ctx(inst); + ictx->mode = mode; + + /* + * Sync-only: the split loop can't drive an async (-EINPROGRESS) child, + * so resolve against a sync inner (mask | CRYPTO_ALG_ASYNC). + */ + err = crypto_grab_skcipher(&ictx->spawn, skcipher_crypto_instance(inst), + cipher_name, 0, mask | CRYPTO_ALG_ASYNC); + if (err) + goto err_free_inst; + + alg = crypto_spawn_skcipher_alg_common(&ictx->spawn); + + /* The mode must accept this IV size, and it must fit our buffers. */ + err = -EINVAL; + if (!alg->ivsize || alg->ivsize > DUN_MAX_IVSIZE || + !mode->ivsize_ok(alg->ivsize)) + goto err_free_inst; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, "dun(%s,%s)", + alg->base.cra_name, mode->name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "dun(%s,%s)", alg->base.cra_driver_name, + mode->name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + inst->alg.base.cra_priority = alg->base.cra_priority; + inst->alg.base.cra_blocksize = alg->base.cra_blocksize; + inst->alg.base.cra_alignmask = alg->base.cra_alignmask; + inst->alg.base.cra_ctxsize = sizeof(struct dun_tfm_ctx); + + inst->alg.ivsize = alg->ivsize; + inst->alg.chunksize = alg->chunksize; + inst->alg.min_keysize = alg->min_keysize; + inst->alg.max_keysize = alg->max_keysize; + + inst->alg.init = dun_init_tfm; + inst->alg.exit = dun_exit_tfm; + inst->alg.setkey = dun_setkey; + inst->alg.encrypt = dun_encrypt; + inst->alg.decrypt = dun_decrypt; + + inst->free = dun_free_instance; + + err = skcipher_register_instance(tmpl, inst); + if (err) { +err_free_inst: + dun_free_instance(inst); + } + return err; +} + +static struct crypto_template dun_tmpl = { + .name = "dun", + .create = dun_create, + .module = THIS_MODULE, +}; + +static int __init dun_module_init(void) +{ + return crypto_register_template(&dun_tmpl); +} + +static void __exit dun_module_exit(void) +{ + crypto_unregister_template(&dun_tmpl); +} + +module_init(dun_module_init); +module_exit(dun_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Data-unit-number dispatch template for skcipher"); +MODULE_ALIAS_CRYPTO("dun"); From 9e21cdc44e8811f9a1e11fcb8fbb2f289fbf577d Mon Sep 17 00:00:00 2001 From: Leonid Ravich Date: Tue, 30 Jun 2026 08:34:29 +0000 Subject: [PATCH 4/6] crypto: testmgr - test dun() dispatch For every ivsize-16 skcipher, wrap it in both a dun(,le) and a dun(,be) instance and cross-check each batched output against an independent N x single-DU reference run directly on the inner tfm (both keyed with one random key, the reference counter walked in the matching endianness), over a deliberately fragmented scatterlist whose entries do not align to the data-unit size. The two must produce byte-identical ciphertext; the batched ciphertext is then round-tripped and the caller IV checked unchanged. Testing both endiannesses exercises the be path independently of any in-tree consumer. Algorithms with no dun wrapper (ivsize != 16) are skipped; a genuine mismatch returns -EBADMSG. Signed-off-by: Leonid Ravich --- crypto/testmgr.c | 289 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 4958211fbfa93..d400823300fbe 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -3210,6 +3210,291 @@ static int test_skcipher(int enc, const struct cipher_test_suite *suite, return 0; } +/* Upper bound on the IVs the dun() template accepts (16: xts; 32: Adiantum). */ +#define TEST_MDU_MAX_IVSIZE 32 + +/* + * Increment an @ivsize-byte IV as a wide counter. Byte-wise with carry -- + * deliberately independent of crypto/dun.c's per-limb walk, so the two only + * agree if the carry is right. LE: byte 0 least significant; BE: last byte. + */ +static void test_mdu_iv_inc(u8 *iv, unsigned int ivsize, bool big_endian) +{ + int i; + + if (big_endian) { + for (i = ivsize - 1; i >= 0; i--) + if (++iv[i]) + break; + } else { + for (i = 0; i < (int)ivsize; i++) + if (++iv[i]) + break; + } +} + +/* + * Seed @iv so the low 64-bit limb is all-ones but its least-significant byte: + * the 2nd increment wraps the limb and carries into the next. LE limb is + * bytes [0,8); BE limb is the last 8 bytes. Bytes outside keep their value. + */ +static void test_mdu_iv_boundary(u8 *iv, unsigned int ivsize, bool big_endian) +{ + unsigned int i; + + if (big_endian) { + for (i = ivsize - 8; i < ivsize; i++) + iv[i] = 0xff; + iv[ivsize - 1] = 0xfe; + } else { + for (i = 0; i < 8; i++) + iv[i] = 0xff; + iv[0] = 0xfe; + } +} + +/* Encrypt one du_size block with a plain single-DU request (the reference). */ +static int test_mdu_ref_encrypt(struct crypto_skcipher *tfm, const u8 *in, + u8 *out, unsigned int du_size, const u8 *iv, + unsigned int ivsize) +{ + struct skcipher_request *req; + struct scatterlist sg_in; + DECLARE_CRYPTO_WAIT(wait); + u8 ivbuf[TEST_MDU_MAX_IVSIZE]; + int err; + + req = skcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) + return -ENOMEM; + memcpy(ivbuf, iv, ivsize); + memcpy(out, in, du_size); + sg_init_one(&sg_in, out, du_size); + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); + skcipher_request_set_crypt(req, &sg_in, &sg_in, du_size, ivbuf); + err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); + skcipher_request_free(req); + return err; +} + +/* + * Build an SG over @buf with du_size-unaligned entries, so the splitter's + * per-DU views cross SG entries and exercise the scatter_walk cursor. + */ +static void test_mdu_sg_fragment(struct scatterlist *sg, unsigned int nents, + u8 *buf, unsigned int total) +{ + unsigned int chunk = total / nents; + unsigned int off = 0, i; + + sg_init_table(sg, nents); + for (i = 0; i < nents; i++) { + unsigned int len = (i == nents - 1) ? total - off : chunk; + + sg_set_buf(&sg[i], buf + off, len); + off += len; + } +} + +#define TEST_MDU_NR_UNITS 4 +#define TEST_MDU_NR_FRAGS 5 +/* + * Verify batched dispatch on @mdu (a dun(,) tfm) is byte-equal + * to an independent N x single-DU reference on @inner with @big_endian-walked + * IVs, over a fragmented SG, then round-trips. Both tfms must share a key. + * @iv_orig is the ivsize-byte starting IV (the caller varies it to exercise + * both a random IV and one seeded to cross a carry boundary). + */ +static int test_skcipher_multi_du_one(struct crypto_skcipher *mdu, + struct crypto_skcipher *inner, + unsigned int du_size, bool big_endian, + const u8 *iv_orig) +{ + const char *driver = crypto_skcipher_driver_name(mdu); + const unsigned int total = du_size * TEST_MDU_NR_UNITS; + const unsigned int ivsize = crypto_skcipher_ivsize(mdu); + struct skcipher_request *req = NULL; + struct scatterlist sg[TEST_MDU_NR_FRAGS]; + DECLARE_CRYPTO_WAIT(wait); + u8 iv_work[TEST_MDU_MAX_IVSIZE], iv_ref[TEST_MDU_MAX_IVSIZE]; + u8 *plain = NULL, *buf = NULL, *ref = NULL; + unsigned int u; + int err; + + plain = kmalloc(total, GFP_KERNEL); + buf = kmalloc(total, GFP_KERNEL); + ref = kmalloc(total, GFP_KERNEL); + req = skcipher_request_alloc(mdu, GFP_KERNEL); + if (!plain || !buf || !ref || !req) { + err = -ENOMEM; + goto out; + } + + get_random_bytes(plain, total); + + /* Reference: per-DU single requests on the inner tfm, counter-walked IVs. */ + memcpy(iv_ref, iv_orig, ivsize); + for (u = 0; u < TEST_MDU_NR_UNITS; u++) { + err = test_mdu_ref_encrypt(inner, plain + u * du_size, + ref + u * du_size, du_size, iv_ref, + ivsize); + if (err) { + pr_err("alg: skcipher: %s multi-DU ref encrypt failed (du=%u): %d\n", + driver, du_size, err); + goto out; + } + test_mdu_iv_inc(iv_ref, ivsize, big_endian); + } + + /* Batched: one request over a fragmented SG. */ + memcpy(buf, plain, total); + memcpy(iv_work, iv_orig, ivsize); + test_mdu_sg_fragment(sg, TEST_MDU_NR_FRAGS, buf, total); + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); + skcipher_request_set_crypt(req, sg, sg, total, iv_work); + skcipher_request_set_data_unit_size(req, du_size); + err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); + if (err) { + pr_err("alg: skcipher: %s multi-DU encrypt failed (du=%u): %d\n", + driver, du_size, err); + goto out; + } + if (memcmp(buf, ref, total) != 0) { + pr_err("alg: skcipher: %s multi-DU ciphertext differs from single-DU reference (du=%u)\n", + driver, du_size); + err = -EBADMSG; + goto out; + } + /* req->iv must be unchanged after multi-DU dispatch. */ + if (memcmp(iv_work, iv_orig, ivsize) != 0) { + pr_err("alg: skcipher: %s multi-DU encrypt mutated caller IV (du=%u)\n", + driver, du_size); + err = -EBADMSG; + goto out; + } + + /* Round-trip the batched ciphertext back to plaintext. */ + test_mdu_sg_fragment(sg, TEST_MDU_NR_FRAGS, buf, total); + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); + skcipher_request_set_crypt(req, sg, sg, total, iv_work); + skcipher_request_set_data_unit_size(req, du_size); + err = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); + if (err) { + pr_err("alg: skcipher: %s multi-DU decrypt failed (du=%u): %d\n", + driver, du_size, err); + goto out; + } + if (memcmp(buf, plain, total) != 0) { + pr_err("alg: skcipher: %s multi-DU round-trip mismatch (du=%u)\n", + driver, du_size); + err = -EBADMSG; + } + +out: + skcipher_request_free(req); + kfree(ref); + kfree(buf); + kfree(plain); + return err; +} + +/* + * Cross-check the dun(,@endian) wrapper against @tfm over all du sizes. + * Returns 0 on success or skip (no wrapper / rejected key); -EBADMSG on a real + * mismatch. + */ +static int test_skcipher_multi_du_endian(struct crypto_skcipher *tfm, + const char *alg_name, + const char *endian, bool big_endian, + const u8 *keybuf, unsigned int keylen) +{ + static const unsigned int du_sizes[] = { 512, 1024, 2048, 4096 }; + char mdu_name[CRYPTO_MAX_ALG_NAME]; + struct crypto_skcipher *mdu; + unsigned int ivsize; + u8 iv[TEST_MDU_MAX_IVSIZE]; + unsigned int j; + int err; + + if (snprintf(mdu_name, sizeof(mdu_name), "dun(%s,%s)", alg_name, + endian) >= (int)sizeof(mdu_name)) + return 0; + + mdu = crypto_alloc_skcipher(mdu_name, 0, 0); + if (IS_ERR(mdu)) { + /* No dun wrapper (ivsize not a multiple of 8, or too wide): skip. */ + if (PTR_ERR(mdu) == -ENOENT || PTR_ERR(mdu) == -EINVAL) + return 0; + return PTR_ERR(mdu); + } + + ivsize = crypto_skcipher_ivsize(mdu); + if (ivsize > TEST_MDU_MAX_IVSIZE) { + err = 0; /* wider than we have buffers for: skip */ + goto out; + } + + err = crypto_skcipher_setkey(mdu, keybuf, keylen); + if (err) { + err = 0; /* weak/rejected key (e.g. XTS equal halves): skip */ + goto out; + } + + for (j = 0; j < ARRAY_SIZE(du_sizes); j++) { + /* A random starting IV. */ + get_random_bytes(iv, ivsize); + err = test_skcipher_multi_du_one(mdu, tfm, du_sizes[j], + big_endian, iv); + if (err) + break; + /* And one seeded to carry across a 64-bit limb / byte run. */ + get_random_bytes(iv, ivsize); + test_mdu_iv_boundary(iv, ivsize, big_endian); + err = test_skcipher_multi_du_one(mdu, tfm, du_sizes[j], + big_endian, iv); + if (err) + break; + cond_resched(); + } +out: + crypto_free_skcipher(mdu); + return err; +} + +/* + * Cross-check dun() dispatch against a single-DU reference, in both le and be, + * for every ivsize the template accepts (16: xts; 32: Adiantum). + */ +static int test_skcipher_multi_du(struct crypto_skcipher *tfm) +{ + const char *alg_name = crypto_skcipher_alg(tfm)->base.cra_name; + u8 keybuf[128]; + unsigned int keylen; + int err; + + /* Key the inner tfm; each dun() wrapper is keyed identically below. */ + keylen = crypto_skcipher_min_keysize(tfm); + if (keylen > sizeof(keybuf)) + return 0; /* unusually large key; skip rather than overflow */ + get_random_bytes(keybuf, keylen); + err = crypto_skcipher_setkey(tfm, keybuf, keylen); + if (err) + return 0; /* weak/rejected key (e.g. XTS equal halves): skip */ + + err = test_skcipher_multi_du_endian(tfm, alg_name, "le", false, + keybuf, keylen); + if (err) + return err; + return test_skcipher_multi_du_endian(tfm, alg_name, "be", true, + keybuf, keylen); +} + static int alg_test_skcipher(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { @@ -3258,6 +3543,10 @@ static int alg_test_skcipher(const struct alg_test_desc *desc, if (err) goto out; + err = test_skcipher_multi_du(tfm); + if (err) + goto out; + err = test_skcipher_vs_generic_impl(desc->generic_driver, req, tsgls); out: free_cipher_test_sglists(tsgls); From a05e48a3be21c4ad271992d9aff037ab5124d699 Mon Sep 17 00:00:00 2001 From: Leonid Ravich Date: Tue, 30 Jun 2026 08:34:30 +0000 Subject: [PATCH 5/6] dm crypt: batch a bio segment's sectors via dun() Submit one skcipher request per contiguous bio segment (a single bio_vec) with data_unit_size = cc->sector_size, instead of one request per sector. E.g. the default 512-byte sector with a 4 KiB bio_vec becomes one request of 8 data units; the crypto layer (the dun() template, or a native driver) walks the per-sector IV as a data-unit counter. Because a bio_vec is one contiguous segment, the request uses only the existing inline dmreq->sg_in[0]/sg_out[0] entry -- no per-bio scatterlist allocation, and no regression on small random I/O. crypt_alloc_tfms() wraps the skcipher in dun(,) when crypt_can_batch_dun() holds: an IV mode that is a data-unit counter (its crypt_iv_operations sets dun_endian to the counter endianness -- "le" for plain64, "be" for plain64be; non-counter modes such as lmk/tcw/eboiv leave it NULL and are excluded), single-tfm, non-aead, and sector_size 512 or iv_large_sectors so the per-unit IV step is exactly one. This is the same kind of name rewrite as essiv(), done in the one alloc helper so callers are unchanged. DM_CRYPT selects CRYPTO_DUN and dun() resolves against a sync inner cipher, so wrapping has no acceptable failure that the bare cipher would survive -- there is no fallback; any error propagates. (A config whose only xts provider is async with no generic CRYPTO_XTS would now fail to activate rather than silently run per-sector; generic xts is selected by the dependency chain, so this does not arise in practice.) crypt_convert_block_skcipher() handles both cases in one function: the length is crypt_skcipher_len() -- a whole contiguous segment when batching, else a single sector -- and data_unit_size is set unconditionally (a dun() tfm reads it; a plain skcipher ignores it). It advances the bio iterators itself (as the aead path already does) and reports the bytes processed, so crypt_convert() advances cc_sector / tag_offset uniformly via one helper, no per-case duplication. Verified byte-equivalent to the per-sector path: plain64 and plain64be dm-crypt with dun() produce ciphertext bit-identical to an unpatched kernel over a 256 MB device (xts-aes driving the split). Signed-off-by: Leonid Ravich --- drivers/md/Kconfig | 1 + drivers/md/dm-crypt.c | 208 +++++++++++++++++++++++++++++++++--------- 2 files changed, 166 insertions(+), 43 deletions(-) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index df27c7d066d23..f43c3adfe71de 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -299,6 +299,7 @@ config DM_CRYPT select CRC32 select CRYPTO select CRYPTO_CBC + select CRYPTO_DUN # multi-data-unit batching of contiguous sectors select CRYPTO_ESSIV select CRYPTO_LIB_AES select CRYPTO_LIB_MD5 # needed by lmk IV mode diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 608b617fb817f..44938223ad3ef 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -115,6 +115,13 @@ struct crypt_iv_operations { struct dm_crypt_request *dmreq); void (*post)(struct crypt_config *cc, u8 *iv, struct dm_crypt_request *dmreq); + + /* + * Counter endianness ("le"/"be") for IV modes whose per-sector IV is a + * data-unit-number counter (IV(s+i) == IV(s)+i), batchable via + * dun(,). NULL for non-counter modes (lmk, tcw, ...). + */ + const char *dun_endian; }; struct iv_benbi_private { @@ -151,6 +158,7 @@ enum cipher_flags { CRYPT_IV_LARGE_SECTORS, /* Calculate IV from sector_size, not 512B sectors */ CRYPT_ENCRYPT_PREPROCESS, /* Must preprocess data for encryption (elephant) */ CRYPT_KEY_MAC_SIZE_SET, /* The integrity_key_size option was used */ + CRYPT_MULTI_DATA_UNIT, /* Batch a bio segment's sectors per crypto request */ }; /* @@ -1018,15 +1026,19 @@ static const struct crypt_iv_operations crypt_iv_plain_ops = { }; static const struct crypt_iv_operations crypt_iv_plain64_ops = { - .generator = crypt_iv_plain64_gen + .generator = crypt_iv_plain64_gen, + .dun_endian = "le", }; static const struct crypt_iv_operations crypt_iv_plain64be_ops = { - .generator = crypt_iv_plain64be_gen + .generator = crypt_iv_plain64be_gen, + .dun_endian = "be", }; static const struct crypt_iv_operations crypt_iv_essiv_ops = { - .generator = crypt_iv_essiv_gen + .generator = crypt_iv_essiv_gen, + /* IV input is le64(sector); the salt-encrypt lives in essiv(). */ + .dun_endian = "le", }; static const struct crypt_iv_operations crypt_iv_benbi_ops = { @@ -1349,21 +1361,51 @@ static int crypt_convert_block_aead(struct crypt_config *cc, return r; } +/* + * Bytes to process in one skcipher request: a whole contiguous segment when + * batching (multi-data-unit), else one sector. 0 means an unusable + * (sub-sector / misaligned) segment. + */ +static unsigned int crypt_skcipher_len(struct crypt_config *cc, + const struct bio_vec *bv_in, + const struct bio_vec *bv_out) +{ + const unsigned int sector_size = cc->sector_size; + + if (test_bit(CRYPT_MULTI_DATA_UNIT, &cc->cipher_flags)) + return round_down(min(bv_in->bv_len, bv_out->bv_len), + sector_size); + + /* Reject unexpected unaligned bio. */ + if (unlikely(bv_in->bv_len & (sector_size - 1))) + return 0; + return sector_size; +} + +/* + * Encrypt/decrypt one bio segment (one sector, or a whole segment when + * batching) and report the bytes done in *out_processed. The integrity / + * preprocess / post handling is inert when batching (crypt_can_batch_dun() + * excludes those configs). + */ static int crypt_convert_block_skcipher(struct crypt_config *cc, struct convert_context *ctx, struct skcipher_request *req, - unsigned int tag_offset) + unsigned int tag_offset, + unsigned int *out_processed) { struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in); struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out); + const unsigned int sector_size = cc->sector_size; struct scatterlist *sg_in, *sg_out; struct dm_crypt_request *dmreq; u8 *iv, *org_iv, *tag_iv; __le64 *sector; + unsigned int len; int r = 0; - /* Reject unexpected unaligned bio. */ - if (unlikely(bv_in.bv_len & (cc->sector_size - 1))) + len = crypt_skcipher_len(cc, &bv_in, &bv_out); + if (unlikely(!len)) return -EIO; dmreq = dmreq_of_req(cc, req); @@ -1386,10 +1428,10 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc, sg_out = &dmreq->sg_out[0]; sg_init_table(sg_in, 1); - sg_set_page(sg_in, bv_in.bv_page, cc->sector_size, bv_in.bv_offset); + sg_set_page(sg_in, bv_in.bv_page, len, bv_in.bv_offset); sg_init_table(sg_out, 1); - sg_set_page(sg_out, bv_out.bv_page, cc->sector_size, bv_out.bv_offset); + sg_set_page(sg_out, bv_out.bv_page, len, bv_out.bv_offset); if (cc->iv_gen_ops) { /* For READs use IV stored in integrity metadata */ @@ -1410,7 +1452,9 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc, memcpy(iv, org_iv, cc->iv_size); } - skcipher_request_set_crypt(req, sg_in, sg_out, cc->sector_size, iv); + skcipher_request_set_crypt(req, sg_in, sg_out, len, iv); + /* A dun() tfm reads this; a plain skcipher ignores it (len is one sector). */ + skcipher_request_set_data_unit_size(req, sector_size); if (bio_data_dir(ctx->bio_in) == WRITE) r = crypto_skcipher_encrypt(req); @@ -1420,9 +1464,10 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc, if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post) cc->iv_gen_ops->post(cc, org_iv, dmreq); - bio_advance_iter(ctx->bio_in, &ctx->iter_in, cc->sector_size); - bio_advance_iter(ctx->bio_out, &ctx->iter_out, cc->sector_size); + bio_advance_iter(ctx->bio_in, &ctx->iter_in, len); + bio_advance_iter(ctx->bio_out, &ctx->iter_out, len); + *out_processed = len; return r; } @@ -1509,13 +1554,25 @@ static void crypt_free_req(struct crypt_config *cc, void *req, struct bio *base_ crypt_free_req_skcipher(cc, req, base_bio); } +/* + * Advance the IV-sector and integrity-tag cursors by @processed bytes; the + * bio iterators are advanced by the per-block helpers themselves. + */ +static void crypt_convert_advance(struct crypt_config *cc, + struct convert_context *ctx, + unsigned int processed) +{ + ctx->cc_sector += processed >> SECTOR_SHIFT; + ctx->tag_offset += processed / cc->sector_size; +} + /* * Encrypt / decrypt data from one bio to another one (can be the same one) */ static blk_status_t crypt_convert(struct crypt_config *cc, struct convert_context *ctx, bool atomic, bool reset_pending) { - unsigned int sector_step = cc->sector_size >> SECTOR_SHIFT; + unsigned int processed; int r; /* @@ -1536,10 +1593,12 @@ static blk_status_t crypt_convert(struct crypt_config *cc, atomic_inc(&ctx->cc_pending); + processed = cc->sector_size; if (crypt_integrity_aead(cc)) r = crypt_convert_block_aead(cc, ctx, ctx->r.req_aead, ctx->tag_offset); else - r = crypt_convert_block_skcipher(cc, ctx, ctx->r.req, ctx->tag_offset); + r = crypt_convert_block_skcipher(cc, ctx, ctx->r.req, + ctx->tag_offset, &processed); switch (r) { /* @@ -1559,8 +1618,7 @@ static blk_status_t crypt_convert(struct crypt_config *cc, * exit and continue processing in a workqueue */ ctx->r.req = NULL; - ctx->tag_offset++; - ctx->cc_sector += sector_step; + crypt_convert_advance(cc, ctx, processed); return BLK_STS_DEV_RESOURCE; } } else { @@ -1574,16 +1632,14 @@ static blk_status_t crypt_convert(struct crypt_config *cc, */ case -EINPROGRESS: ctx->r.req = NULL; - ctx->tag_offset++; - ctx->cc_sector += sector_step; + crypt_convert_advance(cc, ctx, processed); continue; /* * The request was already processed (synchronously). */ case 0: atomic_dec(&ctx->cc_pending); - ctx->cc_sector += sector_step; - ctx->tag_offset++; + crypt_convert_advance(cc, ctx, processed); if (!atomic) cond_resched(); continue; @@ -2345,12 +2401,37 @@ static int crypt_alloc_tfms_aead(struct crypt_config *cc, char *ciphermode) return 0; } +/* + * Whether to wrap the cipher in dun() for multi-data-unit batching: a counter + * IV mode (dun_endian set: plain64 "le", plain64be "be", essiv "le"), single- + * tfm, non-aead, and a per-unit IV step of exactly one (512B sectors or + * iv_large_sectors). Integrity is configured + * after alloc, so it is re-checked post-alloc in crypt_ctr_cipher(); an + * integrity config keeps an inert dun() wrapper but never sets the batch flag. + */ +static bool crypt_can_batch_dun(struct crypt_config *cc) +{ + return !crypt_integrity_aead(cc) && cc->tfms_count == 1 && + cc->iv_gen_ops && cc->iv_gen_ops->dun_endian && + (cc->sector_size == (1 << SECTOR_SHIFT) || + test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags)); +} + static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode) { + char dun_api[CRYPTO_MAX_ALG_NAME]; + if (crypt_integrity_aead(cc)) return crypt_alloc_tfms_aead(cc, ciphermode); - else - return crypt_alloc_tfms_skcipher(cc, ciphermode); + + /* Wrap in dun() for batching when eligible (like the essiv() rewrite). */ + if (crypt_can_batch_dun(cc)) { + if (snprintf(dun_api, sizeof(dun_api), "dun(%s,%s)", ciphermode, + cc->iv_gen_ops->dun_endian) >= (int)sizeof(dun_api)) + return -ENAMETOOLONG; + ciphermode = dun_api; + } + return crypt_alloc_tfms_skcipher(cc, ciphermode); } static unsigned int crypt_subkey_size(struct crypt_config *cc) @@ -2747,25 +2828,15 @@ static void crypt_dtr(struct dm_target *ti) dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1); } -static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) +/* + * Select cc->iv_gen_ops from the IV mode string -- pure parsing, no tfm + * dependency, so it runs before alloc and lets crypt_can_batch_dun() see the + * mode. The tfm-dependent IV sizing is finished later by crypt_ctr_ivmode(). + */ +static int crypt_select_ivmode(struct dm_target *ti, const char *ivmode) { struct crypt_config *cc = ti->private; - if (crypt_integrity_aead(cc)) - cc->iv_size = crypto_aead_ivsize(any_tfm_aead(cc)); - else - cc->iv_size = crypto_skcipher_ivsize(any_tfm(cc)); - - if (cc->iv_size) - /* at least a 64 bit sector number should fit in our buffer */ - cc->iv_size = max(cc->iv_size, - (unsigned int)(sizeof(u64) / sizeof(u8))); - else if (ivmode) { - DMWARN("Selected cipher does not support IVs"); - ivmode = NULL; - } - - /* Choose ivmode, see comments at iv code. */ if (ivmode == NULL) cc->iv_gen_ops = NULL; else if (strcmp(ivmode, "plain") == 0) @@ -2803,12 +2874,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) } } else if (strcmp(ivmode, "tcw") == 0) { cc->iv_gen_ops = &crypt_iv_tcw_ops; - cc->key_parts += 2; /* IV + whitening */ - cc->key_extra_size = cc->iv_size + TCW_WHITENING_SIZE; } else if (strcmp(ivmode, "random") == 0) { cc->iv_gen_ops = &crypt_iv_random_ops; - /* Need storage space in integrity fields. */ - cc->integrity_iv_size = cc->iv_size; } else { ti->error = "Invalid IV mode"; return -EINVAL; @@ -2817,6 +2884,37 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) return 0; } +static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) +{ + struct crypt_config *cc = ti->private; + + if (crypt_integrity_aead(cc)) + cc->iv_size = crypto_aead_ivsize(any_tfm_aead(cc)); + else + cc->iv_size = crypto_skcipher_ivsize(any_tfm(cc)); + + if (cc->iv_size) + /* at least a 64 bit sector number should fit in our buffer */ + cc->iv_size = max(cc->iv_size, + (unsigned int)(sizeof(u64) / sizeof(u8))); + else if (ivmode) { + DMWARN("Selected cipher does not support IVs"); + ivmode = NULL; + cc->iv_gen_ops = NULL; + } + + /* Finish the tfm-dependent IV sizing; modes are already selected. */ + if (cc->iv_gen_ops == &crypt_iv_tcw_ops) { + cc->key_parts += 2; /* IV + whitening */ + cc->key_extra_size = cc->iv_size + TCW_WHITENING_SIZE; + } else if (cc->iv_gen_ops == &crypt_iv_random_ops) { + /* Need storage space in integrity fields. */ + cc->integrity_iv_size = cc->iv_size; + } + + return 0; +} + /* * Workaround to parse HMAC algorithm from AEAD crypto API spec. * The HMAC is needed to calculate tag size (HMAC digest size). @@ -2914,7 +3012,12 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, char *cipher_in, char *key cc->key_parts = cc->tfms_count; - /* Allocate cipher */ + /* Select IV mode before alloc so dun() wrapping can be decided. */ + ret = crypt_select_ivmode(ti, *ivmode); + if (ret < 0) + return ret; + + /* Allocate cipher (skcipher may be wrapped in dun()). */ ret = crypt_alloc_tfms(cc, cipher_api); if (ret < 0) { ti->error = "Error allocating crypto tfm"; @@ -2999,7 +3102,13 @@ static int crypt_ctr_cipher_old(struct dm_target *ti, char *cipher_in, char *key goto bad_mem; } - /* Allocate cipher */ + /* Select IV mode before alloc so dun() wrapping can be decided. */ + ret = crypt_select_ivmode(ti, *ivmode); + if (ret < 0) { + kfree(cipher_api); + return ret; + } + ret = crypt_alloc_tfms(cc, cipher_api); if (ret < 0) { ti->error = "Error allocating crypto tfm"; @@ -3063,6 +3172,19 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key) } } + /* + * Enable batching only if the cipher was dun()-wrapped at alloc time and + * no integrity was configured (integrity is set up after cipher alloc). + */ + if (!crypt_integrity_aead(cc) && !cc->integrity_tag_size && + !cc->integrity_iv_size && + !strncmp(crypto_skcipher_alg(any_tfm(cc))->base.cra_name, + "dun(", 4)) { + set_bit(CRYPT_MULTI_DATA_UNIT, &cc->cipher_flags); + DMINFO("Using multi-data-unit crypto offload (du=%u)", + cc->sector_size); + } + /* wipe the kernel key payload copy */ if (cc->key_string) memset(cc->key, 0, cc->key_size * sizeof(u8)); From 82c265d48f9091334d3df338f454660a46aa6099 Mon Sep 17 00:00:00 2001 From: Leonid Ravich Date: Wed, 1 Jul 2026 06:53:54 +0000 Subject: [PATCH 6/6] blk-crypto: fallback - batch a segment's data units via dun() blk-crypto-fallback open-codes a per-data-unit loop, issuing one skcipher request per data unit with the IV walked as a DUN counter. Allocate dun(,le) instead of the bare cipher so a contiguous bio segment is encrypted/decrypted as one multi-data-unit request, the crypto layer walking the per-unit IV. Every blk-crypto mode feeds the DUN as a little-endian counter, and dun() handles any counter width up to 32 bytes, so all modes -- including Adiantum (32-byte IV) -- are wrapped and the open-coded inner per-unit loop is removed from both the encrypt and decrypt paths. This makes blk-crypto-fallback a second consumer of the template (after dm-crypt) and lets a higher-priority hardware dun(...) driver, if present, handle the request in one pass. Output is unchanged: the template's little-endian per-unit counter is exactly blk_crypto_dun_to_iv()/bio_crypt_dun_increment(). Signed-off-by: Leonid Ravich --- block/Kconfig | 1 + block/blk-crypto-fallback.c | 74 ++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index 70e4a66d941ff..75c5c4d964814 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -204,6 +204,7 @@ config BLK_INLINE_ENCRYPTION_FALLBACK depends on BLK_INLINE_ENCRYPTION select CRYPTO select CRYPTO_SKCIPHER + select CRYPTO_DUN # batches a segment's data units per crypto request help Enabling this lets the block layer handle inline encryption by falling back to the kernel crypto API when inline diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index 2a5c52ab74b4c..1103a5a3da09f 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -251,7 +251,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, unsigned int nr_enc_pages, enc_idx; struct page **enc_pages; struct bio *enc_bio; - unsigned int i; skcipher_request_set_callback(ciph_req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, @@ -261,9 +260,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, sg_init_table(&src, 1); sg_init_table(&dst, 1); - skcipher_request_set_crypt(ciph_req, &src, &dst, data_unit_size, - iv.bytes); - /* * Encrypt each page in the source bio. Because the source bio could * have bio_vecs that span more than a single page, but the encrypted @@ -288,29 +284,26 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, __bio_add_page(enc_bio, enc_page, src_bv.bv_len, src_bv.bv_offset); - sg_set_page(&src, src_bv.bv_page, data_unit_size, - src_bv.bv_offset); - sg_set_page(&dst, enc_page, data_unit_size, src_bv.bv_offset); - /* * Increment the index now that the encrypted page is added to * the bio. This is important for the error unwind path. */ enc_idx++; - /* - * Encrypt each data unit in this page. - */ - for (i = 0; i < src_bv.bv_len; i += data_unit_size) { - blk_crypto_dun_to_iv(curr_dun, &iv); - if (crypto_skcipher_encrypt(ciph_req)) { - enc_bio->bi_status = BLK_STS_IOERR; - goto out_free_enc_bio; - } - bio_crypt_dun_increment(curr_dun, 1); - src.offset += data_unit_size; - dst.offset += data_unit_size; + /* Encrypt the whole segment as one multi-data-unit request. */ + blk_crypto_dun_to_iv(curr_dun, &iv); + sg_set_page(&src, src_bv.bv_page, src_bv.bv_len, + src_bv.bv_offset); + sg_set_page(&dst, enc_page, src_bv.bv_len, src_bv.bv_offset); + skcipher_request_set_crypt(ciph_req, &src, &dst, src_bv.bv_len, + iv.bytes); + skcipher_request_set_data_unit_size(ciph_req, data_unit_size); + if (crypto_skcipher_encrypt(ciph_req)) { + enc_bio->bi_status = BLK_STS_IOERR; + goto out_free_enc_bio; } + bio_crypt_dun_increment(curr_dun, + src_bv.bv_len / data_unit_size); bio_advance_iter_single(src_bio, &src_bio->bi_iter, src_bv.bv_len); @@ -380,7 +373,6 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio, struct scatterlist sg; struct bio_vec bv; const int data_unit_size = bc->bc_key->crypto_cfg.data_unit_size; - unsigned int i; skcipher_request_set_callback(ciph_req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, @@ -388,26 +380,20 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio, memcpy(curr_dun, bc->bc_dun, sizeof(curr_dun)); sg_init_table(&sg, 1); - skcipher_request_set_crypt(ciph_req, &sg, &sg, data_unit_size, - iv.bytes); - /* Decrypt each segment in the bio */ + /* One dun() request per segment; the crypto layer walks the per-unit DUN. */ __bio_for_each_segment(bv, bio, iter, iter) { - struct page *page = bv.bv_page; - if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size)) return BLK_STS_INVAL; - sg_set_page(&sg, page, data_unit_size, bv.bv_offset); - - /* Decrypt each data unit in the segment */ - for (i = 0; i < bv.bv_len; i += data_unit_size) { - blk_crypto_dun_to_iv(curr_dun, &iv); - if (crypto_skcipher_decrypt(ciph_req)) - return BLK_STS_IOERR; - bio_crypt_dun_increment(curr_dun, 1); - sg.offset += data_unit_size; - } + blk_crypto_dun_to_iv(curr_dun, &iv); + sg_set_page(&sg, bv.bv_page, bv.bv_len, bv.bv_offset); + skcipher_request_set_crypt(ciph_req, &sg, &sg, bv.bv_len, + iv.bytes); + skcipher_request_set_data_unit_size(ciph_req, data_unit_size); + if (crypto_skcipher_decrypt(ciph_req)) + return BLK_STS_IOERR; + bio_crypt_dun_increment(curr_dun, bv.bv_len / data_unit_size); } return BLK_STS_OK; @@ -619,6 +605,7 @@ static int blk_crypto_fallback_init(void) int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) { const char *cipher_str = blk_crypto_modes[mode_num].cipher_str; + char dun_str[CRYPTO_MAX_ALG_NAME]; struct blk_crypto_fallback_keyslot *slotp; unsigned int i; int err = 0; @@ -639,15 +626,24 @@ int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) if (err) goto out; + /* + * Wrap in dun() to handle a whole segment per request (a higher-priority + * hardware dun() wins if present). The blk-crypto DUN is little-endian. + */ + if (snprintf(dun_str, sizeof(dun_str), "dun(%s,le)", cipher_str) >= + (int)sizeof(dun_str)) { + err = -EINVAL; + goto out; + } + for (i = 0; i < blk_crypto_num_keyslots; i++) { slotp = &blk_crypto_keyslots[i]; - slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(cipher_str, - 0, 0); + slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(dun_str, 0, 0); if (IS_ERR(slotp->tfms[mode_num])) { err = PTR_ERR(slotp->tfms[mode_num]); if (err == -ENOENT) { pr_warn_once("Missing crypto API support for \"%s\"\n", - cipher_str); + dun_str); err = -ENOPKG; } slotp->tfms[mode_num] = NULL;