Skip to content

Commit 9ca7a42

Browse files
committed
firmware: arm_ffa: Replace mutex with rwlock to avoid sleep in atomic context
The current use of a mutex to protect the notifier hashtable accesses can lead to issues in the atomic context. It results in the below kernel warnings: | BUG: sleeping function called from invalid context at kernel/locking/mutex.c:258 | in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 9, name: kworker/0:0 | preempt_count: 1, expected: 0 | RCU nest depth: 0, expected: 0 | CPU: 0 UID: 0 PID: 9 Comm: kworker/0:0 Not tainted 6.14.0 #4 | Workqueue: ffa_pcpu_irq_notification notif_pcpu_irq_work_fn | Call trace: | show_stack+0x18/0x24 (C) | dump_stack_lvl+0x78/0x90 | dump_stack+0x18/0x24 | __might_resched+0x114/0x170 | __might_sleep+0x48/0x98 | mutex_lock+0x24/0x80 | handle_notif_callbacks+0x54/0xe0 | notif_get_and_handle+0x40/0x88 | generic_exec_single+0x80/0xc0 | smp_call_function_single+0xfc/0x1a0 | notif_pcpu_irq_work_fn+0x2c/0x38 | process_one_work+0x14c/0x2b4 | worker_thread+0x2e4/0x3e0 | kthread+0x13c/0x210 | ret_from_fork+0x10/0x20 To address this, replace the mutex with an rwlock to protect the notifier hashtable accesses. This ensures that read-side locking does not sleep and multiple readers can acquire the lock concurrently, avoiding unnecessary contention and potential deadlocks. Writer access remains exclusive, preserving correctness. This change resolves warnings from lockdep about potential sleep in atomic context. Cc: Jens Wiklander <[email protected]> Reported-by: Jérôme Forissier <[email protected]> Closes: OP-TEE/optee_os#7394 Fixes: e057344 ("firmware: arm_ffa: Add interfaces to request notification callbacks") Message-Id: <[email protected]> Reviewed-by: Jens Wiklander <[email protected]> Tested-by: Jens Wiklander <[email protected]> Signed-off-by: Sudeep Holla <[email protected]>
1 parent 27e850c commit 9ca7a42

File tree

1 file changed

+11
-11
lines changed

1 file changed

+11
-11
lines changed

drivers/firmware/arm_ffa/driver.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ struct ffa_drv_info {
110110
struct work_struct sched_recv_irq_work;
111111
struct xarray partition_info;
112112
DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
113-
struct mutex notify_lock; /* lock to protect notifier hashtable */
113+
rwlock_t notify_lock; /* lock to protect notifier hashtable */
114114
};
115115

116116
static struct ffa_drv_info *drv_info;
@@ -1289,19 +1289,19 @@ static int __ffa_notify_relinquish(struct ffa_device *dev, int notify_id,
12891289
if (notify_id >= FFA_MAX_NOTIFICATIONS)
12901290
return -EINVAL;
12911291

1292-
mutex_lock(&drv_info->notify_lock);
1292+
write_lock(&drv_info->notify_lock);
12931293

12941294
rc = update_notifier_cb(dev, notify_id, NULL, is_framework);
12951295
if (rc) {
12961296
pr_err("Could not unregister notification callback\n");
1297-
mutex_unlock(&drv_info->notify_lock);
1297+
write_unlock(&drv_info->notify_lock);
12981298
return rc;
12991299
}
13001300

13011301
if (!is_framework)
13021302
rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id));
13031303

1304-
mutex_unlock(&drv_info->notify_lock);
1304+
write_unlock(&drv_info->notify_lock);
13051305

13061306
return rc;
13071307
}
@@ -1341,7 +1341,7 @@ static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
13411341
else
13421342
cb_info->cb = cb;
13431343

1344-
mutex_lock(&drv_info->notify_lock);
1344+
write_lock(&drv_info->notify_lock);
13451345

13461346
if (!is_framework) {
13471347
if (is_per_vcpu)
@@ -1361,7 +1361,7 @@ static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
13611361
}
13621362

13631363
out_unlock_free:
1364-
mutex_unlock(&drv_info->notify_lock);
1364+
write_unlock(&drv_info->notify_lock);
13651365
if (rc)
13661366
kfree(cb_info);
13671367

@@ -1407,9 +1407,9 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
14071407
if (!(bitmap & 1))
14081408
continue;
14091409

1410-
mutex_lock(&drv_info->notify_lock);
1410+
read_lock(&drv_info->notify_lock);
14111411
cb_info = notifier_hnode_get_by_type(notify_id, type);
1412-
mutex_unlock(&drv_info->notify_lock);
1412+
read_unlock(&drv_info->notify_lock);
14131413

14141414
if (cb_info && cb_info->cb)
14151415
cb_info->cb(notify_id, cb_info->cb_data);
@@ -1447,9 +1447,9 @@ static void handle_fwk_notif_callbacks(u32 bitmap)
14471447

14481448
ffa_rx_release();
14491449

1450-
mutex_lock(&drv_info->notify_lock);
1450+
read_lock(&drv_info->notify_lock);
14511451
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
1452-
mutex_unlock(&drv_info->notify_lock);
1452+
read_unlock(&drv_info->notify_lock);
14531453

14541454
if (cb_info && cb_info->fwk_cb)
14551455
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
@@ -1974,7 +1974,7 @@ static void ffa_notifications_setup(void)
19741974
goto cleanup;
19751975

19761976
hash_init(drv_info->notifier_hash);
1977-
mutex_init(&drv_info->notify_lock);
1977+
rwlock_init(&drv_info->notify_lock);
19781978

19791979
drv_info->notif_enabled = true;
19801980
return;

0 commit comments

Comments
 (0)