nrelease - fix/improve livecd
[dragonfly.git] / lib / libc / upmap / upmap.c
1 /*
2  * Copyright (c) 2014,2019 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 /*
53  * kpmap - Global user/kernel shared map (RO)
54  * upmap - Per-process user/kernel shared map (RW)
55  * lpmap - Per-thread user/kernel shared map (RW)
56  */
57 static pthread_mutex_t ukpmap_lock;
58 static ukpheader_t *__kpmap_headers;
59 static ukpheader_t *__upmap_headers;
60 __thread ukpheader_t *__lpmap_headers TLS_ATTRIBUTE;
61 __thread uint32_t *__lpmap_blockallsigs TLS_ATTRIBUTE;
62
63 static __thread int lpmap_ok;
64 static int kpmap_ok;
65 static int upmap_ok;
66 static pthread_once_t upmap_once = PTHREAD_ONCE_INIT;
67
68
69 /*
70  * Map the requested data item from the user-kernel global shared mmap
71  *
72  * *state is set to -1 on failure, else it is left alone.
73  * *datap is set to a pointer to the item on success, else it is left alone.
74  * If type == 0 this function finalizes state, setting it to 1 if it is 0.
75  */
76 void
77 __kpmap_map(void *datap, int *state, uint16_t type)
78 {
79         ukpheader_t *head;
80
81         if (__isthreaded)
82                 _pthread_mutex_lock(&ukpmap_lock);
83
84         if (kpmap_ok <= 0) {
85                 int fd;
86
87                 if (kpmap_ok < 0)
88                         goto failed;
89                 fd = _open("/dev/kpmap", O_RDONLY);
90                 if (fd < 0) {
91                         kpmap_ok = -1;
92                         goto failed;
93                 }
94                 __kpmap_headers = mmap(NULL, KPMAP_MAPSIZE,
95                                        PROT_READ, MAP_SHARED | MAP_FILE,
96                                        fd, 0);
97                 _close(fd);
98                 if ((void *)__kpmap_headers == MAP_FAILED) {
99                         kpmap_ok = -1;
100                         goto failed;
101                 }
102                 kpmap_ok = 1;
103         }
104
105         /*
106          * Special case to finalize state
107          */
108         if (type == 0) {
109                 if (*state == 0)
110                         *state = 1;
111                 if (__isthreaded)
112                         _pthread_mutex_unlock(&ukpmap_lock);
113                 return;
114         }
115
116         /*
117          * Look for type.
118          */
119         for (head = __kpmap_headers; head->type; ++head) {
120                 if (head->type == type) {
121                         *(void **)datap = (char *)__kpmap_headers +
122                                           head->offset;
123                         if (__isthreaded)
124                                 _pthread_mutex_unlock(&ukpmap_lock);
125                         return;
126                 }
127         }
128 failed:
129         *state = -1;
130         if (__isthreaded)
131                 _pthread_mutex_unlock(&ukpmap_lock);
132 }
133
134 /*
135  * Map the requested data item from the user-kernel per-process shared mmap
136  *
137  * *state is set to -1 on failure, else it is left alone.
138  * *datap is set to a pointer to the item on success, else it is left alone.
139  * If type == 0 this function finalizes state, setting it to 1 if it is 0.
140  */
141 void
142 __upmap_map(void *datap, int *state, uint16_t type)
143 {
144         ukpheader_t *head;
145
146         if (__isthreaded)
147                 _pthread_mutex_lock(&ukpmap_lock);
148
149         if (upmap_ok <= 0) {
150                 int fd;
151
152                 if (upmap_ok < 0)
153                         goto failed;
154                 fd = _open("/dev/upmap", O_RDWR);
155                 if (fd < 0) {
156                         upmap_ok = -1;
157                         goto failed;
158                 }
159                 __upmap_headers = mmap(NULL, UPMAP_MAPSIZE,
160                                        PROT_READ | PROT_WRITE,
161                                        MAP_SHARED | MAP_FILE,
162                                        fd, 0);
163                 _close(fd);
164                 if ((void *)__upmap_headers == MAP_FAILED) {
165                         upmap_ok = -1;
166                         goto failed;
167                 }
168                 upmap_ok = 1;
169         }
170
171         /*
172          * Special case to finalize state
173          */
174         if (type == 0) {
175                 if (*state == 0)
176                         *state = 1;
177                 if (__isthreaded)
178                         _pthread_mutex_unlock(&ukpmap_lock);
179                 return;
180         }
181
182         /*
183          * Look for type.
184          */
185         for (head = __upmap_headers; head->type; ++head) {
186                 if (head->type == type) {
187                         *(void **)datap = (char *)__upmap_headers +
188                                           head->offset;
189                         if (__isthreaded)
190                                 _pthread_mutex_unlock(&ukpmap_lock);
191                         return;
192                 }
193         }
194 failed:
195         *state = -1;
196         if (__isthreaded)
197                 _pthread_mutex_unlock(&ukpmap_lock);
198 }
199
200 /*
201  * Map the requested data item from the user-kernel per-thread shared mmap
202  *
203  * *state is set to -1 on failure, else it is left alone.
204  * *datap is set to a pointer to the item on success, else it is left alone.
205  * If type == 0 this function finalizes state, setting it to 1 if it is 0.
206  *
207  * WARNING!  This code is used all over pthreads and must NOT make any
208  *           reentrant pthreads calls until after the mapping has been
209  *           set up.
210  */
211 static pthread_key_t lpmap_key;
212
213 static void lpmap_unmap(void **datap);
214
215 void
216 __lpmap_map(void *datap, int *state, uint16_t type)
217 {
218         ukpheader_t *head;
219
220         if (lpmap_ok <= 0) {
221                 int fd;
222
223                 if (lpmap_ok < 0)
224                         goto failed;
225                 fd = _open("/dev/lpmap", O_RDWR);
226                 if (fd < 0) {
227                         lpmap_ok = -1;
228                         goto failed;
229                 }
230                 __lpmap_headers = mmap(NULL, LPMAP_MAPSIZE,
231                                        PROT_READ | PROT_WRITE,
232                                        MAP_SHARED | MAP_FILE,
233                                        fd, 0);
234                 _close(fd);
235                 if ((void *)__lpmap_headers == MAP_FAILED) {
236                         lpmap_ok = -1;
237                         goto failed;
238                 }
239                 lpmap_ok = 1;
240                 _pthread_setspecific(lpmap_key, &__lpmap_headers);
241         }
242
243         /*
244          * Special case to finalize state
245          */
246         if (type == 0) {
247                 if (*state == 0)
248                         *state = 1;
249                 return;
250         }
251
252         /*
253          * Look for type.
254          */
255         for (head = __lpmap_headers; head->type; ++head) {
256                 if (head->type == type) {
257                         *(void **)datap = (char *)__lpmap_headers +
258                                           head->offset;
259                         return;
260                 }
261         }
262 failed:
263         *state = -1;
264 }
265
266 /*
267  * Cleanup thread state
268  */
269 static void
270 lpmap_unmap(void **datap)
271 {
272         ukpheader_t *lpmap = *datap;
273
274         lpmap_ok = -1;
275         if (lpmap) {
276                 __lpmap_blockallsigs = NULL;
277                 *datap = NULL;
278                 munmap(lpmap, LPMAP_MAPSIZE);
279         }
280 }
281
282 /*
283  * upmap initialization code, _upmap_thr_init() is called for the initial
284  * main thread by libc or pthreads, and on every thread create.  We need
285  * the __lpmap_blockallsigs pointer ASAP because it is used everywhere in
286  * pthreads.
287  *
288  * If pthreads is not linked in, _pthread_once() still runs via a stub in
289  * libc, and _pthread_key_create() is a NOP.
290  *
291  * NOTE: These pthreads calls are stubs when pthreads is not linked in.
292  *       The once routine will still be run once regardless.
293  */
294 static
295 void
296 _upmap_init_once(void)
297 {
298         /* ignore error from stub if not threaded */
299         _pthread_key_create(&lpmap_key, (void (*)(void *))lpmap_unmap);
300 }
301
302 void
303 _upmap_thr_init(void)
304 {
305         int dummy_state = 0;
306
307         _pthread_once(&upmap_once, _upmap_init_once);
308         __lpmap_map(&__lpmap_blockallsigs, &dummy_state, LPTYPE_BLOCKALLSIGS);
309 }