1 1.39 thorpej /* $NetBSD: putter.c,v 1.39 2021/09/26 01:16:09 thorpej Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2006, 2007 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Ulla Tuominen Foundation and the Finnish Cultural Foundation and the 8 1.1 pooka * Research Foundation of Helsinki University of Technology 9 1.1 pooka * 10 1.1 pooka * Redistribution and use in source and binary forms, with or without 11 1.1 pooka * modification, are permitted provided that the following conditions 12 1.1 pooka * are met: 13 1.1 pooka * 1. Redistributions of source code must retain the above copyright 14 1.1 pooka * notice, this list of conditions and the following disclaimer. 15 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer in the 17 1.1 pooka * documentation and/or other materials provided with the distribution. 18 1.1 pooka * 19 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 pooka * SUCH DAMAGE. 30 1.1 pooka */ 31 1.1 pooka 32 1.1 pooka /* 33 1.1 pooka * Pass-to-Userspace TransporTER: generic kernel-user request-response 34 1.1 pooka * transport interface. 35 1.1 pooka */ 36 1.1 pooka 37 1.1 pooka #include <sys/cdefs.h> 38 1.39 thorpej __KERNEL_RCSID(0, "$NetBSD: putter.c,v 1.39 2021/09/26 01:16:09 thorpej Exp $"); 39 1.1 pooka 40 1.1 pooka #include <sys/param.h> 41 1.13 ad #include <sys/systm.h> 42 1.1 pooka #include <sys/conf.h> 43 1.1 pooka #include <sys/file.h> 44 1.1 pooka #include <sys/filedesc.h> 45 1.1 pooka #include <sys/kmem.h> 46 1.1 pooka #include <sys/poll.h> 47 1.22 christos #include <sys/stat.h> 48 1.1 pooka #include <sys/socketvar.h> 49 1.10 jmcneill #include <sys/module.h> 50 1.23 christos #include <sys/kauth.h> 51 1.1 pooka 52 1.2 pooka #include <dev/putter/putter_sys.h> 53 1.1 pooka 54 1.1 pooka /* 55 1.27 pooka * Device routines. These are for when /dev/putter is initially 56 1.22 christos * opened before it has been cloned. 57 1.22 christos */ 58 1.22 christos 59 1.22 christos dev_type_open(puttercdopen); 60 1.22 christos dev_type_close(puttercdclose); 61 1.22 christos dev_type_ioctl(puttercdioctl); 62 1.22 christos 63 1.22 christos /* dev */ 64 1.22 christos const struct cdevsw putter_cdevsw = { 65 1.34 dholland .d_open = puttercdopen, 66 1.34 dholland .d_close = puttercdclose, 67 1.34 dholland .d_read = noread, 68 1.34 dholland .d_write = nowrite, 69 1.34 dholland .d_ioctl = noioctl, 70 1.34 dholland .d_stop = nostop, 71 1.34 dholland .d_tty = notty, 72 1.34 dholland .d_poll = nopoll, 73 1.34 dholland .d_mmap = nommap, 74 1.34 dholland .d_kqfilter = nokqfilter, 75 1.35 dholland .d_discard = nodiscard, 76 1.34 dholland .d_flag = D_OTHER 77 1.22 christos }; 78 1.22 christos 79 1.22 christos /* 80 1.5 pooka * Configuration data. 81 1.5 pooka * 82 1.5 pooka * This is static-size for now. Will be redone for devfs. 83 1.5 pooka */ 84 1.5 pooka 85 1.5 pooka #define PUTTER_CONFSIZE 16 86 1.5 pooka 87 1.5 pooka static struct putter_config { 88 1.5 pooka int pc_minor; 89 1.5 pooka int (*pc_config)(int, int, int); 90 1.5 pooka } putterconf[PUTTER_CONFSIZE]; 91 1.5 pooka 92 1.5 pooka static int 93 1.5 pooka putter_configure(dev_t dev, int flags, int fmt, int fd) 94 1.5 pooka { 95 1.5 pooka struct putter_config *pc; 96 1.5 pooka 97 1.5 pooka /* are we the catch-all node? */ 98 1.5 pooka if (minor(dev) == PUTTER_MINOR_WILDCARD 99 1.5 pooka || minor(dev) == PUTTER_MINOR_COMPAT) 100 1.5 pooka return 0; 101 1.5 pooka 102 1.5 pooka /* nopes? try to configure us */ 103 1.5 pooka for (pc = putterconf; pc->pc_config; pc++) 104 1.5 pooka if (minor(dev) == pc->pc_minor) 105 1.5 pooka return pc->pc_config(fd, flags, fmt); 106 1.5 pooka return ENXIO; 107 1.5 pooka } 108 1.5 pooka 109 1.5 pooka int 110 1.5 pooka putter_register(putter_config_fn pcfn, int minor) 111 1.5 pooka { 112 1.5 pooka int i; 113 1.5 pooka 114 1.5 pooka for (i = 0; i < PUTTER_CONFSIZE; i++) 115 1.5 pooka if (putterconf[i].pc_config == NULL) 116 1.5 pooka break; 117 1.5 pooka if (i == PUTTER_CONFSIZE) 118 1.5 pooka return EBUSY; 119 1.5 pooka 120 1.5 pooka putterconf[i].pc_minor = minor; 121 1.5 pooka putterconf[i].pc_config = pcfn; 122 1.5 pooka return 0; 123 1.5 pooka } 124 1.5 pooka 125 1.5 pooka /* 126 1.1 pooka * putter instance structures. these are always allocated and freed 127 1.1 pooka * from the context of the transport user. 128 1.1 pooka */ 129 1.1 pooka struct putter_instance { 130 1.1 pooka pid_t pi_pid; 131 1.1 pooka int pi_idx; 132 1.1 pooka int pi_fd; 133 1.1 pooka struct selinfo pi_sel; 134 1.1 pooka 135 1.1 pooka void *pi_private; 136 1.1 pooka struct putter_ops *pi_pop; 137 1.1 pooka 138 1.1 pooka uint8_t *pi_curput; 139 1.1 pooka size_t pi_curres; 140 1.1 pooka void *pi_curopaq; 141 1.22 christos struct timespec pi_atime; 142 1.22 christos struct timespec pi_mtime; 143 1.22 christos struct timespec pi_btime; 144 1.1 pooka 145 1.1 pooka TAILQ_ENTRY(putter_instance) pi_entries; 146 1.1 pooka }; 147 1.1 pooka #define PUTTER_EMBRYO ((void *)-1) /* before attach */ 148 1.1 pooka #define PUTTER_DEAD ((void *)-2) /* after detach */ 149 1.1 pooka 150 1.1 pooka static TAILQ_HEAD(, putter_instance) putter_ilist 151 1.1 pooka = TAILQ_HEAD_INITIALIZER(putter_ilist); 152 1.1 pooka 153 1.1 pooka static int get_pi_idx(struct putter_instance *); 154 1.1 pooka 155 1.1 pooka #ifdef DEBUG 156 1.1 pooka #ifndef PUTTERDEBUG 157 1.1 pooka #define PUTTERDEBUG 158 1.1 pooka #endif 159 1.1 pooka #endif 160 1.1 pooka 161 1.1 pooka #ifdef PUTTERDEBUG 162 1.7 pooka int putterdebug = 0; 163 1.1 pooka #define DPRINTF(x) if (putterdebug > 0) printf x 164 1.1 pooka #define DPRINTF_VERBOSE(x) if (putterdebug > 1) printf x 165 1.1 pooka #else 166 1.1 pooka #define DPRINTF(x) 167 1.1 pooka #define DPRINTF_VERBOSE(x) 168 1.1 pooka #endif 169 1.1 pooka 170 1.1 pooka /* 171 1.1 pooka * public init / deinit 172 1.1 pooka */ 173 1.1 pooka 174 1.1 pooka /* protects both the list and the contents of the list elements */ 175 1.1 pooka static kmutex_t pi_mtx; 176 1.1 pooka 177 1.1 pooka void putterattach(void); 178 1.1 pooka 179 1.1 pooka void 180 1.20 cegger putterattach(void) 181 1.1 pooka { 182 1.1 pooka 183 1.1 pooka mutex_init(&pi_mtx, MUTEX_DEFAULT, IPL_NONE); 184 1.1 pooka } 185 1.1 pooka 186 1.1 pooka #if 0 187 1.1 pooka void 188 1.20 cegger putter_destroy(void) 189 1.1 pooka { 190 1.1 pooka 191 1.1 pooka mutex_destroy(&pi_mtx); 192 1.1 pooka } 193 1.1 pooka #endif 194 1.1 pooka 195 1.1 pooka /* 196 1.1 pooka * fd routines, for cloner 197 1.1 pooka */ 198 1.9 ad static int putter_fop_read(file_t *, off_t *, struct uio *, 199 1.1 pooka kauth_cred_t, int); 200 1.9 ad static int putter_fop_write(file_t *, off_t *, struct uio *, 201 1.1 pooka kauth_cred_t, int); 202 1.9 ad static int putter_fop_ioctl(file_t*, u_long, void *); 203 1.9 ad static int putter_fop_poll(file_t *, int); 204 1.22 christos static int putter_fop_stat(file_t *, struct stat *); 205 1.9 ad static int putter_fop_close(file_t *); 206 1.9 ad static int putter_fop_kqfilter(file_t *, struct knote *); 207 1.1 pooka 208 1.1 pooka 209 1.1 pooka static const struct fileops putter_fileops = { 210 1.37 christos .fo_name = "putter", 211 1.21 ad .fo_read = putter_fop_read, 212 1.21 ad .fo_write = putter_fop_write, 213 1.21 ad .fo_ioctl = putter_fop_ioctl, 214 1.21 ad .fo_fcntl = fnullop_fcntl, 215 1.21 ad .fo_poll = putter_fop_poll, 216 1.22 christos .fo_stat = putter_fop_stat, 217 1.21 ad .fo_close = putter_fop_close, 218 1.21 ad .fo_kqfilter = putter_fop_kqfilter, 219 1.26 dsl .fo_restart = fnullop_restart, 220 1.1 pooka }; 221 1.1 pooka 222 1.1 pooka static int 223 1.9 ad putter_fop_read(file_t *fp, off_t *off, struct uio *uio, 224 1.1 pooka kauth_cred_t cred, int flags) 225 1.1 pooka { 226 1.1 pooka struct putter_instance *pi = fp->f_data; 227 1.1 pooka size_t origres, moved; 228 1.1 pooka int error; 229 1.1 pooka 230 1.23 christos KERNEL_LOCK(1, NULL); 231 1.22 christos getnanotime(&pi->pi_atime); 232 1.13 ad 233 1.1 pooka if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 234 1.1 pooka printf("putter_fop_read: private %d not inited\n", pi->pi_idx); 235 1.13 ad KERNEL_UNLOCK_ONE(NULL); 236 1.1 pooka return ENOENT; 237 1.1 pooka } 238 1.1 pooka 239 1.1 pooka if (pi->pi_curput == NULL) { 240 1.1 pooka error = pi->pi_pop->pop_getout(pi->pi_private, uio->uio_resid, 241 1.1 pooka fp->f_flag & O_NONBLOCK, &pi->pi_curput, 242 1.1 pooka &pi->pi_curres, &pi->pi_curopaq); 243 1.13 ad if (error) { 244 1.13 ad KERNEL_UNLOCK_ONE(NULL); 245 1.1 pooka return error; 246 1.13 ad } 247 1.1 pooka } 248 1.1 pooka 249 1.1 pooka origres = uio->uio_resid; 250 1.1 pooka error = uiomove(pi->pi_curput, pi->pi_curres, uio); 251 1.1 pooka moved = origres - uio->uio_resid; 252 1.1 pooka DPRINTF(("putter_fop_read (%p): moved %zu bytes from %p, error %d\n", 253 1.1 pooka pi, moved, pi->pi_curput, error)); 254 1.1 pooka 255 1.1 pooka KASSERT(pi->pi_curres >= moved); 256 1.1 pooka pi->pi_curres -= moved; 257 1.1 pooka pi->pi_curput += moved; 258 1.1 pooka 259 1.1 pooka if (pi->pi_curres == 0) { 260 1.1 pooka pi->pi_pop->pop_releaseout(pi->pi_private, 261 1.1 pooka pi->pi_curopaq, error); 262 1.1 pooka pi->pi_curput = NULL; 263 1.1 pooka } 264 1.1 pooka 265 1.13 ad KERNEL_UNLOCK_ONE(NULL); 266 1.1 pooka return error; 267 1.1 pooka } 268 1.1 pooka 269 1.1 pooka static int 270 1.9 ad putter_fop_write(file_t *fp, off_t *off, struct uio *uio, 271 1.1 pooka kauth_cred_t cred, int flags) 272 1.1 pooka { 273 1.1 pooka struct putter_instance *pi = fp->f_data; 274 1.2 pooka struct putter_hdr pth; 275 1.1 pooka uint8_t *buf; 276 1.1 pooka size_t frsize; 277 1.1 pooka int error; 278 1.1 pooka 279 1.23 christos KERNEL_LOCK(1, NULL); 280 1.22 christos getnanotime(&pi->pi_mtime); 281 1.13 ad 282 1.2 pooka DPRINTF(("putter_fop_write (%p): writing response, resid %zu\n", 283 1.1 pooka pi->pi_private, uio->uio_resid)); 284 1.1 pooka 285 1.1 pooka if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 286 1.1 pooka printf("putter_fop_write: putter %d not inited\n", pi->pi_idx); 287 1.13 ad KERNEL_UNLOCK_ONE(NULL); 288 1.1 pooka return ENOENT; 289 1.1 pooka } 290 1.1 pooka 291 1.2 pooka error = uiomove(&pth, sizeof(struct putter_hdr), uio); 292 1.13 ad if (error) { 293 1.13 ad KERNEL_UNLOCK_ONE(NULL); 294 1.1 pooka return error; 295 1.13 ad } 296 1.1 pooka 297 1.1 pooka /* Sorry mate, the kernel doesn't buffer. */ 298 1.2 pooka frsize = pth.pth_framelen - sizeof(struct putter_hdr); 299 1.13 ad if (uio->uio_resid < frsize) { 300 1.13 ad KERNEL_UNLOCK_ONE(NULL); 301 1.1 pooka return EINVAL; 302 1.13 ad } 303 1.1 pooka 304 1.2 pooka buf = kmem_alloc(frsize + sizeof(struct putter_hdr), KM_SLEEP); 305 1.2 pooka memcpy(buf, &pth, sizeof(pth)); 306 1.2 pooka error = uiomove(buf+sizeof(struct putter_hdr), frsize, uio); 307 1.1 pooka if (error == 0) { 308 1.3 pooka pi->pi_pop->pop_dispatch(pi->pi_private, 309 1.3 pooka (struct putter_hdr *)buf); 310 1.1 pooka } 311 1.2 pooka kmem_free(buf, frsize + sizeof(struct putter_hdr)); 312 1.1 pooka 313 1.13 ad KERNEL_UNLOCK_ONE(NULL); 314 1.1 pooka return error; 315 1.1 pooka } 316 1.1 pooka 317 1.1 pooka /* 318 1.1 pooka * Poll query interface. The question is only if an event 319 1.2 pooka * can be read from us. 320 1.1 pooka */ 321 1.1 pooka #define PUTTERPOLL_EVSET (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI) 322 1.1 pooka static int 323 1.9 ad putter_fop_poll(file_t *fp, int events) 324 1.1 pooka { 325 1.1 pooka struct putter_instance *pi = fp->f_data; 326 1.1 pooka int revents; 327 1.1 pooka 328 1.13 ad KERNEL_LOCK(1, NULL); 329 1.13 ad 330 1.1 pooka if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) { 331 1.1 pooka printf("putter_fop_ioctl: putter %d not inited\n", pi->pi_idx); 332 1.13 ad KERNEL_UNLOCK_ONE(NULL); 333 1.1 pooka return ENOENT; 334 1.1 pooka } 335 1.1 pooka 336 1.1 pooka revents = events & (POLLOUT | POLLWRNORM | POLLWRBAND); 337 1.13 ad if ((events & PUTTERPOLL_EVSET) == 0) { 338 1.13 ad KERNEL_UNLOCK_ONE(NULL); 339 1.1 pooka return revents; 340 1.13 ad } 341 1.1 pooka 342 1.1 pooka /* check queue */ 343 1.1 pooka if (pi->pi_pop->pop_waitcount(pi->pi_private)) 344 1.1 pooka revents |= PUTTERPOLL_EVSET; 345 1.1 pooka else 346 1.9 ad selrecord(curlwp, &pi->pi_sel); 347 1.1 pooka 348 1.13 ad KERNEL_UNLOCK_ONE(NULL); 349 1.1 pooka return revents; 350 1.1 pooka } 351 1.1 pooka 352 1.1 pooka /* 353 1.1 pooka * device close = forced unmount. 354 1.1 pooka * 355 1.1 pooka * unmounting is a frightfully complex operation to avoid races 356 1.1 pooka */ 357 1.1 pooka static int 358 1.9 ad putter_fop_close(file_t *fp) 359 1.1 pooka { 360 1.1 pooka struct putter_instance *pi = fp->f_data; 361 1.1 pooka int rv; 362 1.1 pooka 363 1.1 pooka DPRINTF(("putter_fop_close: device closed\n")); 364 1.1 pooka 365 1.13 ad KERNEL_LOCK(1, NULL); 366 1.13 ad 367 1.1 pooka restart: 368 1.1 pooka mutex_enter(&pi_mtx); 369 1.1 pooka /* 370 1.27 pooka * First check if the driver was never born. In that case 371 1.1 pooka * remove the instance from the list. If mount is attempted later, 372 1.1 pooka * it will simply fail. 373 1.1 pooka */ 374 1.1 pooka if (pi->pi_private == PUTTER_EMBRYO) { 375 1.1 pooka TAILQ_REMOVE(&putter_ilist, pi, pi_entries); 376 1.1 pooka mutex_exit(&pi_mtx); 377 1.1 pooka 378 1.1 pooka DPRINTF(("putter_fop_close: data associated with fp %p was " 379 1.1 pooka "embryonic\n", fp)); 380 1.1 pooka 381 1.1 pooka goto out; 382 1.1 pooka } 383 1.1 pooka 384 1.1 pooka /* 385 1.1 pooka * Next, analyze if unmount was called and the instance is dead. 386 1.1 pooka * In this case we can just free the structure and go home, it 387 1.1 pooka * was removed from the list by putter_rmprivate(). 388 1.1 pooka */ 389 1.1 pooka if (pi->pi_private == PUTTER_DEAD) { 390 1.1 pooka mutex_exit(&pi_mtx); 391 1.1 pooka 392 1.1 pooka DPRINTF(("putter_fop_close: putter associated with fp %p (%d) " 393 1.1 pooka "dead, freeing\n", fp, pi->pi_idx)); 394 1.1 pooka 395 1.1 pooka goto out; 396 1.1 pooka } 397 1.1 pooka 398 1.1 pooka /* 399 1.27 pooka * So we have a reference. Proceed to unravel the 400 1.27 pooka * underlying driver. 401 1.1 pooka */ 402 1.1 pooka mutex_exit(&pi_mtx); 403 1.1 pooka 404 1.1 pooka /* hmm? suspicious locking? */ 405 1.33 yamt if (pi->pi_curput != NULL) { 406 1.33 yamt pi->pi_pop->pop_releaseout(pi->pi_private, pi->pi_curopaq, 407 1.33 yamt ENXIO); 408 1.33 yamt pi->pi_curput = NULL; 409 1.33 yamt } 410 1.1 pooka while ((rv = pi->pi_pop->pop_close(pi->pi_private)) == ERESTART) 411 1.1 pooka goto restart; 412 1.1 pooka 413 1.1 pooka out: 414 1.13 ad KERNEL_UNLOCK_ONE(NULL); 415 1.1 pooka /* 416 1.1 pooka * Finally, release the instance information. It was already 417 1.1 pooka * removed from the list by putter_rmprivate() and we know it's 418 1.1 pooka * dead, so no need to lock. 419 1.1 pooka */ 420 1.1 pooka kmem_free(pi, sizeof(struct putter_instance)); 421 1.1 pooka 422 1.1 pooka return 0; 423 1.1 pooka } 424 1.1 pooka 425 1.1 pooka static int 426 1.22 christos putter_fop_stat(file_t *fp, struct stat *st) 427 1.22 christos { 428 1.22 christos struct putter_instance *pi = fp->f_data; 429 1.22 christos 430 1.22 christos (void)memset(st, 0, sizeof(*st)); 431 1.22 christos KERNEL_LOCK(1, NULL); 432 1.22 christos st->st_dev = makedev(cdevsw_lookup_major(&putter_cdevsw), pi->pi_idx); 433 1.22 christos st->st_atimespec = pi->pi_atime; 434 1.22 christos st->st_mtimespec = pi->pi_mtime; 435 1.22 christos st->st_ctimespec = st->st_birthtimespec = pi->pi_btime; 436 1.23 christos st->st_uid = kauth_cred_geteuid(fp->f_cred); 437 1.23 christos st->st_gid = kauth_cred_getegid(fp->f_cred); 438 1.32 hannken st->st_mode = S_IFCHR; 439 1.22 christos KERNEL_UNLOCK_ONE(NULL); 440 1.22 christos return 0; 441 1.22 christos } 442 1.22 christos 443 1.22 christos static int 444 1.9 ad putter_fop_ioctl(file_t *fp, u_long cmd, void *data) 445 1.1 pooka { 446 1.1 pooka 447 1.1 pooka /* 448 1.1 pooka * work already done in sys_ioctl(). skip sanity checks to enable 449 1.27 pooka * setting non-blocking fd on an embryotic driver. 450 1.1 pooka */ 451 1.1 pooka if (cmd == FIONBIO) 452 1.1 pooka return 0; 453 1.1 pooka 454 1.1 pooka return EINVAL; 455 1.1 pooka } 456 1.1 pooka 457 1.1 pooka /* kqueue stuff */ 458 1.1 pooka 459 1.1 pooka static void 460 1.1 pooka filt_putterdetach(struct knote *kn) 461 1.1 pooka { 462 1.1 pooka struct putter_instance *pi = kn->kn_hook; 463 1.1 pooka 464 1.13 ad KERNEL_LOCK(1, NULL); 465 1.1 pooka mutex_enter(&pi_mtx); 466 1.38 thorpej selremove_knote(&pi->pi_sel, kn); 467 1.1 pooka mutex_exit(&pi_mtx); 468 1.13 ad KERNEL_UNLOCK_ONE(NULL); 469 1.1 pooka } 470 1.1 pooka 471 1.1 pooka static int 472 1.6 pooka filt_putter(struct knote *kn, long hint) 473 1.1 pooka { 474 1.1 pooka struct putter_instance *pi = kn->kn_hook; 475 1.13 ad int error, rv; 476 1.1 pooka 477 1.13 ad KERNEL_LOCK(1, NULL); 478 1.1 pooka error = 0; 479 1.1 pooka mutex_enter(&pi_mtx); 480 1.1 pooka if (pi->pi_private == PUTTER_EMBRYO || pi->pi_private == PUTTER_DEAD) 481 1.1 pooka error = 1; 482 1.1 pooka mutex_exit(&pi_mtx); 483 1.13 ad if (error) { 484 1.13 ad KERNEL_UNLOCK_ONE(NULL); 485 1.1 pooka return 0; 486 1.13 ad } 487 1.1 pooka 488 1.1 pooka kn->kn_data = pi->pi_pop->pop_waitcount(pi->pi_private); 489 1.13 ad rv = kn->kn_data != 0; 490 1.13 ad KERNEL_UNLOCK_ONE(NULL); 491 1.13 ad return rv; 492 1.1 pooka } 493 1.1 pooka 494 1.36 maya static const struct filterops putter_filtops = { 495 1.39 thorpej .f_flags = FILTEROP_ISFD, 496 1.36 maya .f_attach = NULL, 497 1.36 maya .f_detach = filt_putterdetach, 498 1.36 maya .f_event = filt_putter, 499 1.36 maya }; 500 1.1 pooka 501 1.1 pooka static int 502 1.9 ad putter_fop_kqfilter(file_t *fp, struct knote *kn) 503 1.1 pooka { 504 1.1 pooka struct putter_instance *pi = fp->f_data; 505 1.1 pooka 506 1.13 ad KERNEL_LOCK(1, NULL); 507 1.13 ad 508 1.6 pooka switch (kn->kn_filter) { 509 1.6 pooka case EVFILT_READ: 510 1.6 pooka kn->kn_fop = &putter_filtops; 511 1.6 pooka kn->kn_hook = pi; 512 1.1 pooka 513 1.6 pooka mutex_enter(&pi_mtx); 514 1.38 thorpej selrecord_knote(&pi->pi_sel, kn); 515 1.6 pooka mutex_exit(&pi_mtx); 516 1.1 pooka 517 1.6 pooka break; 518 1.6 pooka case EVFILT_WRITE: 519 1.6 pooka kn->kn_fop = &seltrue_filtops; 520 1.6 pooka break; 521 1.6 pooka default: 522 1.13 ad KERNEL_UNLOCK_ONE(NULL); 523 1.6 pooka return EINVAL; 524 1.6 pooka } 525 1.1 pooka 526 1.13 ad KERNEL_UNLOCK_ONE(NULL); 527 1.1 pooka return 0; 528 1.1 pooka } 529 1.1 pooka 530 1.1 pooka int 531 1.1 pooka puttercdopen(dev_t dev, int flags, int fmt, struct lwp *l) 532 1.1 pooka { 533 1.1 pooka struct putter_instance *pi; 534 1.9 ad file_t *fp; 535 1.1 pooka int error, fd, idx; 536 1.9 ad proc_t *p; 537 1.1 pooka 538 1.9 ad p = curproc; 539 1.1 pooka pi = kmem_alloc(sizeof(struct putter_instance), KM_SLEEP); 540 1.1 pooka mutex_enter(&pi_mtx); 541 1.1 pooka idx = get_pi_idx(pi); 542 1.1 pooka 543 1.9 ad pi->pi_pid = p->p_pid; 544 1.1 pooka pi->pi_idx = idx; 545 1.1 pooka pi->pi_curput = NULL; 546 1.1 pooka pi->pi_curres = 0; 547 1.1 pooka pi->pi_curopaq = NULL; 548 1.22 christos getnanotime(&pi->pi_btime); 549 1.22 christos pi->pi_atime = pi->pi_mtime = pi->pi_btime; 550 1.4 pooka selinit(&pi->pi_sel); 551 1.1 pooka mutex_exit(&pi_mtx); 552 1.1 pooka 553 1.9 ad if ((error = fd_allocfile(&fp, &fd)) != 0) 554 1.5 pooka goto bad1; 555 1.5 pooka 556 1.5 pooka if ((error = putter_configure(dev, flags, fmt, fd)) != 0) 557 1.5 pooka goto bad2; 558 1.5 pooka 559 1.1 pooka DPRINTF(("puttercdopen: registered embryonic pmp for pid: %d\n", 560 1.1 pooka pi->pi_pid)); 561 1.1 pooka 562 1.9 ad error = fd_clone(fp, fd, FREAD|FWRITE, &putter_fileops, pi); 563 1.16 pooka KASSERT(error == EMOVEFD); 564 1.5 pooka return error; 565 1.5 pooka 566 1.5 pooka bad2: 567 1.9 ad fd_abort(p, fp, fd); 568 1.5 pooka bad1: 569 1.5 pooka putter_detach(pi); 570 1.5 pooka kmem_free(pi, sizeof(struct putter_instance)); 571 1.5 pooka return error; 572 1.1 pooka } 573 1.1 pooka 574 1.1 pooka int 575 1.1 pooka puttercdclose(dev_t dev, int flags, int fmt, struct lwp *l) 576 1.1 pooka { 577 1.1 pooka 578 1.1 pooka panic("puttercdclose impossible\n"); 579 1.1 pooka 580 1.1 pooka return 0; 581 1.1 pooka } 582 1.1 pooka 583 1.1 pooka 584 1.1 pooka /* 585 1.1 pooka * Set the private structure for the file descriptor. This is 586 1.1 pooka * typically done immediately when the counterpart has knowledge 587 1.1 pooka * about the private structure's address and the file descriptor 588 1.1 pooka * (e.g. vfs mount routine). 589 1.1 pooka * 590 1.1 pooka * We only want to make sure that the caller had the right to open the 591 1.1 pooka * device, we don't so much care about which context it gets in case 592 1.1 pooka * the same process opened multiple (since they are equal at this point). 593 1.1 pooka */ 594 1.1 pooka struct putter_instance * 595 1.1 pooka putter_attach(pid_t pid, int fd, void *ppriv, struct putter_ops *pop) 596 1.1 pooka { 597 1.1 pooka struct putter_instance *pi = NULL; 598 1.1 pooka 599 1.1 pooka mutex_enter(&pi_mtx); 600 1.1 pooka TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { 601 1.1 pooka if (pi->pi_pid == pid && pi->pi_private == PUTTER_EMBRYO) { 602 1.1 pooka pi->pi_private = ppriv; 603 1.1 pooka pi->pi_fd = fd; 604 1.1 pooka pi->pi_pop = pop; 605 1.1 pooka break; 606 1.1 pooka } 607 1.1 pooka } 608 1.1 pooka mutex_exit(&pi_mtx); 609 1.1 pooka 610 1.1 pooka DPRINTF(("putter_setprivate: pi at %p (%d/%d)\n", pi, 611 1.1 pooka pi ? pi->pi_pid : 0, pi ? pi->pi_fd : 0)); 612 1.1 pooka 613 1.1 pooka return pi; 614 1.1 pooka } 615 1.1 pooka 616 1.1 pooka /* 617 1.1 pooka * Remove fp <-> private mapping. 618 1.1 pooka */ 619 1.1 pooka void 620 1.1 pooka putter_detach(struct putter_instance *pi) 621 1.1 pooka { 622 1.1 pooka 623 1.1 pooka mutex_enter(&pi_mtx); 624 1.1 pooka TAILQ_REMOVE(&putter_ilist, pi, pi_entries); 625 1.1 pooka pi->pi_private = PUTTER_DEAD; 626 1.1 pooka mutex_exit(&pi_mtx); 627 1.29 pooka seldestroy(&pi->pi_sel); 628 1.1 pooka 629 1.1 pooka DPRINTF(("putter_nukebypmp: nuked %p\n", pi)); 630 1.1 pooka } 631 1.1 pooka 632 1.1 pooka void 633 1.1 pooka putter_notify(struct putter_instance *pi) 634 1.1 pooka { 635 1.1 pooka 636 1.8 rmind selnotify(&pi->pi_sel, 0, 0); 637 1.1 pooka } 638 1.1 pooka 639 1.1 pooka /* search sorted list of instances for free minor, sorted insert arg */ 640 1.1 pooka static int 641 1.1 pooka get_pi_idx(struct putter_instance *pi_i) 642 1.1 pooka { 643 1.1 pooka struct putter_instance *pi; 644 1.1 pooka int i; 645 1.1 pooka 646 1.4 pooka KASSERT(mutex_owned(&pi_mtx)); 647 1.4 pooka 648 1.1 pooka i = 0; 649 1.1 pooka TAILQ_FOREACH(pi, &putter_ilist, pi_entries) { 650 1.1 pooka if (i != pi->pi_idx) 651 1.1 pooka break; 652 1.1 pooka i++; 653 1.1 pooka } 654 1.1 pooka 655 1.1 pooka pi_i->pi_private = PUTTER_EMBRYO; 656 1.1 pooka 657 1.1 pooka if (pi == NULL) 658 1.1 pooka TAILQ_INSERT_TAIL(&putter_ilist, pi_i, pi_entries); 659 1.1 pooka else 660 1.1 pooka TAILQ_INSERT_BEFORE(pi, pi_i, pi_entries); 661 1.1 pooka 662 1.1 pooka return i; 663 1.1 pooka } 664 1.10 jmcneill 665 1.31 haad MODULE(MODULE_CLASS_DRIVER, putter, NULL); 666 1.10 jmcneill 667 1.10 jmcneill static int 668 1.10 jmcneill putter_modcmd(modcmd_t cmd, void *arg) 669 1.10 jmcneill { 670 1.18 pooka #ifdef _MODULE 671 1.19 drochner devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; 672 1.10 jmcneill 673 1.10 jmcneill switch (cmd) { 674 1.10 jmcneill case MODULE_CMD_INIT: 675 1.28 pooka putterattach(); 676 1.10 jmcneill return devsw_attach("putter", NULL, &bmajor, 677 1.10 jmcneill &putter_cdevsw, &cmajor); 678 1.10 jmcneill case MODULE_CMD_FINI: 679 1.28 pooka return ENOTTY; /* XXX: putterdetach */ 680 1.10 jmcneill default: 681 1.10 jmcneill return ENOTTY; 682 1.10 jmcneill } 683 1.18 pooka #else 684 1.18 pooka if (cmd == MODULE_CMD_INIT) 685 1.18 pooka return 0; 686 1.18 pooka return ENOTTY; 687 1.18 pooka #endif 688 1.10 jmcneill } 689