efi: vars: Don't drop lock in the middle of efivar_init()
authorArd Biesheuvel <ardb@kernel.org>
Mon, 20 Jun 2022 15:04:32 +0000 (17:04 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 24 Jun 2022 18:40:18 +0000 (20:40 +0200)
commitec3507b2ca51286de6ecd85fdac8e722219cdef8
tree134b3046bb3b859a73aa44c132e0c072b15fbb20
parent8ca869b24538a7b5501af368e87e4a59b0c04117
efi: vars: Don't drop lock in the middle of efivar_init()

Even though the efivars_lock lock is documented as protecting the
efivars->ops pointer (among other things), efivar_init() happily
releases and reacquires the lock for every EFI variable that it
enumerates. This used to be needed because the lock was originally a
spinlock, which prevented the callback that is invoked for every
variable from being able to sleep. However, releasing the lock could
potentially invalidate the ops pointer, but more importantly, it might
allow a SetVariable() runtime service call to take place concurrently,
and the UEFI spec does not define how this affects an enumeration that
is running in parallel using the GetNextVariable() runtime service,
which is what efivar_init() uses.

In the meantime, the lock has been converted into a semaphore, and the
only reason we need to drop the lock is because the efivarfs pseudo
filesystem driver will otherwise deadlock when it invokes the efivars
API from the callback to create the efivar_entry items and insert them
into the linked list. (EFI pstore is affected in a similar way)

So let's switch to helpers that can be used while the lock is already
taken. This way, we can hold on to the lock throughout the enumeration.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/vars.c
fs/efivarfs/super.c
include/linux/efi.h