Home | History | Annotate | Line # | Download | only in libshmif
      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