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