[PATCH v4 08/13] crypto: s390/sha256 - implement library instead of shash
Eric Biggers
ebiggers at kernel.org
Fri May 30 07:16:39 AEST 2025
On Thu, May 29, 2025 at 01:14:31PM -0700, Linus Torvalds wrote:
> On Thu, 29 May 2025 at 10:37, Eric Biggers <ebiggers at kernel.org> wrote:
> >
> > Long-term, I'd like to find a clean way to consolidate the library code for each
> > algorithm into a single module.
>
> No, while I think the current situation isn't great, I think the "make
> it one single module" is even worse.
>
> For most architectures - including s390 - you end up being in the
> situation that these kinds of hw accelerated crypto things depend on
> some CPU capability, and aren't necessarily statically always
> available.
>
> So these things end up having stupid extra overhead due to having some
> conditional.
>
> That extra overhead is then in turn minimized with tricks like static
> branches, but that's all just just piling more ugly hacks on top
> because it picked a bad choice to begin with.
>
> So what's the *right* thing to do?
>
> The right thing to do is to just link the right routine in the first
> place, and *not* have static branch hackery at all. Because you didn't
> need it.
>
> And we already do runtime linking at module loading time. So if it's a
> module, if the hardware acceleration doesn't exist, the module load
> should just fail, and the loader should go on to load the next option.
So using crc32c() + ext4 + x86 as an example (but SHA-256 would be very
similar), the current behavior is that ext4.ko depends on the crc32c_arch()
symbol. That causes crc32-x86.ko to be loaded, which then depends on the
crc32c_base() symbol as a fallback, which causes crc32.ko to be loaded too. My
idea is to consolidate the two crc32 modules into one (they always go together,
after all), keeping the same symbols. The main challenge is just the current
directory structure.
Your suggestion sounds like: ext4.ko would depend on the crc32c() symbol, which
would be defined in *both* crc32-x86.ko and crc32.ko. The module loader would
try to load crc32-x86.ko first. If the CPU does not support any of the x86
accelerated CRC32 code, then loading that module would fail. The module loader
would then load crc32.ko instead.
Does any of the infrastructure to handle "this symbol is in multiple modules and
they must be loaded in this particular order" actually exist, though?
And how do we avoid the issues the crypto API often has where the accelerated
modules don't get loaded, causing slow generic code to unnecessarily be used?
IMO this sounds questionable compared to just using static keys and/or branches,
which we'd need anyway to support the non-modular case.
> Not any silly "one module to rule them all" hackery that only results
> in worse code. Just a simple "if this module loads successfully,
> you'll link the optimal hw acceleration".
>
> Now, the problem with this all is the *non*modular case.
>
> For modules, we already have the optimal solution in the form of
> init-module error handling and runtime linking.
>
> So I think the module case is "solved" (except the solution is not
> what we actually do).
>
> For the non-module case, the problem is that "I linked this
> unconditionally, and now it turns out I run on hardware that doesn't
> have the capability to run this".
>
> And that's when you need to do things like static_call_update() to
> basically do runtime re-linking of a static decision.
>
> And currently we very much do this wrong. See how s390 and x86-64 (and
> presumably others) basically have the *exact* same problems, but they
> then mix static branches and static calls (in the case of x86-64) and
> just have non-optimal code in general.
>
> What I think the generic code should do (for the built-in case) is just have
>
> DEFINE_STATIC_CALL(sha256_blocks_fn, sha256_blocks_generic);
>
> and do
>
> static_call(sha256_blocks_fn)(args..);
>
> and then architecture code can do the static_call_update() to set
> their optimal version.
>
> And yeah, we'd presumably need multiple versions, since there's the
> whole "is simd usable" thing. Although maybe that's going away?
Moving the static_call into the generic code might make sense. I don't think
it's a win in all cases currently, though. Only x86 and PPC32 actually have a
real static_call implementation; everywhere else it's an indirect call which is
slower than a static branch. Also, some arch code is just usable
unconditionally without any CPU feature check, e.g. the MIPS ChaCha code. That
doesn't use (or need to use) a static call or branch at all.
Also, while the centralized static_call would *allow* for the generic code to be
loaded while the arch code is not, in the vast majority of cases that would be a
bug, not a feature. The generic crypto infrastructure has that bug, and this
has caused a huge amount of pain over the years. People have to go out of the
way to ensure that the arch-optimized crypto code gets loaded. And they often
forget, resulting in the slow generic code being used unnecessarily...
Making the arch-optimized code be loaded through a direct symbol dependency
solves that problem.
- Eric
More information about the Linuxppc-dev
mailing list