summaryrefslogtreecommitdiff
path: root/debian/patches/0001-ipc-rework-the-kernel-message-buffer-cache.patch
blob: b166cf0009be3aa2af5eaea35c6d35fe8f0b92a6 (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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
From e23a941eaf5aabe087f50700213c05c6d269d63b Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Wed, 17 Dec 2014 14:21:15 +0100
Subject: [PATCH gnumach 1/3] ipc: rework the kernel message buffer cache

Keep a per-processor stack of free kernel messages buffers.

* ipc/ipc_kmsg.h (IKM_CACHE_SIZE): New macro.
(struct ipc_mksg_cpu_cache): New type.
(ipc_kmsg_cache): Use the new type for the cache.
(ikm_cache): Drop macro.
(ikm_cache_get, ikm_cache_put): New functions.
(ikm_free): Return buffers instead of freeing them.
(_ikm_free): New version of `ikm_free' that only frees buffers.
* ipc/ipc_kmsg.c (ipc_kmsg_cache): Use new type.
(ipc_kmsg_get, ipc_kmsg_put): Use new functions.
* ipc/mach_msg.c (mach_msg_trap): Likewise.
* kern/exception.c (exception_raise): Likewise.
(exception_parse_reply): Likewise.
* kern/ipc_kobject.c (ipc_kobject_server): Likewise.
---
 ipc/ipc_kmsg.c     | 29 ++++---------------
 ipc/ipc_kmsg.h     | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 ipc/mach_msg.c     | 14 ++++-----
 kern/exception.c   | 28 ++++--------------
 kern/ipc_kobject.c |  6 +---
 5 files changed, 97 insertions(+), 63 deletions(-)

diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
index 66643fd..04cdbc9 100644
--- a/ipc/ipc_kmsg.c
+++ b/ipc/ipc_kmsg.c
@@ -73,7 +73,7 @@
 #define ptr_align(x)	\
 	( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
 
-ipc_kmsg_t ipc_kmsg_cache[NCPUS];
+struct ipc_kmsg_cpu_cache ipc_kmsg_cache[NCPUS];
 
 /*
  *	Routine:	ipc_kmsg_enqueue
@@ -506,23 +506,9 @@ ipc_kmsg_get(
 	if ((size < sizeof(mach_msg_header_t)) || (size & 3))
 		return MACH_SEND_MSG_TOO_SMALL;
 
-	if (size <= IKM_SAVED_MSG_SIZE) {
-		kmsg = ikm_cache();
-		if (kmsg != IKM_NULL) {
-			ikm_cache() = IKM_NULL;
-			ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
-		} else {
-			kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
-			if (kmsg == IKM_NULL)
-				return MACH_SEND_NO_BUFFER;
-			ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
-		}
-	} else {
-		kmsg = ikm_alloc(size);
-		if (kmsg == IKM_NULL)
-			return MACH_SEND_NO_BUFFER;
-		ikm_init(kmsg, size);
-	}
+	kmsg = ikm_cache_get (size);
+	if (kmsg == IKM_NULL)
+		return MACH_SEND_NO_BUFFER;
 
 	if (copyinmsg(msg, &kmsg->ikm_header, size)) {
 		ikm_free(kmsg);
@@ -599,12 +585,7 @@ ipc_kmsg_put(
 	else
 		mr = MACH_MSG_SUCCESS;
 
-	if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
-	    (ikm_cache() == IKM_NULL))
-		ikm_cache() = kmsg;
-	else
-		ikm_free(kmsg);
-
+	ikm_cache_put (kmsg);
 	return mr;
 }
 
diff --git a/ipc/ipc_kmsg.h b/ipc/ipc_kmsg.h
index 620785b..c676996 100644
--- a/ipc/ipc_kmsg.h
+++ b/ipc/ipc_kmsg.h
@@ -96,11 +96,36 @@ MACRO_END
  *	The per-processor cache seems to miss less than a per-thread cache,
  *	and it also uses less memory.  Access to the cache doesn't
  *	require locking.
+ *
+ *	The per-processor cache is a stack containing unused kernel
+ *	message buffers.  We choose IKM_CACHE_SIZE so that the size of
+ *	the struct ipc_kmsg_cpu_cache is a multiple of a cache line,
+ *	to prevent it bouncing between per-cpu caches.
+ *
+ *	A kernel message buffer can be allocated using
+ *	`ikm_cache_get', and returned using `ikm_cache_put'.
  */
 
-extern ipc_kmsg_t	ipc_kmsg_cache[NCPUS];
+#define IKM_CACHE_SIZE	(((1 << CPU_L1_SHIFT) - sizeof (size_t))	\
+			 / sizeof (ipc_kmsg_t))
+
+struct ipc_kmsg_cpu_cache
+{
+	size_t		count;
+	ipc_kmsg_t	buffers[IKM_CACHE_SIZE];
+};
+
+extern struct ipc_kmsg_cpu_cache ipc_kmsg_cache[NCPUS];
+
+/* Return a kernel message buffer of at least SIZE size, preferably
+   from the cache.  This functions is defined below.  */
+static inline ipc_kmsg_t ikm_cache_get (mach_msg_size_t size)
+	__attribute__ ((always_inline));
 
