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 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 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 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 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 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 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 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