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