-#define ikm_cache()     ipc_kmsg_cache[cpu_number()]
+/* Return a kernel message buffer to the cache, or free it.  This
+   functions is defined below.  */
+static inline void ikm_cache_put (ipc_kmsg_t kmsg)
+	__attribute__ ((always_inline));
 
 /*
  *	The size of the kernel message buffers that will be cached.
@@ -150,11 +175,18 @@ MACRO_BEGIN								\
 	register vm_size_t _size = (kmsg)->ikm_size;			\
 									\
 	if ((integer_t)_size > 0)					\
-		kfree((vm_offset_t) (kmsg), _size);			\
+		ikm_cache_put (kmsg);					\
 	else								\
 		ipc_kmsg_free(kmsg);					\
 MACRO_END
 
+#define	_ikm_free(kmsg)							\
+MACRO_BEGIN								\
+	vm_size_t _size = (kmsg)->ikm_size;				\
+	assert (_size != IKM_SIZE_NETWORK);				\
+	kfree((vm_offset_t) (kmsg), _size);				\
+MACRO_END
+
 /*
  *	struct ipc_kmsg_queue is defined in ipc/ipc_kmsg_queue.h
  */
@@ -280,5 +312,50 @@ ipc_kmsg_copyout_pseudo(ipc_kmsg_t, ipc_space_t, vm_map_t);
 
 extern void
 ipc_kmsg_copyout_dest(ipc_kmsg_t, ipc_space_t);
+
+static inline ipc_kmsg_t
+ikm_cache_get (mach_msg_size_t size)
+{
+	ipc_kmsg_t kmsg;
+	struct ipc_kmsg_cpu_cache *c = &ipc_kmsg_cache[cpu_number ()];
+
+	if (size < IKM_SAVED_MSG_SIZE)
+		size = IKM_SAVED_MSG_SIZE;
+
+	if (size > IKM_SAVED_MSG_SIZE
+	    || c->count == 0) {
+		kmsg = ikm_alloc (size);
+		if (kmsg)
+			ikm_init (kmsg, size);
+		return kmsg;
+	}
+
+	c->count -= 1;
+	kmsg = c->buffers[c->count];
+
+#if	MACH_IPC_TEST
+	ikm_check_initialized (kmsg, IKM_SAVED_KMSG_SIZE);
+#endif	/* MACH_IPC_TEST */
+	return kmsg;
+}
+
+static inline void
+ikm_cache_put (ipc_kmsg_t kmsg)
+{
+	struct ipc_kmsg_cpu_cache *c = &ipc_kmsg_cache[cpu_number ()];
+
+	if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE
+	    || c->count == IKM_CACHE_SIZE) {
+		_ikm_free (kmsg);
+		return;
+	}
+
+	c->buffers[c->count] = kmsg;
+	c->count += 1;
+
+#if	MACH_IPC_TEST
+	ikm_check_initialized (kmsg, IKM_SAVED_KMSG_SIZE);
+#endif	/* MACH_IPC_TEST */
+}
 
 #endif	/* _IPC_IPC_KMSG_H_ */
diff --git a/ipc/mach_msg.c b/ipc/mach_msg.c
index 1e122c7..cdf16ea 100644
--- a/ipc/mach_msg.c
+++ b/ipc/mach_msg.c
@@ -451,16 +451,14 @@ mach_msg_trap(
 
 		if ((send_size > IKM_SAVED_MSG_SIZE) ||
 		    (send_size < sizeof(mach_msg_header_t)) ||
-		    (send_size & 3) ||
-		    ((kmsg = ikm_cache()) == IKM_NULL))
+		    (send_size & 3))
 			goto slow_get;
 
