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