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