-		ikm_cache() = IKM_NULL;
-		ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
+		kmsg = ikm_cache_get (IKM_SAVED_MSG_SIZE);
 
 		if (copyinmsg(msg, &kmsg->ikm_header,
 			      send_size)) {
-			ikm_free(kmsg);
+			ikm_cache_put (kmsg);
 			goto slow_get;
 		}
 
@@ -1263,18 +1261,16 @@ mach_msg_trap(
 		 *	We have the reply message data in kmsg,
 		 *	and the reply message size in reply_size.
 		 *	Just need to copy it out to the user and free kmsg.
-		 *	We must check ikm_cache after copyoutmsg.
 		 */
 
 		ikm_check_initialized(kmsg, kmsg->ikm_size);
 
 		if ((kmsg->ikm_size != IKM_SAVED_KMSG_SIZE) ||
 		    copyoutmsg(&kmsg->ikm_header, msg,
-			       reply_size) ||
-		    (ikm_cache() != IKM_NULL))
+			       reply_size))
 			goto slow_put;
 
-		ikm_cache() = kmsg;
+		ikm_cache_put (kmsg);
 		thread_syscall_return(MACH_MSG_SUCCESS);
 		/*NOTREACHED*/
 		return MACH_MSG_SUCCESS; /* help for the compiler */
diff --git a/kern/exception.c b/kern/exception.c
index 7954fba..72a4f29 100644
--- a/kern/exception.c
+++ b/kern/exception.c
@@ -348,16 +348,9 @@ exception_raise(
 	 *	and it will give the buffer back with its reply.
 	 */
 
-	kmsg = ikm_cache();
-	if (kmsg != IKM_NULL) {
-		ikm_cache() = IKM_NULL;
-		ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
-	} else {
-		kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
-		if (kmsg == IKM_NULL)
-			panic("exception_raise");
-		ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
-	}
+	kmsg = ikm_cache_get (IKM_SAVED_MSG_SIZE);
+	if (kmsg == IKM_NULL)
+		panic("exception_raise");
 
 	/*
 	 *	We need a reply port for the RPC.
@@ -681,22 +674,19 @@ exception_raise(
 
 	/*
 	 *	Optimized version of ipc_kmsg_put.
-	 *	We must check ikm_cache after copyoutmsg.
 	 */
-
 	ikm_check_initialized(kmsg, kmsg->ikm_size);
 	assert(kmsg->ikm_size == IKM_SAVED_KMSG_SIZE);
 
 	if (copyoutmsg(&kmsg->ikm_header, receiver->ith_msg,
-		       sizeof(struct mach_exception)) ||
-	    (ikm_cache() != IKM_NULL)) {
+		       sizeof(struct mach_exception))) {
 		mr = ipc_kmsg_put(receiver->ith_msg, kmsg,
 				  kmsg->ikm_header.msgh_size);
 		thread_syscall_return(mr);
 		/*NOTREACHED*/
 	}
 
-	ikm_cache() = kmsg;
+	ikm_cache_put (kmsg);
 	thread_syscall_return(MACH_MSG_SUCCESS);
 	/*NOTREACHED*/
 #ifndef	__GNUC__
@@ -809,13 +799,7 @@ exception_parse_reply(ipc_kmsg_t kmsg)
 	}
 
 	kr = msg->RetCode;
-
-	if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
-	    (ikm_cache() == IKM_NULL))
-		ikm_cache() = kmsg;
-	else
-		ikm_free(kmsg);
-
+	ikm_cache_put (kmsg);
 	return kr;
 }
 
diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
index bf22028..27535b0 100644
--- a/kern/ipc_kobject.c
+++ b/kern/ipc_kobject.c
@@ -236,11 +236,7 @@ ipc_kobject_server(request)
 		/* like ipc_kmsg_put, but without the copyout */
 
 		ikm_check_initialized(request, request->ikm_size);
-		if ((request->ikm_size == IKM_SAVED_KMSG_SIZE) &&
-		    (ikm_cache() == IKM_NULL))
-			ikm_cache() = request;
-		else
-			ikm_free(request);
+		ikm_cache_put (request);
 	} else {
 		/*
 		 *	The message contents of the request are intact.
-- 
2.1.3