From: zhanghui <zhanghui31@xxxxxxxxxx> On Android devices, we found that there is a probability that the ufs has been shut down but the thread is still deleting the key, which will cause the bus error. We checked the Android reboot process and found that it is indeed possible that some threads have not been killed before the device shutdown, because the Android reboot process will not wait until all threads are killed before continuing to execute. The call stack is as follows: __blk_crypto_evict_key+0x148/0x1c4 blk_crypto_evict_key+0x38/0x9c dm_keyslot_evict_callback+0x18/0x2c default_key_iterate_devices+0x40/0x50 dm_keyslot_evict+0xac/0xfc __blk_crypto_evict_key+0xf4/0x1c4 blk_crypto_evict_key+0x38/0x9c fscrypt_destroy_inline_crypt_key+0xb8/0x10c fscrypt_destroy_prepared_key+0x30/0x48 fscrypt_put_master_key_activeref+0xc4/0x308 fscrypt_destroy_keyring+0xb0/0xfc generic_shutdown_super+0x60/0x12c kill_block_super+0x1c/0x48 kill_f2fs_super+0xc4/0x1a8 deactivate_locked_super+0x98/0x144 deactivate_super+0x78/0x8c cleanup_mnt+0x110/0x148 __cleanup_mnt+0x14/0x20 task_work_run+0xc4/0xec get_signal+0x6c/0x8d8 do_notify_resume+0x128/0x828 el0_svc+0x6c/0x70 el0t_64_sync_handler+0x68/0xbc el0t_64_sync+0x1a8/0x1ac Let's fixed this issue by adding a lock in program_key flow. Signed-off-by: zhanghui <zhanghui31@xxxxxxxxxx> --- drivers/ufs/core/ufshcd-crypto.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/ufs/core/ufshcd-crypto.c b/drivers/ufs/core/ufshcd-crypto.c index 694ff7578fc1..f3260a072c0c 100644 --- a/drivers/ufs/core/ufshcd-crypto.c +++ b/drivers/ufs/core/ufshcd-crypto.c @@ -5,6 +5,7 @@ #include <ufs/ufshcd.h> #include "ufshcd-crypto.h" +#include "ufshcd-priv.h" /* Blk-crypto modes supported by UFS crypto */ static const struct ufs_crypto_alg_entry { @@ -17,12 +18,18 @@ static const struct ufs_crypto_alg_entry { }, }; -static void ufshcd_program_key(struct ufs_hba *hba, +static int ufshcd_program_key(struct ufs_hba *hba, const union ufs_crypto_cfg_entry *cfg, int slot) { int i; u32 slot_offset = hba->crypto_cfg_register + slot * sizeof(*cfg); + down(&hba->host_sem); + if (!ufshcd_is_user_access_allowed(hba)) { + up(&hba->host_sem); + return -EBUSY; + } + ufshcd_hold(hba); /* Ensure that CFGE is cleared before programming the key */ @@ -38,6 +45,9 @@ static void ufshcd_program_key(struct ufs_hba *hba, ufshcd_writel(hba, le32_to_cpu(cfg->reg_val[16]), slot_offset + 16 * sizeof(cfg->reg_val[0])); ufshcd_release(hba); + + up(&hba->host_sem); + return 0; } static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile, @@ -52,6 +62,7 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile, int i; int cap_idx = -1; union ufs_crypto_cfg_entry cfg = {}; + int err; BUILD_BUG_ON(UFS_CRYPTO_KEY_SIZE_INVALID != 0); for (i = 0; i < hba->crypto_capabilities.num_crypto_cap; i++) { @@ -79,10 +90,10 @@ static int ufshcd_crypto_keyslot_program(struct blk_crypto_profile *profile, memcpy(cfg.crypto_key, key->raw, key->size); } - ufshcd_program_key(hba, &cfg, slot); + err = ufshcd_program_key(hba, &cfg, slot); memzero_explicit(&cfg, sizeof(cfg)); - return 0; + return err; } static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile, @@ -96,8 +107,7 @@ static int ufshcd_crypto_keyslot_evict(struct blk_crypto_profile *profile, */ union ufs_crypto_cfg_entry cfg = {}; - ufshcd_program_key(hba, &cfg, slot); - return 0; + return ufshcd_program_key(hba, &cfg, slot); } /* -- 2.43.0