mp_ws_query.c revision 171795
155714Skris/*-
255714Skris * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
355714Skris * All rights reserved.
455714Skris *
555714Skris * Redistribution and use in source and binary forms, with or without
655714Skris * modification, are permitted provided that the following conditions
755714Skris * are met:
8280304Sjkim * 1. Redistributions of source code must retain the above copyright
955714Skris *    notice, this list of conditions and the following disclaimer.
1055714Skris * 2. Redistributions in binary form must reproduce the above copyright
1155714Skris *    notice, this list of conditions and the following disclaimer in the
1255714Skris *    documentation and/or other materials provided with the distribution.
1355714Skris *
1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15280304Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1655714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1755714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22280304Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2455714Skris * SUCH DAMAGE.
2555714Skris *
2655714Skris */
2755714Skris
2855714Skris#include <sys/cdefs.h>
2955714Skris__FBSDID("$FreeBSD: head/usr.sbin/nscd/mp_ws_query.c 171795 2007-08-09 13:06:12Z bushman $");
3055714Skris
3155714Skris#include <sys/socket.h>
3255714Skris#include <sys/time.h>
3355714Skris#include <sys/types.h>
3455714Skris#include <sys/event.h>
3555714Skris#include <assert.h>
3655714Skris#include <errno.h>
37280304Sjkim#include <stdlib.h>
3855714Skris#include <string.h>
3955714Skris#include <stdio.h>
40280304Sjkim
4155714Skris#include "cachelib.h"
4255714Skris#include "config.h"
4355714Skris#include "debug.h"
4455714Skris#include "log.h"
4555714Skris#include "query.h"
4655714Skris#include "mp_ws_query.h"
4755714Skris#include "singletons.h"
4855714Skris
4955714Skrisstatic int on_mp_write_session_abandon_notification(struct query_state *);
5055714Skrisstatic int on_mp_write_session_close_notification(struct query_state *);
5155714Skrisstatic void on_mp_write_session_destroy(struct query_state *);
52280304Sjkimstatic int on_mp_write_session_mapper(struct query_state *);
5355714Skris/* int on_mp_write_session_request_read1(struct query_state *); */
5455714Skrisstatic int on_mp_write_session_request_read2(struct query_state *);
5555714Skrisstatic int on_mp_write_session_request_process(struct query_state *);
5655714Skrisstatic int on_mp_write_session_response_write1(struct query_state *);
5755714Skrisstatic int on_mp_write_session_write_request_read1(struct query_state *);
5855714Skrisstatic int on_mp_write_session_write_request_read2(struct query_state *);
59280304Sjkimstatic int on_mp_write_session_write_request_process(struct query_state *);
60280304Sjkimstatic int on_mp_write_session_write_response_write1(struct query_state *);
61280304Sjkim
62280304Sjkim/*
63160814Ssimon * This function is used as the query_state's destroy_func to make the
64280304Sjkim * proper cleanup in case of errors.
65160814Ssimon */
66160814Ssimonstatic void
6755714Skrison_mp_write_session_destroy(struct query_state *qstate)
6855714Skris{
6955714Skris
70109998Smarkm	TRACE_IN(on_mp_write_session_destroy);
71109998Smarkm	finalize_comm_element(&qstate->request);
72109998Smarkm	finalize_comm_element(&qstate->response);
7355714Skris
7455714Skris	if (qstate->mdata != NULL) {
7555714Skris		configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
7659191Skris		abandon_cache_mp_write_session(
77100928Snectar	    		(cache_mp_write_session)qstate->mdata);
7855714Skris		configuration_unlock_entry(qstate->config_entry,
79109998Smarkm			CELT_MULTIPART);
8055714Skris	}
8155714Skris	TRACE_OUT(on_mp_write_session_destroy);
8255714Skris}
83280304Sjkim
8455714Skris/*
8555714Skris * The functions below are used to process multipart write session initiation
86280304Sjkim * requests.
8755714Skris * - on_mp_write_session_request_read1 and on_mp_write_session_request_read2
88280304Sjkim *   read the request itself
89280304Sjkim * - on_mp_write_session_request_process processes it
90280304Sjkim * - on_mp_write_session_response_write1 sends the response
91280304Sjkim */
92280304Sjkimint
9355714Skrison_mp_write_session_request_read1(struct query_state *qstate)
94160814Ssimon{
9555714Skris	struct cache_mp_write_session_request	*c_mp_ws_request;
96280304Sjkim	ssize_t	result;
97280304Sjkim
9855714Skris	TRACE_IN(on_mp_write_session_request_read1);
9955714Skris	if (qstate->kevent_watermark == 0)
100280304Sjkim		qstate->kevent_watermark = sizeof(size_t);
101280304Sjkim	else {
102280304Sjkim		init_comm_element(&qstate->request,
103280304Sjkim	    		CET_MP_WRITE_SESSION_REQUEST);
104280304Sjkim		c_mp_ws_request = get_cache_mp_write_session_request(
105280304Sjkim	    		&qstate->request);
106280304Sjkim
107280304Sjkim		result = qstate->read_func(qstate,
10855714Skris	    		&c_mp_ws_request->entry_length, sizeof(size_t));
109280304Sjkim
110280304Sjkim		if (result != sizeof(size_t)) {
111280304Sjkim			LOG_ERR_3("on_mp_write_session_request_read1",
112109998Smarkm				"read failed");
113280304Sjkim			TRACE_OUT(on_mp_write_session_request_read1);
114280304Sjkim			return (-1);
115280304Sjkim		}
11655714Skris
117280304Sjkim		if (BUFSIZE_INVALID(c_mp_ws_request->entry_length)) {
11859191Skris			LOG_ERR_3("on_mp_write_session_request_read1",
119280304Sjkim				"invalid entry_length value");
120280304Sjkim			TRACE_OUT(on_mp_write_session_request_read1);
121280304Sjkim			return (-1);
122280304Sjkim		}
12355714Skris
124280304Sjkim		c_mp_ws_request->entry = (char *)malloc(
125280304Sjkim			c_mp_ws_request->entry_length + 1);
126280304Sjkim		assert(c_mp_ws_request->entry != NULL);
127280304Sjkim		memset(c_mp_ws_request->entry, 0,
128280304Sjkim			c_mp_ws_request->entry_length + 1);
12955714Skris
130280304Sjkim		qstate->kevent_watermark = c_mp_ws_request->entry_length;
131280304Sjkim		qstate->process_func = on_mp_write_session_request_read2;
132280304Sjkim	}
133280304Sjkim	TRACE_OUT(on_mp_write_session_request_read1);
134280304Sjkim	return (0);
135280304Sjkim}
136280304Sjkim
137280304Sjkimstatic int
138280304Sjkimon_mp_write_session_request_read2(struct query_state *qstate)
139280304Sjkim{
140100928Snectar	struct cache_mp_write_session_request	*c_mp_ws_request;
141280304Sjkim	ssize_t	result;
142280304Sjkim
143280304Sjkim	TRACE_IN(on_mp_write_session_request_read2);
144280304Sjkim	c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request);
145280304Sjkim
14655714Skris	result = qstate->read_func(qstate, c_mp_ws_request->entry,
147280304Sjkim		c_mp_ws_request->entry_length);
148280304Sjkim
149280304Sjkim	if (result != qstate->kevent_watermark) {
15055714Skris		LOG_ERR_3("on_mp_write_session_request_read2",
151280304Sjkim			"read failed");
152280304Sjkim		TRACE_OUT(on_mp_write_session_request_read2);
153280304Sjkim		return (-1);
154280304Sjkim	}
15555714Skris
156280304Sjkim	qstate->kevent_watermark = 0;
157280304Sjkim	qstate->process_func = on_mp_write_session_request_process;
158280304Sjkim
159160814Ssimon	TRACE_OUT(on_mp_write_session_request_read2);
160280304Sjkim	return (0);
161280304Sjkim}
162280304Sjkim
163280304Sjkimstatic int
164280304Sjkimon_mp_write_session_request_process(struct query_state *qstate)
165280304Sjkim{
166280304Sjkim	struct cache_mp_write_session_request	*c_mp_ws_request;
16755714Skris	struct cache_mp_write_session_response	*c_mp_ws_response;
168280304Sjkim	cache_mp_write_session	ws;
169280304Sjkim	cache_entry	c_entry;
170280304Sjkim	char	*dec_cache_entry_name;
171280304Sjkim
172280304Sjkim	TRACE_IN(on_mp_write_session_request_process);
173280304Sjkim	init_comm_element(&qstate->response, CET_MP_WRITE_SESSION_RESPONSE);
174280304Sjkim	c_mp_ws_response = get_cache_mp_write_session_response(
17555714Skris		&qstate->response);
176280304Sjkim	c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request);
177280304Sjkim
178280304Sjkim	qstate->config_entry = configuration_find_entry(
17955714Skris		s_configuration, c_mp_ws_request->entry);
180280304Sjkim	if (qstate->config_entry == NULL) {
181280304Sjkim		c_mp_ws_response->error_code = ENOENT;
182280304Sjkim
183280304Sjkim		LOG_ERR_2("write_session_request",
184280304Sjkim			"can't find configuration entry '%s'. "
185280304Sjkim	    		"aborting request", c_mp_ws_request->entry);
18655714Skris	    	goto fin;
187280304Sjkim	}
188280304Sjkim
189280304Sjkim	if (qstate->config_entry->enabled == 0) {
19055714Skris		c_mp_ws_response->error_code = EACCES;
191280304Sjkim
192280304Sjkim		LOG_ERR_2("write_session_request",
193280304Sjkim			"configuration entry '%s' is disabled",
194280304Sjkim			c_mp_ws_request->entry);
195280304Sjkim		goto fin;
196280304Sjkim	}
197280304Sjkim
198280304Sjkim	if (qstate->config_entry->perform_actual_lookups != 0) {
199280304Sjkim		c_mp_ws_response->error_code = EOPNOTSUPP;
200280304Sjkim
201280304Sjkim		LOG_ERR_2("write_session_request",
202280304Sjkim			"entry '%s' performs lookups by itself: "
203280304Sjkim			"can't write to it", c_mp_ws_request->entry);
204100928Snectar		goto fin;
205280304Sjkim	} else {
206280304Sjkim#ifdef NS_NSCD_EID_CHECKING
207280304Sjkim		if (check_query_eids(qstate) != 0) {
208280304Sjkim			c_mp_ws_response->error_code = EPERM;
209280304Sjkim			goto fin;
210280304Sjkim		}
211280304Sjkim#endif
212280304Sjkim	}
213280304Sjkim
214280304Sjkim	/*
215280304Sjkim	 * All multipart entries are separated by their name decorations.
216280304Sjkim	 * For one configuration entry there will be a lot of multipart
217280304Sjkim	 * cache entries - each with its own decorated name.
218280304Sjkim	 */
219280304Sjkim	asprintf(&dec_cache_entry_name, "%s%s", qstate->eid_str,
220280304Sjkim		qstate->config_entry->mp_cache_params.entry_name);
22155714Skris	assert(dec_cache_entry_name != NULL);
222160814Ssimon
223280304Sjkim	configuration_lock_rdlock(s_configuration);
224280304Sjkim	c_entry = find_cache_entry(s_cache,
22555714Skris		dec_cache_entry_name);
226280304Sjkim	configuration_unlock(s_configuration);
227280304Sjkim
228280304Sjkim	if (c_entry == INVALID_CACHE_ENTRY)
229280304Sjkim		c_entry = register_new_mp_cache_entry(qstate,
230280304Sjkim			dec_cache_entry_name);
231280304Sjkim
232280304Sjkim	free(dec_cache_entry_name);
233280304Sjkim
234280304Sjkim	assert(c_entry != NULL);
235280304Sjkim	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
236280304Sjkim	ws = open_cache_mp_write_session(c_entry);
237280304Sjkim	if (ws == INVALID_CACHE_MP_WRITE_SESSION)
238280304Sjkim		c_mp_ws_response->error_code = -1;
239280304Sjkim	else {
240280304Sjkim		qstate->mdata = ws;
24155714Skris		qstate->destroy_func = on_mp_write_session_destroy;
242
243		if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
244		    (qstate->config_entry->mp_query_timeout.tv_usec != 0))
245			memcpy(&qstate->timeout,
246				&qstate->config_entry->mp_query_timeout,
247				sizeof(struct timeval));
248	}
249	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
250
251fin:
252	qstate->process_func = on_mp_write_session_response_write1;
253	qstate->kevent_watermark = sizeof(int);
254	qstate->kevent_filter = EVFILT_WRITE;
255
256	TRACE_OUT(on_mp_write_session_request_process);
257	return (0);
258}
259
260static int
261on_mp_write_session_response_write1(struct query_state *qstate)
262{
263	struct cache_mp_write_session_response	*c_mp_ws_response;
264	ssize_t	result;
265
266	TRACE_IN(on_mp_write_session_response_write1);
267	c_mp_ws_response = get_cache_mp_write_session_response(
268		&qstate->response);
269	result = qstate->write_func(qstate, &c_mp_ws_response->error_code,
270		sizeof(int));
271	if (result != sizeof(int)) {
272		LOG_ERR_3("on_mp_write_session_response_write1",
273			"write failed");
274		TRACE_OUT(on_mp_write_session_response_write1);
275		return (-1);
276	}
277
278	if (c_mp_ws_response->error_code == 0) {
279		qstate->kevent_watermark = sizeof(int);
280		qstate->process_func = on_mp_write_session_mapper;
281		qstate->kevent_filter = EVFILT_READ;
282	} else {
283		qstate->kevent_watermark = 0;
284		qstate->process_func = NULL;
285	}
286	TRACE_OUT(on_mp_write_session_response_write1);
287	return (0);
288}
289
290/*
291 * Mapper function is used to avoid multiple connections for each session
292 * write or read requests. After processing the request, it does not close
293 * the connection, but waits for the next request.
294 */
295static int
296on_mp_write_session_mapper(struct query_state *qstate)
297{
298	ssize_t	result;
299	int		elem_type;
300
301	TRACE_IN(on_mp_write_session_mapper);
302	if (qstate->kevent_watermark == 0) {
303		qstate->kevent_watermark = sizeof(int);
304	} else {
305		result = qstate->read_func(qstate, &elem_type, sizeof(int));
306		if (result != sizeof(int)) {
307			LOG_ERR_3("on_mp_write_session_mapper",
308				"read failed");
309			TRACE_OUT(on_mp_write_session_mapper);
310			return (-1);
311		}
312
313		switch (elem_type) {
314		case CET_MP_WRITE_SESSION_WRITE_REQUEST:
315			qstate->kevent_watermark = sizeof(size_t);
316			qstate->process_func =
317				on_mp_write_session_write_request_read1;
318			break;
319		case CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION:
320			qstate->kevent_watermark = 0;
321			qstate->process_func =
322				on_mp_write_session_abandon_notification;
323			break;
324		case CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION:
325			qstate->kevent_watermark = 0;
326			qstate->process_func =
327				on_mp_write_session_close_notification;
328			break;
329		default:
330			qstate->kevent_watermark = 0;
331			qstate->process_func = NULL;
332			LOG_ERR_2("on_mp_write_session_mapper",
333				"unknown element type");
334			TRACE_OUT(on_mp_write_session_mapper);
335			return (-1);
336		}
337	}
338	TRACE_OUT(on_mp_write_session_mapper);
339	return (0);
340}
341
342/*
343 * The functions below are used to process multipart write sessions write
344 * requests.
345 * - on_mp_write_session_write_request_read1 and
346 *   on_mp_write_session_write_request_read2 read the request itself
347 * - on_mp_write_session_write_request_process processes it
348 * - on_mp_write_session_write_response_write1 sends the response
349 */
350static int
351on_mp_write_session_write_request_read1(struct query_state *qstate)
352{
353	struct cache_mp_write_session_write_request	*write_request;
354	ssize_t	result;
355
356	TRACE_IN(on_mp_write_session_write_request_read1);
357	init_comm_element(&qstate->request,
358		CET_MP_WRITE_SESSION_WRITE_REQUEST);
359	write_request = get_cache_mp_write_session_write_request(
360		&qstate->request);
361
362	result = qstate->read_func(qstate, &write_request->data_size,
363		sizeof(size_t));
364
365	if (result != sizeof(size_t)) {
366		LOG_ERR_3("on_mp_write_session_write_request_read1",
367			"read failed");
368		TRACE_OUT(on_mp_write_session_write_request_read1);
369		return (-1);
370	}
371
372	if (BUFSIZE_INVALID(write_request->data_size)) {
373		LOG_ERR_3("on_mp_write_session_write_request_read1",
374			"invalid data_size value");
375		TRACE_OUT(on_mp_write_session_write_request_read1);
376		return (-1);
377	}
378
379	write_request->data = (char *)malloc(write_request->data_size);
380	assert(write_request->data != NULL);
381	memset(write_request->data, 0, write_request->data_size);
382
383	qstate->kevent_watermark = write_request->data_size;
384	qstate->process_func = on_mp_write_session_write_request_read2;
385	TRACE_OUT(on_mp_write_session_write_request_read1);
386	return (0);
387}
388
389static int
390on_mp_write_session_write_request_read2(struct query_state *qstate)
391{
392	struct cache_mp_write_session_write_request	*write_request;
393	ssize_t	result;
394
395	TRACE_IN(on_mp_write_session_write_request_read2);
396	write_request = get_cache_mp_write_session_write_request(
397		&qstate->request);
398
399	result = qstate->read_func(qstate, write_request->data,
400		write_request->data_size);
401
402	if (result != qstate->kevent_watermark) {
403		LOG_ERR_3("on_mp_write_session_write_request_read2",
404			"read failed");
405		TRACE_OUT(on_mp_write_session_write_request_read2);
406		return (-1);
407	}
408
409	qstate->kevent_watermark = 0;
410	qstate->process_func = on_mp_write_session_write_request_process;
411	TRACE_OUT(on_mp_write_session_write_request_read2);
412	return (0);
413}
414
415static int
416on_mp_write_session_write_request_process(struct query_state *qstate)
417{
418	struct cache_mp_write_session_write_request	*write_request;
419	struct cache_mp_write_session_write_response	*write_response;
420
421	TRACE_IN(on_mp_write_session_write_request_process);
422	init_comm_element(&qstate->response,
423		CET_MP_WRITE_SESSION_WRITE_RESPONSE);
424	write_response = get_cache_mp_write_session_write_response(
425		&qstate->response);
426	write_request = get_cache_mp_write_session_write_request(
427		&qstate->request);
428
429	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
430	write_response->error_code = cache_mp_write(
431		(cache_mp_write_session)qstate->mdata,
432		write_request->data,
433		write_request->data_size);
434	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
435
436	qstate->kevent_watermark = sizeof(int);
437	qstate->process_func = on_mp_write_session_write_response_write1;
438	qstate->kevent_filter = EVFILT_WRITE;
439
440	TRACE_OUT(on_mp_write_session_write_request_process);
441	return (0);
442}
443
444static int
445on_mp_write_session_write_response_write1(struct query_state *qstate)
446{
447	struct cache_mp_write_session_write_response	*write_response;
448	ssize_t	result;
449
450	TRACE_IN(on_mp_write_session_write_response_write1);
451	write_response = get_cache_mp_write_session_write_response(
452		&qstate->response);
453	result = qstate->write_func(qstate, &write_response->error_code,
454		sizeof(int));
455	if (result != sizeof(int)) {
456		LOG_ERR_3("on_mp_write_session_write_response_write1",
457			"write failed");
458		TRACE_OUT(on_mp_write_session_write_response_write1);
459		return (-1);
460	}
461
462	if (write_response->error_code == 0) {
463		finalize_comm_element(&qstate->request);
464		finalize_comm_element(&qstate->response);
465
466		qstate->kevent_watermark = sizeof(int);
467		qstate->process_func = on_mp_write_session_mapper;
468		qstate->kevent_filter = EVFILT_READ;
469	} else {
470		qstate->kevent_watermark = 0;
471		qstate->process_func = 0;
472	}
473
474	TRACE_OUT(on_mp_write_session_write_response_write1);
475	return (0);
476}
477
478/*
479 * Handles abandon notifications. Destroys the session by calling the
480 * abandon_cache_mp_write_session.
481 */
482static int
483on_mp_write_session_abandon_notification(struct query_state *qstate)
484{
485	TRACE_IN(on_mp_write_session_abandon_notification);
486	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
487	abandon_cache_mp_write_session((cache_mp_write_session)qstate->mdata);
488	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
489	qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION;
490
491	qstate->kevent_watermark = 0;
492	qstate->process_func = NULL;
493	TRACE_OUT(on_mp_write_session_abandon_notification);
494	return (0);
495}
496
497/*
498 * Handles close notifications. Commits the session by calling
499 * the close_cache_mp_write_session.
500 */
501static int
502on_mp_write_session_close_notification(struct query_state *qstate)
503{
504	TRACE_IN(on_mp_write_session_close_notification);
505	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
506	close_cache_mp_write_session((cache_mp_write_session)qstate->mdata);
507	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);
508	qstate->mdata = INVALID_CACHE_MP_WRITE_SESSION;
509
510	qstate->kevent_watermark = 0;
511	qstate->process_func = NULL;
512	TRACE_OUT(on_mp_write_session_close_notification);
513	return (0);
514}
515
516cache_entry register_new_mp_cache_entry(struct query_state *qstate,
517	const char *dec_cache_entry_name)
518{
519	cache_entry c_entry;
520	char *en_bkp;
521
522	TRACE_IN(register_new_mp_cache_entry);
523	c_entry = INVALID_CACHE_ENTRY;
524	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
525
526	configuration_lock_wrlock(s_configuration);
527	en_bkp = qstate->config_entry->mp_cache_params.entry_name;
528	qstate->config_entry->mp_cache_params.entry_name =
529		(char *)dec_cache_entry_name;
530	register_cache_entry(s_cache, (struct cache_entry_params *)
531		&qstate->config_entry->mp_cache_params);
532	qstate->config_entry->mp_cache_params.entry_name = en_bkp;
533	configuration_unlock(s_configuration);
534
535	configuration_lock_rdlock(s_configuration);
536	c_entry = find_cache_entry(s_cache,
537		dec_cache_entry_name);
538	configuration_unlock(s_configuration);
539
540	configuration_entry_add_mp_cache_entry(qstate->config_entry,
541		c_entry);
542
543	configuration_unlock_entry(qstate->config_entry,
544		CELT_MULTIPART);
545
546	TRACE_OUT(register_new_mp_cache_entry);
547	return (c_entry);
548}
549