Message ID | 20230610061139.212085-1-ebiggers@kernel.org (mailing list archive) |
---|---|
State | Not Applicable, archived |
Delegated to: | Mike Snitzer |
Headers | show |
Series | blk-crypto: use dynamic lock class for blk_crypto_profile::lock | expand |
On 6/9/23 23:11, Eric Biggers wrote: > 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. Reviewed-by: Bart Van Assche <bvanassche@acm.org> -- dm-devel mailing list dm-devel@redhat.com https://listman.redhat.com/mailman/listinfo/dm-devel
On Fri, Jun 09, 2023 at 11:11:39PM -0700, Eric Biggers wrote: > From: Eric Biggers <ebiggers@google.com> > > 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. Jens, can you apply this? - Eric -- dm-devel mailing list dm-devel@redhat.com https://listman.redhat.com/mailman/listinfo/dm-devel
On Fri, 09 Jun 2023 23:11:39 -0700, Eric Biggers wrote: > 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. > > [...] Applied, thanks! [1/1] blk-crypto: use dynamic lock class for blk_crypto_profile::lock commit: de9f927faf8dfb158763898e09a3e371f2ebd30d Best regards,
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c index 2a67d3fb63e5c..7fabc883e39f1 100644 --- a/block/blk-crypto-profile.c +++ b/block/blk-crypto-profile.c @@ -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; @@ -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; @@ -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); diff --git a/include/linux/blk-crypto-profile.h b/include/linux/blk-crypto-profile.h index e6802b69cdd64..90ab33cb5d0ef 100644 --- a/include/linux/blk-crypto-profile.h +++ b/include/linux/blk-crypto-profile.h @@ -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;