1*7a202823SKonstantin Belousov /*- 2*7a202823SKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*7a202823SKonstantin Belousov * 4*7a202823SKonstantin Belousov * Copyright (c) 2007 Roman Divacky 5*7a202823SKonstantin Belousov * Copyright (c) 2014 Dmitry Chagin 6*7a202823SKonstantin Belousov * All rights reserved. 7*7a202823SKonstantin Belousov * 8*7a202823SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 9*7a202823SKonstantin Belousov * modification, are permitted provided that the following conditions 10*7a202823SKonstantin Belousov * are met: 11*7a202823SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 12*7a202823SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 13*7a202823SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 14*7a202823SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 15*7a202823SKonstantin Belousov * documentation and/or other materials provided with the distribution. 16*7a202823SKonstantin Belousov * 17*7a202823SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*7a202823SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*7a202823SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*7a202823SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*7a202823SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*7a202823SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*7a202823SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*7a202823SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*7a202823SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*7a202823SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*7a202823SKonstantin Belousov * SUCH DAMAGE. 28*7a202823SKonstantin Belousov */ 29*7a202823SKonstantin Belousov 30*7a202823SKonstantin Belousov #include <sys/cdefs.h> 31*7a202823SKonstantin Belousov __FBSDID("$FreeBSD$"); 32*7a202823SKonstantin Belousov 33*7a202823SKonstantin Belousov #include <sys/param.h> 34*7a202823SKonstantin Belousov #include <sys/systm.h> 35*7a202823SKonstantin Belousov #include <sys/kernel.h> 36*7a202823SKonstantin Belousov #include <sys/malloc.h> 37*7a202823SKonstantin Belousov #include <sys/limits.h> 38*7a202823SKonstantin Belousov #include <sys/lock.h> 39*7a202823SKonstantin Belousov #include <sys/mutex.h> 40*7a202823SKonstantin Belousov #include <sys/types.h> 41*7a202823SKonstantin Belousov #include <sys/user.h> 42*7a202823SKonstantin Belousov #include <sys/fcntl.h> 43*7a202823SKonstantin Belousov #include <sys/file.h> 44*7a202823SKonstantin Belousov #include <sys/filedesc.h> 45*7a202823SKonstantin Belousov #include <sys/filio.h> 46*7a202823SKonstantin Belousov #include <sys/stat.h> 47*7a202823SKonstantin Belousov #include <sys/errno.h> 48*7a202823SKonstantin Belousov #include <sys/event.h> 49*7a202823SKonstantin Belousov #include <sys/poll.h> 50*7a202823SKonstantin Belousov #include <sys/proc.h> 51*7a202823SKonstantin Belousov #include <sys/uio.h> 52*7a202823SKonstantin Belousov #include <sys/selinfo.h> 53*7a202823SKonstantin Belousov #include <sys/eventfd.h> 54*7a202823SKonstantin Belousov 55*7a202823SKonstantin Belousov #include <security/audit/audit.h> 56*7a202823SKonstantin Belousov 57*7a202823SKonstantin Belousov _Static_assert(EFD_CLOEXEC == O_CLOEXEC, "Mismatched EFD_CLOEXEC"); 58*7a202823SKonstantin Belousov _Static_assert(EFD_NONBLOCK == O_NONBLOCK, "Mismatched EFD_NONBLOCK"); 59*7a202823SKonstantin Belousov 60*7a202823SKonstantin Belousov MALLOC_DEFINE(M_EVENTFD, "eventfd", "eventfd structures"); 61*7a202823SKonstantin Belousov 62*7a202823SKonstantin Belousov static fo_rdwr_t eventfd_read; 63*7a202823SKonstantin Belousov static fo_rdwr_t eventfd_write; 64*7a202823SKonstantin Belousov static fo_ioctl_t eventfd_ioctl; 65*7a202823SKonstantin Belousov static fo_poll_t eventfd_poll; 66*7a202823SKonstantin Belousov static fo_kqfilter_t eventfd_kqfilter; 67*7a202823SKonstantin Belousov static fo_stat_t eventfd_stat; 68*7a202823SKonstantin Belousov static fo_close_t eventfd_close; 69*7a202823SKonstantin Belousov static fo_fill_kinfo_t eventfd_fill_kinfo; 70*7a202823SKonstantin Belousov 71*7a202823SKonstantin Belousov static struct fileops eventfdops = { 72*7a202823SKonstantin Belousov .fo_read = eventfd_read, 73*7a202823SKonstantin Belousov .fo_write = eventfd_write, 74*7a202823SKonstantin Belousov .fo_truncate = invfo_truncate, 75*7a202823SKonstantin Belousov .fo_ioctl = eventfd_ioctl, 76*7a202823SKonstantin Belousov .fo_poll = eventfd_poll, 77*7a202823SKonstantin Belousov .fo_kqfilter = eventfd_kqfilter, 78*7a202823SKonstantin Belousov .fo_stat = eventfd_stat, 79*7a202823SKonstantin Belousov .fo_close = eventfd_close, 80*7a202823SKonstantin Belousov .fo_chmod = invfo_chmod, 81*7a202823SKonstantin Belousov .fo_chown = invfo_chown, 82*7a202823SKonstantin Belousov .fo_sendfile = invfo_sendfile, 83*7a202823SKonstantin Belousov .fo_fill_kinfo = eventfd_fill_kinfo, 84*7a202823SKonstantin Belousov .fo_flags = DFLAG_PASSABLE 85*7a202823SKonstantin Belousov }; 86*7a202823SKonstantin Belousov 87*7a202823SKonstantin Belousov static void filt_eventfddetach(struct knote *kn); 88*7a202823SKonstantin Belousov static int filt_eventfdread(struct knote *kn, long hint); 89*7a202823SKonstantin Belousov static int filt_eventfdwrite(struct knote *kn, long hint); 90*7a202823SKonstantin Belousov 91*7a202823SKonstantin Belousov static struct filterops eventfd_rfiltops = { 92*7a202823SKonstantin Belousov .f_isfd = 1, 93*7a202823SKonstantin Belousov .f_detach = filt_eventfddetach, 94*7a202823SKonstantin Belousov .f_event = filt_eventfdread 95*7a202823SKonstantin Belousov }; 96*7a202823SKonstantin Belousov 97*7a202823SKonstantin Belousov static struct filterops eventfd_wfiltops = { 98*7a202823SKonstantin Belousov .f_isfd = 1, 99*7a202823SKonstantin Belousov .f_detach = filt_eventfddetach, 100*7a202823SKonstantin Belousov .f_event = filt_eventfdwrite 101*7a202823SKonstantin Belousov }; 102*7a202823SKonstantin Belousov 103*7a202823SKonstantin Belousov struct eventfd { 104*7a202823SKonstantin Belousov eventfd_t efd_count; 105*7a202823SKonstantin Belousov uint32_t efd_flags; 106*7a202823SKonstantin Belousov struct selinfo efd_sel; 107*7a202823SKonstantin Belousov struct mtx efd_lock; 108*7a202823SKonstantin Belousov }; 109*7a202823SKonstantin Belousov 110*7a202823SKonstantin Belousov int 111*7a202823SKonstantin Belousov eventfd_create_file(struct thread *td, struct file *fp, uint32_t initval, 112*7a202823SKonstantin Belousov int flags) 113*7a202823SKonstantin Belousov { 114*7a202823SKonstantin Belousov struct eventfd *efd; 115*7a202823SKonstantin Belousov int fflags; 116*7a202823SKonstantin Belousov 117*7a202823SKonstantin Belousov AUDIT_ARG_FFLAGS(flags); 118*7a202823SKonstantin Belousov AUDIT_ARG_VALUE(initval); 119*7a202823SKonstantin Belousov 120*7a202823SKonstantin Belousov efd = malloc(sizeof(*efd), M_EVENTFD, M_WAITOK | M_ZERO); 121*7a202823SKonstantin Belousov efd->efd_flags = flags; 122*7a202823SKonstantin Belousov efd->efd_count = initval; 123*7a202823SKonstantin Belousov mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF); 124*7a202823SKonstantin Belousov knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock); 125*7a202823SKonstantin Belousov 126*7a202823SKonstantin Belousov fflags = FREAD | FWRITE; 127*7a202823SKonstantin Belousov if ((flags & EFD_NONBLOCK) != 0) 128*7a202823SKonstantin Belousov fflags |= FNONBLOCK; 129*7a202823SKonstantin Belousov finit(fp, fflags, DTYPE_EVENTFD, efd, &eventfdops); 130*7a202823SKonstantin Belousov 131*7a202823SKonstantin Belousov return (0); 132*7a202823SKonstantin Belousov } 133*7a202823SKonstantin Belousov 134*7a202823SKonstantin Belousov static int 135*7a202823SKonstantin Belousov eventfd_close(struct file *fp, struct thread *td) 136*7a202823SKonstantin Belousov { 137*7a202823SKonstantin Belousov struct eventfd *efd; 138*7a202823SKonstantin Belousov 139*7a202823SKonstantin Belousov efd = fp->f_data; 140*7a202823SKonstantin Belousov seldrain(&efd->efd_sel); 141*7a202823SKonstantin Belousov knlist_destroy(&efd->efd_sel.si_note); 142*7a202823SKonstantin Belousov mtx_destroy(&efd->efd_lock); 143*7a202823SKonstantin Belousov free(efd, M_EVENTFD); 144*7a202823SKonstantin Belousov return (0); 145*7a202823SKonstantin Belousov } 146*7a202823SKonstantin Belousov 147*7a202823SKonstantin Belousov static int 148*7a202823SKonstantin Belousov eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 149*7a202823SKonstantin Belousov int flags, struct thread *td) 150*7a202823SKonstantin Belousov { 151*7a202823SKonstantin Belousov struct eventfd *efd; 152*7a202823SKonstantin Belousov eventfd_t count; 153*7a202823SKonstantin Belousov int error; 154*7a202823SKonstantin Belousov 155*7a202823SKonstantin Belousov if (uio->uio_resid < sizeof(eventfd_t)) 156*7a202823SKonstantin Belousov return (EINVAL); 157*7a202823SKonstantin Belousov 158*7a202823SKonstantin Belousov error = 0; 159*7a202823SKonstantin Belousov efd = fp->f_data; 160*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 161*7a202823SKonstantin Belousov while (error == 0 && efd->efd_count == 0) { 162*7a202823SKonstantin Belousov if ((fp->f_flag & FNONBLOCK) != 0) { 163*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 164*7a202823SKonstantin Belousov return (EAGAIN); 165*7a202823SKonstantin Belousov } 166*7a202823SKonstantin Belousov error = mtx_sleep(&efd->efd_count, &efd->efd_lock, PCATCH, 167*7a202823SKonstantin Belousov "efdrd", 0); 168*7a202823SKonstantin Belousov } 169*7a202823SKonstantin Belousov if (error == 0) { 170*7a202823SKonstantin Belousov MPASS(efd->efd_count > 0); 171*7a202823SKonstantin Belousov if ((efd->efd_flags & EFD_SEMAPHORE) != 0) { 172*7a202823SKonstantin Belousov count = 1; 173*7a202823SKonstantin Belousov --efd->efd_count; 174*7a202823SKonstantin Belousov } else { 175*7a202823SKonstantin Belousov count = efd->efd_count; 176*7a202823SKonstantin Belousov efd->efd_count = 0; 177*7a202823SKonstantin Belousov } 178*7a202823SKonstantin Belousov KNOTE_LOCKED(&efd->efd_sel.si_note, 0); 179*7a202823SKonstantin Belousov selwakeup(&efd->efd_sel); 180*7a202823SKonstantin Belousov wakeup(&efd->efd_count); 181*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 182*7a202823SKonstantin Belousov error = uiomove(&count, sizeof(eventfd_t), uio); 183*7a202823SKonstantin Belousov } else 184*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 185*7a202823SKonstantin Belousov 186*7a202823SKonstantin Belousov return (error); 187*7a202823SKonstantin Belousov } 188*7a202823SKonstantin Belousov 189*7a202823SKonstantin Belousov static int 190*7a202823SKonstantin Belousov eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 191*7a202823SKonstantin Belousov int flags, struct thread *td) 192*7a202823SKonstantin Belousov { 193*7a202823SKonstantin Belousov struct eventfd *efd; 194*7a202823SKonstantin Belousov eventfd_t count; 195*7a202823SKonstantin Belousov int error; 196*7a202823SKonstantin Belousov 197*7a202823SKonstantin Belousov if (uio->uio_resid < sizeof(eventfd_t)) 198*7a202823SKonstantin Belousov return (EINVAL); 199*7a202823SKonstantin Belousov 200*7a202823SKonstantin Belousov error = uiomove(&count, sizeof(eventfd_t), uio); 201*7a202823SKonstantin Belousov if (error != 0) 202*7a202823SKonstantin Belousov return (error); 203*7a202823SKonstantin Belousov if (count == UINT64_MAX) 204*7a202823SKonstantin Belousov return (EINVAL); 205*7a202823SKonstantin Belousov 206*7a202823SKonstantin Belousov efd = fp->f_data; 207*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 208*7a202823SKonstantin Belousov retry: 209*7a202823SKonstantin Belousov if (UINT64_MAX - efd->efd_count <= count) { 210*7a202823SKonstantin Belousov if ((fp->f_flag & FNONBLOCK) != 0) { 211*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 212*7a202823SKonstantin Belousov /* Do not not return the number of bytes written */ 213*7a202823SKonstantin Belousov uio->uio_resid += sizeof(eventfd_t); 214*7a202823SKonstantin Belousov return (EAGAIN); 215*7a202823SKonstantin Belousov } 216*7a202823SKonstantin Belousov error = mtx_sleep(&efd->efd_count, &efd->efd_lock, 217*7a202823SKonstantin Belousov PCATCH, "efdwr", 0); 218*7a202823SKonstantin Belousov if (error == 0) 219*7a202823SKonstantin Belousov goto retry; 220*7a202823SKonstantin Belousov } 221*7a202823SKonstantin Belousov if (error == 0) { 222*7a202823SKonstantin Belousov MPASS(UINT64_MAX - efd->efd_count > count); 223*7a202823SKonstantin Belousov efd->efd_count += count; 224*7a202823SKonstantin Belousov KNOTE_LOCKED(&efd->efd_sel.si_note, 0); 225*7a202823SKonstantin Belousov selwakeup(&efd->efd_sel); 226*7a202823SKonstantin Belousov wakeup(&efd->efd_count); 227*7a202823SKonstantin Belousov } 228*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 229*7a202823SKonstantin Belousov 230*7a202823SKonstantin Belousov return (error); 231*7a202823SKonstantin Belousov } 232*7a202823SKonstantin Belousov 233*7a202823SKonstantin Belousov static int 234*7a202823SKonstantin Belousov eventfd_poll(struct file *fp, int events, struct ucred *active_cred, 235*7a202823SKonstantin Belousov struct thread *td) 236*7a202823SKonstantin Belousov { 237*7a202823SKonstantin Belousov struct eventfd *efd; 238*7a202823SKonstantin Belousov int revents; 239*7a202823SKonstantin Belousov 240*7a202823SKonstantin Belousov efd = fp->f_data; 241*7a202823SKonstantin Belousov revents = 0; 242*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 243*7a202823SKonstantin Belousov if ((events & (POLLIN | POLLRDNORM)) != 0 && efd->efd_count > 0) 244*7a202823SKonstantin Belousov revents |= events & (POLLIN | POLLRDNORM); 245*7a202823SKonstantin Belousov if ((events & (POLLOUT | POLLWRNORM)) != 0 && UINT64_MAX - 1 > 246*7a202823SKonstantin Belousov efd->efd_count) 247*7a202823SKonstantin Belousov revents |= events & (POLLOUT | POLLWRNORM); 248*7a202823SKonstantin Belousov if (revents == 0) 249*7a202823SKonstantin Belousov selrecord(td, &efd->efd_sel); 250*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 251*7a202823SKonstantin Belousov 252*7a202823SKonstantin Belousov return (revents); 253*7a202823SKonstantin Belousov } 254*7a202823SKonstantin Belousov 255*7a202823SKonstantin Belousov static int 256*7a202823SKonstantin Belousov eventfd_kqfilter(struct file *fp, struct knote *kn) 257*7a202823SKonstantin Belousov { 258*7a202823SKonstantin Belousov struct eventfd *efd = fp->f_data; 259*7a202823SKonstantin Belousov 260*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 261*7a202823SKonstantin Belousov switch (kn->kn_filter) { 262*7a202823SKonstantin Belousov case EVFILT_READ: 263*7a202823SKonstantin Belousov kn->kn_fop = &eventfd_rfiltops; 264*7a202823SKonstantin Belousov break; 265*7a202823SKonstantin Belousov case EVFILT_WRITE: 266*7a202823SKonstantin Belousov kn->kn_fop = &eventfd_wfiltops; 267*7a202823SKonstantin Belousov break; 268*7a202823SKonstantin Belousov default: 269*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 270*7a202823SKonstantin Belousov return (EINVAL); 271*7a202823SKonstantin Belousov } 272*7a202823SKonstantin Belousov 273*7a202823SKonstantin Belousov kn->kn_hook = efd; 274*7a202823SKonstantin Belousov knlist_add(&efd->efd_sel.si_note, kn, 1); 275*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 276*7a202823SKonstantin Belousov 277*7a202823SKonstantin Belousov return (0); 278*7a202823SKonstantin Belousov } 279*7a202823SKonstantin Belousov 280*7a202823SKonstantin Belousov static void 281*7a202823SKonstantin Belousov filt_eventfddetach(struct knote *kn) 282*7a202823SKonstantin Belousov { 283*7a202823SKonstantin Belousov struct eventfd *efd = kn->kn_hook; 284*7a202823SKonstantin Belousov 285*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 286*7a202823SKonstantin Belousov knlist_remove(&efd->efd_sel.si_note, kn, 1); 287*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 288*7a202823SKonstantin Belousov } 289*7a202823SKonstantin Belousov 290*7a202823SKonstantin Belousov static int 291*7a202823SKonstantin Belousov filt_eventfdread(struct knote *kn, long hint) 292*7a202823SKonstantin Belousov { 293*7a202823SKonstantin Belousov struct eventfd *efd = kn->kn_hook; 294*7a202823SKonstantin Belousov int ret; 295*7a202823SKonstantin Belousov 296*7a202823SKonstantin Belousov mtx_assert(&efd->efd_lock, MA_OWNED); 297*7a202823SKonstantin Belousov kn->kn_data = (int64_t)efd->efd_count; 298*7a202823SKonstantin Belousov ret = efd->efd_count > 0; 299*7a202823SKonstantin Belousov 300*7a202823SKonstantin Belousov return (ret); 301*7a202823SKonstantin Belousov } 302*7a202823SKonstantin Belousov 303*7a202823SKonstantin Belousov static int 304*7a202823SKonstantin Belousov filt_eventfdwrite(struct knote *kn, long hint) 305*7a202823SKonstantin Belousov { 306*7a202823SKonstantin Belousov struct eventfd *efd = kn->kn_hook; 307*7a202823SKonstantin Belousov int ret; 308*7a202823SKonstantin Belousov 309*7a202823SKonstantin Belousov mtx_assert(&efd->efd_lock, MA_OWNED); 310*7a202823SKonstantin Belousov kn->kn_data = (int64_t)(UINT64_MAX - 1 - efd->efd_count); 311*7a202823SKonstantin Belousov ret = UINT64_MAX - 1 > efd->efd_count; 312*7a202823SKonstantin Belousov 313*7a202823SKonstantin Belousov return (ret); 314*7a202823SKonstantin Belousov } 315*7a202823SKonstantin Belousov 316*7a202823SKonstantin Belousov static int 317*7a202823SKonstantin Belousov eventfd_ioctl(struct file *fp, u_long cmd, void *data, 318*7a202823SKonstantin Belousov struct ucred *active_cred, struct thread *td) 319*7a202823SKonstantin Belousov { 320*7a202823SKonstantin Belousov switch (cmd) { 321*7a202823SKonstantin Belousov case FIONBIO: 322*7a202823SKonstantin Belousov case FIOASYNC: 323*7a202823SKonstantin Belousov return (0); 324*7a202823SKonstantin Belousov } 325*7a202823SKonstantin Belousov 326*7a202823SKonstantin Belousov return (ENOTTY); 327*7a202823SKonstantin Belousov } 328*7a202823SKonstantin Belousov 329*7a202823SKonstantin Belousov static int 330*7a202823SKonstantin Belousov eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, 331*7a202823SKonstantin Belousov struct thread *td) 332*7a202823SKonstantin Belousov { 333*7a202823SKonstantin Belousov bzero((void *)st, sizeof *st); 334*7a202823SKonstantin Belousov st->st_mode = S_IFIFO; 335*7a202823SKonstantin Belousov return (0); 336*7a202823SKonstantin Belousov } 337*7a202823SKonstantin Belousov 338*7a202823SKonstantin Belousov static int 339*7a202823SKonstantin Belousov eventfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) 340*7a202823SKonstantin Belousov { 341*7a202823SKonstantin Belousov struct eventfd *efd = fp->f_data; 342*7a202823SKonstantin Belousov 343*7a202823SKonstantin Belousov kif->kf_type = KF_TYPE_EVENTFD; 344*7a202823SKonstantin Belousov mtx_lock(&efd->efd_lock); 345*7a202823SKonstantin Belousov kif->kf_un.kf_eventfd.kf_eventfd_value = efd->efd_count; 346*7a202823SKonstantin Belousov kif->kf_un.kf_eventfd.kf_eventfd_flags = efd->efd_flags; 347*7a202823SKonstantin Belousov mtx_unlock(&efd->efd_lock); 348*7a202823SKonstantin Belousov return (0); 349*7a202823SKonstantin Belousov } 350