summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-4.4/0210-vchiq_arm-Access-the-dequeue_pending-flag-locked.patch
blob: 861f8853fc3d5d7e3ad94d5fed46ec515d2ab4e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
From 39afc75832ce9cd81f09b035630dd30e325f1797 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 23 Mar 2016 14:16:25 +0000
Subject: [PATCH] vchiq_arm: Access the dequeue_pending flag locked

Reading through this code looking for another problem (now found in userland)
the use of dequeue_pending outside a lock didn't seem safe.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
 .../misc/vc04_services/interface/vchiq_arm/vchiq_arm.c  | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -279,6 +279,7 @@ service_callback(VCHIQ_REASON_T reason,
 	USER_SERVICE_T *user_service;
 	VCHIQ_SERVICE_T *service;
 	VCHIQ_INSTANCE_T instance;
+	int skip_completion = 0;
 	DEBUG_INITIALISE(g_state.local)
 
 	DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -345,9 +346,6 @@ service_callback(VCHIQ_REASON_T reason,
 		user_service->msg_queue[user_service->msg_insert &
 			(MSG_QUEUE_SIZE - 1)] = header;
 		user_service->msg_insert++;
-		spin_unlock(&msg_queue_spinlock);
-
-		up(&user_service->insert_event);
 
 		/* If there is a thread waiting in DEQUEUE_MESSAGE, or if
 		** there is a MESSAGE_AVAILABLE in the completion queue then
@@ -356,13 +354,22 @@ service_callback(VCHIQ_REASON_T reason,
 		if (((user_service->message_available_pos -
 			instance->completion_remove) >= 0) ||
 			user_service->dequeue_pending) {
-			DEBUG_TRACE(SERVICE_CALLBACK_LINE);
 			user_service->dequeue_pending = 0;
-			return VCHIQ_SUCCESS;
+			skip_completion = 1;
 		}
 
+		spin_unlock(&msg_queue_spinlock);
+
+		up(&user_service->insert_event);
+
 		header = NULL;
 	}
+
+	if (skip_completion) {
+		DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+		return VCHIQ_SUCCESS;
+	}
+
 	DEBUG_TRACE(SERVICE_CALLBACK_LINE);
 
 	return add_completion(instance, reason, header, user_service,