1 /* $NetBSD: shmif_user.c,v 1.1 2014/03/13 01:42:59 pooka 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 33 #include <rump/rumpuser_component.h> 34 35 #include "shmif_user.h" 36 37 #define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0; 38 39 /* 40 * On BSD we use kqueue, on Linux we use inotify. The underlying 41 * interface requirements aren't quite the same, but we have a very 42 * good chance of doing the fd->path mapping on Linux thanks to dcache, 43 * so just keep the existing interfaces for now. 44 */ 45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \ 46 || defined(__OpenBSD__) 47 #include <sys/event.h> 48 49 #include <stdlib.h> 50 51 int 52 rumpcomp_shmif_watchsetup(int *kqp, int fd) 53 { 54 struct kevent kev; 55 int rv, kq; 56 57 kq = *kqp; 58 if (kq == -1) { 59 kq = kqueue(); 60 if (kq == -1) { 61 rv = errno; 62 goto out; 63 } 64 } 65 66 EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR, 67 NOTE_WRITE, 0, 0); 68 if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) { 69 rv = errno; 70 } else { 71 rv = 0; 72 *kqp = kq; 73 } 74 75 out: 76 return rumpuser_component_errtrans(rv); 77 } 78 79 int 80 rumpcomp_shmif_watchwait(int kq) 81 { 82 void *cookie; 83 struct kevent kev; 84 int rv; 85 86 cookie = rumpuser_component_unschedule(); 87 do { 88 rv = kevent(kq, NULL, 0, &kev, 1, NULL); 89 } while (rv == -1 && errno == EINTR); 90 if (rv == -1) { 91 rv = errno; 92 } else { 93 rv = 0; 94 } 95 rumpuser_component_schedule(cookie); 96 97 return rumpuser_component_errtrans(rv); 98 } 99 100 #elif defined(__linux__) 101 #include <sys/inotify.h> 102 103 #include <limits.h> 104 #include <stdio.h> 105 #include <unistd.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 #include <unistd.h> 175 176 /* a polling default implementation */ 177 int 178 rumpcomp_shmif_watchsetup(int *nono, int fd) 179 { 180 static int warned = 0; 181 182 if (!warned) { 183 fprintf(stderr, "WARNING: rumpuser writewatchfile routines are " 184 "polling-only on this platform\n"); 185 warned = 1; 186 } 187 188 return 0; 189 } 190 191 int 192 rumpcomp_shmif_watchwait(int kq) 193 { 194 void *cookie; 195 196 cookie = rumpuser_component_unschedule(); 197 usleep(10000); 198 rumpuser_component_schedule(cookie); 199 200 return 0; 201 } 202 #endif 203 204 int 205 rumpcomp_shmif_mmap(int fd, size_t len, void **memp) 206 { 207 void *mem; 208 int rv; 209 210 if (ftruncate(fd, len) == -1) { 211 rv = errno; 212 goto out; 213 } 214 215 #if defined(__sun__) && !defined(MAP_FILE) 216 #define MAP_FILE 0 217 #endif 218 219 mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0); 220 if (mem == MAP_FAILED) { 221 rv = errno; 222 } else { 223 rv = 0; 224 *memp = mem; 225 } 226 227 out: 228 return rumpuser_component_errtrans(rv); 229 } 230 #endif 231