xref: /dragonfly/lib/libc/upmap/upmap.c (revision 279dd846)
1 /*
2  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "namespace.h"
36 #include <sys/cdefs.h>
37 #include <sys/types.h>
38 #include <sys/syscall.h>
39 #include <sys/upmap.h>
40 #include <sys/time.h>
41 #include <sys/mman.h>
42 #include <sys/fcntl.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <time.h>
47 #include <pthread.h>
48 #include "un-namespace.h"
49 #include "libc_private.h"
50 #include "upmap.h"
51 
52 static pthread_mutex_t ukpmap_lock;
53 static ukpheader_t *kpmap_headers;
54 static ukpheader_t *upmap_headers;
55 static int kpmap_ok;
56 static int upmap_ok;
57 
58 /*
59  * Map the requested data item from the user-kernel global shared mmap
60  *
61  * *state is set to -1 on failure, else it is left alone.
62  * *datap is set to a pointer to the item on success, else it is left alone.
63  * If type == 0 this function finalizes state, setting it to 1 if it is 0.
64  */
65 void
66 __kpmap_map(void *datap, int *state, uint16_t type)
67 {
68 	ukpheader_t *head;
69 
70 	if (__isthreaded)
71 		_pthread_mutex_lock(&ukpmap_lock);
72 
73 	if (kpmap_ok <= 0) {
74 		int fd;
75 
76 		if (kpmap_ok < 0)
77 			goto failed;
78 		fd = _open("/dev/kpmap", O_RDONLY);
79 		if (fd < 0) {
80 			kpmap_ok = -1;
81 			goto failed;
82 		}
83 		kpmap_headers = mmap(NULL, KPMAP_MAPSIZE,
84 				     PROT_READ, MAP_SHARED,
85 				     fd, 0);
86 		_close(fd);
87 		if ((void *)kpmap_headers == MAP_FAILED) {
88 			kpmap_ok = -1;
89 			goto failed;
90 		}
91 		kpmap_ok = 1;
92 	}
93 
94 	/*
95 	 * Special case to finalize state
96 	 */
97 	if (type == 0) {
98 		if (*state == 0)
99 			*state = 1;
100 		if (__isthreaded)
101 			_pthread_mutex_unlock(&ukpmap_lock);
102 		return;
103 	}
104 
105 	/*
106 	 * Look for type.
107 	 */
108 	for (head = kpmap_headers; head->type; ++head) {
109 		if (head->type == type) {
110 			*(void **)datap = (char *)kpmap_headers + head->offset;
111 			if (__isthreaded)
112 				_pthread_mutex_unlock(&ukpmap_lock);
113 			return;
114 		}
115 	}
116 failed:
117 	*state = -1;
118 	if (__isthreaded)
119 		_pthread_mutex_unlock(&ukpmap_lock);
120 }
121 
122 /*
123  * Map the requested data item from the user-kernel per-process shared mmap
124  *
125  * *state is set to -1 on failure, else it is left alone.
126  * *datap is set to a pointer to the item on success, else it is left alone.
127  * If type == 0 this function finalizes state, setting it to 1 if it is 0.
128  */
129 void
130 __upmap_map(void *datap, int *state, uint16_t type)
131 {
132 	ukpheader_t *head;
133 
134 	if (__isthreaded)
135 		_pthread_mutex_lock(&ukpmap_lock);
136 
137 	if (upmap_ok <= 0) {
138 		int fd;
139 
140 		if (upmap_ok < 0)
141 			goto failed;
142 		fd = _open("/dev/upmap", O_RDWR);
143 		if (fd < 0) {
144 			upmap_ok = -1;
145 			goto failed;
146 		}
147 		upmap_headers = mmap(NULL, UPMAP_MAPSIZE,
148 				     PROT_READ | PROT_WRITE, MAP_SHARED,
149 				     fd, 0);
150 		_close(fd);
151 		if ((void *)upmap_headers == MAP_FAILED) {
152 			upmap_ok = -1;
153 			goto failed;
154 		}
155 		upmap_ok = 1;
156 	}
157 
158 	/*
159 	 * Special case to finalize state
160 	 */
161 	if (type == 0) {
162 		if (*state == 0)
163 			*state = 1;
164 		if (__isthreaded)
165 			_pthread_mutex_unlock(&ukpmap_lock);
166 		return;
167 	}
168 
169 	/*
170 	 * Look for type.
171 	 */
172 	for (head = upmap_headers; head->type; ++head) {
173 		if (head->type == type) {
174 			*(void **)datap = (char *)upmap_headers + head->offset;
175 			if (__isthreaded)
176 				_pthread_mutex_unlock(&ukpmap_lock);
177 			return;
178 		}
179 	}
180 failed:
181 	*state = -1;
182 	if (__isthreaded)
183 		_pthread_mutex_unlock(&ukpmap_lock);
184 }
185