Skip to content

Commit

Permalink
blk-crypto: use dynamic lock class for blk_crypto_profile::lock
Browse files Browse the repository at this point in the history
When a device-mapper device is passing through the inline encryption
support of an underlying device, calls to blk_crypto_evict_key() take
the blk_crypto_profile::lock of the device-mapper device, then take the
blk_crypto_profile::lock of the underlying device (nested).  This isn't
a real deadlock, but it causes a lockdep report because there is only
one lock class for all instances of this lock.

Lockdep subclasses don't really work here because the hierarchy of block
devices is dynamic and could have more than 2 levels.

Instead, register a dynamic lock class for each blk_crypto_profile, and
associate that with the lock.

This avoids false-positive lockdep reports like the following:

    ============================================
    WARNING: possible recursive locking detected
    6.4.0-rc5 #2 Not tainted
    --------------------------------------------
    fscryptctl/1421 is trying to acquire lock:
    ffffff80829ca418 (&profile->lock){++++}-{3:3}, at: __blk_crypto_evict_key+0x44/0x1c0

                   but task is already holding lock:
    ffffff8086b68ca8 (&profile->lock){++++}-{3:3}, at: __blk_crypto_evict_key+0xc8/0x1c0

                   other info that might help us debug this:
     Possible unsafe locking scenario:

           CPU0
           ----
      lock(&profile->lock);
      lock(&profile->lock);

                    *** DEADLOCK ***

     May be due to missing lock nesting notation

Fixes: 1b26283 ("block: Keyslot Manager for Inline Encryption")
Reported-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20230610061139.212085-1-ebiggers@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
ebiggers authored and axboe committed Jul 5, 2023
1 parent 7eb1e47 commit 2fb48d8
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 2 deletions.
12 changes: 10 additions & 2 deletions block/blk-crypto-profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,14 @@ int blk_crypto_profile_init(struct blk_crypto_profile *profile,
unsigned int slot_hashtable_size;

memset(profile, 0, sizeof(*profile));
init_rwsem(&profile->lock);

/*
* profile->lock of an underlying device can nest inside profile->lock
* of a device-mapper device, so use a dynamic lock class to avoid
* false-positive lockdep reports.
*/
lockdep_register_key(&profile->lockdep_key);
__init_rwsem(&profile->lock, "&profile->lock", &profile->lockdep_key);

if (num_slots == 0)
return 0;
Expand All @@ -89,7 +96,7 @@ int blk_crypto_profile_init(struct blk_crypto_profile *profile,
profile->slots = kvcalloc(num_slots, sizeof(profile->slots[0]),
GFP_KERNEL);
if (!profile->slots)
return -ENOMEM;
goto err_destroy;

profile->num_slots = num_slots;

Expand Down Expand Up @@ -435,6 +442,7 @@ void blk_crypto_profile_destroy(struct blk_crypto_profile *profile)
{
if (!profile)
return;
lockdep_unregister_key(&profile->lockdep_key);
kvfree(profile->slot_hashtable);
kvfree_sensitive(profile->slots,
sizeof(profile->slots[0]) * profile->num_slots);
Expand Down
1 change: 1 addition & 0 deletions include/linux/blk-crypto-profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct blk_crypto_profile {
* keyslots while ensuring that they can't be changed concurrently.
*/
struct rw_semaphore lock;
struct lock_class_key lockdep_key;

/* List of idle slots, with least recently used slot at front */
wait_queue_head_t idle_slots_wait_queue;
Expand Down

0 comments on commit 2fb48d8

Please sign in to comment.