xref: /netbsd-src/sys/rump/net/lib/libshmif/shmif_user.c (revision a57097d054360e98c1663784f42b0697fa32bfd6)
1 /*      $NetBSD: shmif_user.c,v 1.3 2018/12/12 00:48:44 alnsn 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 __KERNEL_RCSID(0, "$NetBSD: shmif_user.c,v 1.3 2018/12/12 00:48:44 alnsn Exp $");
30 
31 #ifndef _KERNEL
32 #include <sys/types.h>
33 #include <sys/mman.h>
34 
35 #include <errno.h>
36 #include <unistd.h>
37 
38 #include <rump/rumpuser_component.h>
39 
40 #include "shmif_user.h"
41 
42 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
43 
44 /*
45  * On BSD we use kqueue, on Linux we use inotify.  The underlying
46  * interface requirements aren't quite the same, but we have a very
47  * good chance of doing the fd->path mapping on Linux thanks to dcache,
48  * so just keep the existing interfaces for now.
49  */
50 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
51     || defined(__OpenBSD__)
52 #include <sys/event.h>
53 
54 #include <stdlib.h>
55 
56 int
57 rumpcomp_shmif_watchsetup(int *kqp, int fd)
58 {
59 	struct kevent kev;
60 	int rv, kq;
61 
62 	kq = *kqp;
63 	if (kq == -1) {
64 		kq = kqueue();
65 		if (kq == -1) {
66 			rv = errno;
67 			goto out;
68 		}
69 	}
70 
71 	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
72 	    NOTE_WRITE, 0, 0);
73 	if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
74 		rv = errno;
75 	} else {
76 		rv = 0;
77 		*kqp = kq;
78 	}
79 
80  out:
81 	return rumpuser_component_errtrans(rv);
82 }
83 
84 int
85 rumpcomp_shmif_watchwait(int kq)
86 {
87 	void *cookie;
88 	struct kevent kev;
89 	int rv;
90 
91 	cookie = rumpuser_component_unschedule();
92 	do {
93 		rv = kevent(kq, NULL, 0, &kev, 1, NULL);
94 	} while (rv == -1 && errno == EINTR);
95 	if (rv == -1) {
96 		rv = errno;
97 	} else {
98 		rv = 0;
99 	}
100 	rumpuser_component_schedule(cookie);
101 
102 	return rumpuser_component_errtrans(rv);
103 }
104 
105 #elif defined(__linux__)
106 #include <sys/inotify.h>
107 
108 #include <limits.h>
109 #include <stdio.h>
110 
111 int
112 rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
113 {
114 	char procbuf[PATH_MAX], linkbuf[PATH_MAX];
115 	ssize_t nn;
116 	int inotify, rv;
117 
118 	inotify = *inotifyp;
119 	if (inotify == -1) {
120 		inotify = inotify_init();
121 		if (inotify == -1) {
122 			rv = errno;
123 			goto out;
124 		}
125 	}
126 
127 	/* ok, need to map fd into path for inotify */
128 	snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
129 	nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
130 	if (nn >= (ssize_t)sizeof(linkbuf)-1) {
131 		nn = -1;
132 		errno = E2BIG; /* pick something */
133 	}
134 	if (nn == -1) {
135 		rv = errno;
136 		close(inotify);
137 		goto out;
138 	}
139 
140 	linkbuf[nn] = '\0';
141 	if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
142 		rv = errno;
143 		close(inotify);
144 		goto out;
145 	}
146 	rv = 0;
147 	*inotifyp = inotify;
148 
149  out:
150 	return rumpuser_component_errtrans(rv);
151 }
152 
153 int
154 rumpcomp_shmif_watchwait(int kq)
155 {
156 	struct inotify_event iev;
157 	void *cookie;
158 	ssize_t nn;
159 	int rv;
160 
161 	cookie = rumpuser_component_unschedule();
162 	do {
163 		nn = read(kq, &iev, sizeof(iev));
164 	} while (nn == -1 && errno == EINTR);
165 	if (nn == -1) {
166 		rv = errno;
167 	} else {
168 		rv = 0;
169 	}
170 
171 	rumpuser_component_schedule(cookie);
172 
173 	return rumpuser_component_errtrans(rv);
174 }
175 
176 #else
177 #include <stdio.h>
178 
179 /* a polling default implementation */
180 int
181 rumpcomp_shmif_watchsetup(int *nono, int fd)
182 {
183 	static int warned = 0;
184 
185 	if (!warned) {
186 		fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
187 		    "polling-only on this platform\n");
188 		warned = 1;
189 	}
190 
191 	return 0;
192 }
193 
194 int
195 rumpcomp_shmif_watchwait(int kq)
196 {
197 	void *cookie;
198 
199 	cookie = rumpuser_component_unschedule();
200 	usleep(10000);
201 	rumpuser_component_schedule(cookie);
202 
203 	return 0;
204 }
205 #endif
206 
207 int
208 rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
209 {
210 	void *mem;
211 	int rv;
212 
213 	if (ftruncate(fd, len) == -1) {
214 		rv = errno;
215 		goto out;
216 	}
217 
218 #if defined(__sun__) && !defined(MAP_FILE)
219 #define MAP_FILE 0
220 #endif
221 
222 	mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
223 	if (mem == MAP_FAILED) {
224 		rv = errno;
225 	} else {
226 		rv = 0;
227 		*memp = mem;
228 	}
229 
230  out:
231 	return rumpuser_component_errtrans(rv);
232 }
233 #endif
234