Skip to content

Commit 698f744

Browse files
committed
habanalabs: never copy_from_user inside spinlock
copy_from_user might sleep so we can never call it when we have a spinlock. Moreover, it is not necessary in waiting for user interrupt, because if multiple threads will call this function on the same interrupt, each one will have it's own fence object inside the driver. The user address might be the same, but it doesn't really matter to us, as we only read from it. Signed-off-by: Oded Gabbay <[email protected]>
1 parent 053caa2 commit 698f744

File tree

1 file changed

+12
-23
lines changed

1 file changed

+12
-23
lines changed

drivers/misc/habanalabs/common/command_submission.c

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2740,14 +2740,10 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27402740
else
27412741
interrupt = &hdev->user_interrupt[interrupt_offset];
27422742

2743-
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
2744-
2745-
if (copy_from_user(&completion_value, u64_to_user_ptr(user_address),
2746-
4)) {
2747-
dev_err(hdev->dev,
2748-
"Failed to copy completion value from user\n");
2743+
if (copy_from_user(&completion_value, u64_to_user_ptr(user_address), 4)) {
2744+
dev_err(hdev->dev, "Failed to copy completion value from user\n");
27492745
rc = -EFAULT;
2750-
goto unlock_and_free_fence;
2746+
goto free_fence;
27512747
}
27522748

27532749
if (completion_value >= target_value)
@@ -2756,42 +2752,35 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
27562752
*status = CS_WAIT_STATUS_BUSY;
27572753

27582754
if (!timeout_us || (*status == CS_WAIT_STATUS_COMPLETED))
2759-
goto unlock_and_free_fence;
2755+
goto free_fence;
27602756

27612757
/* Add pending user interrupt to relevant list for the interrupt
27622758
* handler to monitor
27632759
*/
2760+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
27642761
list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head);
27652762
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
27662763

27672764
wait_again:
27682765
/* Wait for interrupt handler to signal completion */
2769-
completion_rc =
2770-
wait_for_completion_interruptible_timeout(
2771-
&pend->fence.completion, timeout);
2766+
completion_rc = wait_for_completion_interruptible_timeout(&pend->fence.completion,
2767+
timeout);
27722768

27732769
/* If timeout did not expire we need to perform the comparison.
27742770
* If comparison fails, keep waiting until timeout expires
27752771
*/
27762772
if (completion_rc > 0) {
2777-
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
2778-
2779-
if (copy_from_user(&completion_value,
2780-
u64_to_user_ptr(user_address), 4)) {
2781-
2782-
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
2783-
2784-
dev_err(hdev->dev,
2785-
"Failed to copy completion value from user\n");
2773+
if (copy_from_user(&completion_value, u64_to_user_ptr(user_address), 4)) {
2774+
dev_err(hdev->dev, "Failed to copy completion value from user\n");
27862775
rc = -EFAULT;
27872776

27882777
goto remove_pending_user_interrupt;
27892778
}
27902779

27912780
if (completion_value >= target_value) {
2792-
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
27932781
*status = CS_WAIT_STATUS_COMPLETED;
27942782
} else {
2783+
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
27952784
reinit_completion(&pend->fence.completion);
27962785
timeout = completion_rc;
27972786

@@ -2811,9 +2800,9 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx,
28112800
remove_pending_user_interrupt:
28122801
spin_lock_irqsave(&interrupt->wait_list_lock, flags);
28132802
list_del(&pend->wait_list_node);
2814-
2815-
unlock_and_free_fence:
28162803
spin_unlock_irqrestore(&interrupt->wait_list_lock, flags);
2804+
2805+
free_fence:
28172806
kfree(pend);
28182807
hl_ctx_put(ctx);
28192808

0 commit comments

Comments
 (0)