xref: /netbsd-src/sys/rump/net/lib/libshmif/shmif_user.c (revision e0888b5db503563672b46c6c42066b880d4c1460)
1 /*      $NetBSD: shmif_user.c,v 1.5 2019/03/26 08:56:17 bad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009, 2010 Antti Kantee.  All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #ifdef __KERNEL_RCSID
30 __KERNEL_RCSID(0, "$NetBSD: shmif_user.c,v 1.5 2019/03/26 08:56:17 bad Exp $");
31 #endif
32 
33 #ifndef _KERNEL
34 #include <sys/types.h>
35 #include <sys/mman.h>
36 
37 #include <errno.h>
38 #include <unistd.h>
39 
40 #include <rump/rumpuser_component.h>
41 
42 #include "shmif_user.h"
43 
44 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
45 
46 /*
47  * On BSD we use kqueue, on Linux we use inotify.  The underlying
48  * interface requirements aren't quite the same, but we have a very
49  * good chance of doing the fd->path mapping on Linux thanks to dcache,
50  * so just keep the existing interfaces for now.
51  */
52 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
53     || defined(__OpenBSD__)
54 #include <sys/event.h>
55 
56 #include <stdlib.h>
57 
58 int
rumpcomp_shmif_watchsetup(int * kqp,int fd)59 rumpcomp_shmif_watchsetup(int *kqp, int fd)
60 {
61 	struct kevent kev;
62 	int rv, kq;
63 
64 	kq = *kqp;
65 	if (kq == -1) {
66 		kq = kqueue();
67 		if (kq == -1) {
68 			rv = errno;
69 			goto out;
70 		}
71 	}
72 
73 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
74 	    NOTE_WRITE, 0, 0);
75 	if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
76 		rv = errno;
77 	} else {
78 		rv = 0;
79 		*kqp = kq;
80 	}
81 
82  out:
83 	return rumpuser_component_errtrans(rv);
84 }
85 
86 int
rumpcomp_shmif_watchwait(int kq)87 rumpcomp_shmif_watchwait(int kq)
88 {
89 	void *cookie;
90 	struct kevent kev;
91 	int rv;
92 
93 	cookie = rumpuser_component_unschedule();
94 	do {
95 		rv = kevent(kq, NULL, 0, &kev, 1, NULL);
96 	} while (rv == -1 && errno == EINTR);
97 	if (rv == -1) {
98 		rv = errno;
99 	} else {
100 		rv = 0;
101 	}
102 	rumpuser_component_schedule(cookie);
103 
104 	return rumpuser_component_errtrans(rv);
105 }
106 
107 #elif defined(__linux__)
108 #include <sys/inotify.h>
109 
110 #include <limits.h>
111 #include <stdio.h>
112 
113 int
rumpcomp_shmif_watchsetup(int * inotifyp,int fd)114 rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
115 {
116 	char procbuf[PATH_MAX], linkbuf[PATH_MAX];
117 	ssize_t nn;
118 	int inotify, rv;
119 
120 	inotify = *inotifyp;
121 	if (inotify == -1) {
122 		inotify = inotify_init();
123 		if (inotify == -1) {
124 			rv = errno;
125 			goto out;
126 		}
127 	}
128 
129 	/* ok, need to map fd into path for inotify */
130 	snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
131 	nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
132 	if (nn >= (ssize_t)sizeof(linkbuf)-1) {
133 		nn = -1;
134 		errno = E2BIG; /* pick something */
135 	}
136 	if (nn == -1) {
137 		rv = errno;
138 		close(inotify);
139 		goto out;
140 	}
141 
142 	linkbuf[nn] = '\0';
143 	if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
144 		rv = errno;
145 		close(inotify);
146 		goto out;
147 	}
148 	rv = 0;
149 	*inotifyp = inotify;
150 
151  out:
152 	return rumpuser_component_errtrans(rv);
153 }
154 
155 int
rumpcomp_shmif_watchwait(int kq)156 rumpcomp_shmif_watchwait(int kq)
157 {
158 	struct inotify_event iev;
159 	void *cookie;
160 	ssize_t nn;
161 	int rv;
162 
163 	cookie = rumpuser_component_unschedule();
164 	do {
165 		nn = read(kq, &iev, sizeof(iev));
166 	} while (nn == -1 && errno == EINTR);
167 	if (nn == -1) {
168 		rv = errno;
169 	} else {
170 		rv = 0;
171 	}
172 
173 	rumpuser_component_schedule(cookie);
174 
175 	return rumpuser_component_errtrans(rv);
176 }
177 
178 #else
179 #include <stdio.h>
180 
181 /* a polling default implementation */
182 int
rumpcomp_shmif_watchsetup(int * nono,int fd)183 rumpcomp_shmif_watchsetup(int *nono, int fd)
184 {
185 	static int warned = 0;
186 
187 	if (!warned) {
188 		fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
189 		    "polling-only on this platform\n");
190 		warned = 1;
191 	}
192 
193 	return 0;
194 }
195 
196 int
rumpcomp_shmif_watchwait(int kq)197 rumpcomp_shmif_watchwait(int kq)
198 {
199 	void *cookie;
200 
201 	cookie = rumpuser_component_unschedule();
202 	usleep(10000);
203 	rumpuser_component_schedule(cookie);
204 
205 	return 0;
206 }
207 #endif
208 
209 int
rumpcomp_shmif_mmap(int fd,size_t len,void ** memp)210 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
211 {
212 	void *mem;
213 	int rv;
214 
215 	if (ftruncate(fd, len) == -1) {
216 		rv = errno;
217 		goto out;
218 	}
219 
220 #if defined(__sun__) && !defined(MAP_FILE)
221 #define MAP_FILE 0
222 #endif
223 
224 	mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
225 	if (mem == MAP_FAILED) {
226 		rv = errno;
227 	} else {
228 		rv = 0;
229 		*memp = mem;
230 	}
231 
232  out:
233 	return rumpuser_component_errtrans(rv);
234 }
235 #endif
236