1*03ca6dbdSKonstantin Belousov /* 2*03ca6dbdSKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause 3*03ca6dbdSKonstantin Belousov * 4*03ca6dbdSKonstantin Belousov * Copyright 2026 The FreeBSD Foundation 5*03ca6dbdSKonstantin Belousov * 6*03ca6dbdSKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 7*03ca6dbdSKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 8*03ca6dbdSKonstantin Belousov */ 9*03ca6dbdSKonstantin Belousov 10*03ca6dbdSKonstantin Belousov #include <sys/systm.h> 11*03ca6dbdSKonstantin Belousov #include <sys/conf.h> 12*03ca6dbdSKonstantin Belousov #include <sys/fcntl.h> 13*03ca6dbdSKonstantin Belousov #include <sys/file.h> 14*03ca6dbdSKonstantin Belousov #include <sys/filedesc.h> 15*03ca6dbdSKonstantin Belousov #include <sys/kernel.h> 16*03ca6dbdSKonstantin Belousov #include <sys/limits.h> 17*03ca6dbdSKonstantin Belousov #include <sys/malloc.h> 18*03ca6dbdSKonstantin Belousov #include <sys/module.h> 19*03ca6dbdSKonstantin Belousov #include <sys/proc.h> 20*03ca6dbdSKonstantin Belousov #include <sys/stat.h> 21*03ca6dbdSKonstantin Belousov #include <sys/sysent.h> 22*03ca6dbdSKonstantin Belousov #include <dev/ntsync/ntsyncvar.h> 23*03ca6dbdSKonstantin Belousov 24*03ca6dbdSKonstantin Belousov static struct cdev *ntsync_cdev; 25*03ca6dbdSKonstantin Belousov MALLOC_DEFINE(M_NTSYNC, "ntsync", "ntsync"); 26*03ca6dbdSKonstantin Belousov 27*03ca6dbdSKonstantin Belousov static void ntsync_free_priv(struct ntsync_priv *priv); 28*03ca6dbdSKonstantin Belousov 29*03ca6dbdSKonstantin Belousov /* 30*03ca6dbdSKonstantin Belousov * Returning error from an ioctl handler prevents the generic ioctl 31*03ca6dbdSKonstantin Belousov * code from copying out the result. Use direct access to ioctl(2) 32*03ca6dbdSKonstantin Belousov * args to get the parameters block pointer to implement Linux 33*03ca6dbdSKonstantin Belousov * semantic of both returning an error and updating the parameters 34*03ca6dbdSKonstantin Belousov * block. 35*03ca6dbdSKonstantin Belousov */ 36*03ca6dbdSKonstantin Belousov static int 37*03ca6dbdSKonstantin Belousov ntsync_ioctl_copyout(struct thread *td, const void *ptr, size_t sz) 38*03ca6dbdSKonstantin Belousov { 39*03ca6dbdSKonstantin Belousov void *uptr; 40*03ca6dbdSKonstantin Belousov 41*03ca6dbdSKonstantin Belousov if (SV_PROC_ABI(td->td_proc) != SV_ABI_FREEBSD) 42*03ca6dbdSKonstantin Belousov return (0); 43*03ca6dbdSKonstantin Belousov uptr = (void *)(uintptr_t)td->td_sa.args[2]; 44*03ca6dbdSKonstantin Belousov return (copyout(ptr, uptr, sz)); 45*03ca6dbdSKonstantin Belousov } 46*03ca6dbdSKonstantin Belousov 47*03ca6dbdSKonstantin Belousov static bool 48*03ca6dbdSKonstantin Belousov ntsync_wait_any(struct ntsync_wait_state *state) 49*03ca6dbdSKonstantin Belousov { 50*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 51*03ca6dbdSKonstantin Belousov int i; 52*03ca6dbdSKonstantin Belousov 53*03ca6dbdSKonstantin Belousov MPASS(state->any); 54*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 55*03ca6dbdSKonstantin Belousov 56*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) { 57*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 58*03ca6dbdSKonstantin Belousov if (obj->is_signaled(obj, state, i)) { 59*03ca6dbdSKonstantin Belousov state->index = i; 60*03ca6dbdSKonstantin Belousov obj->consume(obj, state, state->index); 61*03ca6dbdSKonstantin Belousov return (true); 62*03ca6dbdSKonstantin Belousov } 63*03ca6dbdSKonstantin Belousov } 64*03ca6dbdSKonstantin Belousov return (false); 65*03ca6dbdSKonstantin Belousov } 66*03ca6dbdSKonstantin Belousov 67*03ca6dbdSKonstantin Belousov static bool 68*03ca6dbdSKonstantin Belousov ntsync_wait_all_prepare(struct ntsync_wait_state *state, bool *stop) 69*03ca6dbdSKonstantin Belousov { 70*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 71*03ca6dbdSKonstantin Belousov int alerti, i; 72*03ca6dbdSKonstantin Belousov bool first; 73*03ca6dbdSKonstantin Belousov 74*03ca6dbdSKonstantin Belousov MPASS(state->all); 75*03ca6dbdSKonstantin Belousov MPASS(state->error == 0); 76*03ca6dbdSKonstantin Belousov MPASS(!*stop); 77*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 78*03ca6dbdSKonstantin Belousov 79*03ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1; 80*03ca6dbdSKonstantin Belousov first = true; 81*03ca6dbdSKonstantin Belousov 82*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) { 83*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 84*03ca6dbdSKonstantin Belousov if (!obj->prepare(obj, state, i, stop)) 85*03ca6dbdSKonstantin Belousov return (false); 86*03ca6dbdSKonstantin Belousov if (*stop) { 87*03ca6dbdSKonstantin Belousov MPASS(state->error != 0); 88*03ca6dbdSKonstantin Belousov return (false); 89*03ca6dbdSKonstantin Belousov } 90*03ca6dbdSKonstantin Belousov MPASS (state->error == 0); 91*03ca6dbdSKonstantin Belousov if (first) { 92*03ca6dbdSKonstantin Belousov first = false; 93*03ca6dbdSKonstantin Belousov state->index = i; 94*03ca6dbdSKonstantin Belousov } 95*03ca6dbdSKonstantin Belousov } 96*03ca6dbdSKonstantin Belousov return (true); 97*03ca6dbdSKonstantin Belousov } 98*03ca6dbdSKonstantin Belousov 99*03ca6dbdSKonstantin Belousov static void 100*03ca6dbdSKonstantin Belousov ntsync_wait_all_commit(struct ntsync_wait_state *state) 101*03ca6dbdSKonstantin Belousov { 102*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 103*03ca6dbdSKonstantin Belousov int i, alerti; 104*03ca6dbdSKonstantin Belousov 105*03ca6dbdSKonstantin Belousov MPASS(state->all); 106*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 107*03ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1; 108*03ca6dbdSKonstantin Belousov 109*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) { 110*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 111*03ca6dbdSKonstantin Belousov obj->commit(obj, state, i); 112*03ca6dbdSKonstantin Belousov } 113*03ca6dbdSKonstantin Belousov } 114*03ca6dbdSKonstantin Belousov 115*03ca6dbdSKonstantin Belousov static void 116*03ca6dbdSKonstantin Belousov ntsync_wait_link_waiters(struct ntsync_wait_state *state) 117*03ca6dbdSKonstantin Belousov { 118*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 119*03ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *waiter; 120*03ca6dbdSKonstantin Belousov int i; 121*03ca6dbdSKonstantin Belousov 122*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 123*03ca6dbdSKonstantin Belousov 124*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) { 125*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 126*03ca6dbdSKonstantin Belousov waiter = &state->waiters[i]; 127*03ca6dbdSKonstantin Belousov waiter->state = state; 128*03ca6dbdSKonstantin Belousov TAILQ_INSERT_TAIL(&obj->waiters, waiter, link); 129*03ca6dbdSKonstantin Belousov } 130*03ca6dbdSKonstantin Belousov } 131*03ca6dbdSKonstantin Belousov 132*03ca6dbdSKonstantin Belousov static void 133*03ca6dbdSKonstantin Belousov ntsync_wait_unlink_waiters(struct ntsync_wait_state *state) 134*03ca6dbdSKonstantin Belousov { 135*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 136*03ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *waiter; 137*03ca6dbdSKonstantin Belousov int i; 138*03ca6dbdSKonstantin Belousov 139*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 140*03ca6dbdSKonstantin Belousov 141*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) { 142*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 143*03ca6dbdSKonstantin Belousov waiter = &state->waiters[i]; 144*03ca6dbdSKonstantin Belousov TAILQ_REMOVE(&obj->waiters, waiter, link); 145*03ca6dbdSKonstantin Belousov } 146*03ca6dbdSKonstantin Belousov } 147*03ca6dbdSKonstantin Belousov 148*03ca6dbdSKonstantin Belousov static void 149*03ca6dbdSKonstantin Belousov ntsync_wait_post_commit(struct ntsync_wait_state *state) 150*03ca6dbdSKonstantin Belousov { 151*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 152*03ca6dbdSKonstantin Belousov int alerti, i; 153*03ca6dbdSKonstantin Belousov 154*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 155*03ca6dbdSKonstantin Belousov 156*03ca6dbdSKonstantin Belousov alerti = state->alert_event == NULL ? 0 : 1; 157*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count - alerti; i++) { 158*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 159*03ca6dbdSKonstantin Belousov obj->post_commit(obj, state, i); 160*03ca6dbdSKonstantin Belousov } 161*03ca6dbdSKonstantin Belousov } 162*03ca6dbdSKonstantin Belousov 163*03ca6dbdSKonstantin Belousov static void 164*03ca6dbdSKonstantin Belousov ntsync_wait_check_ready(struct ntsync_wait_state *state) 165*03ca6dbdSKonstantin Belousov { 166*03ca6dbdSKonstantin Belousov struct ntsync_obj *ae; 167*03ca6dbdSKonstantin Belousov int index; 168*03ca6dbdSKonstantin Belousov bool stop; 169*03ca6dbdSKonstantin Belousov 170*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 171*03ca6dbdSKonstantin Belousov 172*03ca6dbdSKonstantin Belousov if (state->ready) 173*03ca6dbdSKonstantin Belousov return; 174*03ca6dbdSKonstantin Belousov 175*03ca6dbdSKonstantin Belousov if (state->all) { 176*03ca6dbdSKonstantin Belousov stop = false; 177*03ca6dbdSKonstantin Belousov if (ntsync_wait_all_prepare(state, &stop)) { 178*03ca6dbdSKonstantin Belousov MPASS(!stop); 179*03ca6dbdSKonstantin Belousov ntsync_wait_all_commit(state); 180*03ca6dbdSKonstantin Belousov state->ready = true; 181*03ca6dbdSKonstantin Belousov ntsync_wait_post_commit(state); 182*03ca6dbdSKonstantin Belousov } else if (stop) { 183*03ca6dbdSKonstantin Belousov /* skip */ 184*03ca6dbdSKonstantin Belousov } else if (state->alert_event != NULL) { 185*03ca6dbdSKonstantin Belousov ae = &state->alert_event->obj; 186*03ca6dbdSKonstantin Belousov index = state->obj_count - 1; 187*03ca6dbdSKonstantin Belousov if (ae->is_signaled(ae, state, index)) { 188*03ca6dbdSKonstantin Belousov state->index = index; 189*03ca6dbdSKonstantin Belousov ae->consume(ae, state, index); 190*03ca6dbdSKonstantin Belousov ae->post_commit(ae, state, index); 191*03ca6dbdSKonstantin Belousov state->ready = true; 192*03ca6dbdSKonstantin Belousov } 193*03ca6dbdSKonstantin Belousov } 194*03ca6dbdSKonstantin Belousov } else { /* state->any */ 195*03ca6dbdSKonstantin Belousov if (ntsync_wait_any(state)) 196*03ca6dbdSKonstantin Belousov state->ready = true; 197*03ca6dbdSKonstantin Belousov } 198*03ca6dbdSKonstantin Belousov } 199*03ca6dbdSKonstantin Belousov 200*03ca6dbdSKonstantin Belousov /* 201*03ca6dbdSKonstantin Belousov * Perform the wait. Errors returned through state->error still 202*03ca6dbdSKonstantin Belousov * result in the copyout of the ntsync_wait_args after the wait, while 203*03ca6dbdSKonstantin Belousov * errors returned as the function result do not. 204*03ca6dbdSKonstantin Belousov */ 205*03ca6dbdSKonstantin Belousov static int 206*03ca6dbdSKonstantin Belousov ntsync_wait_locked(struct ntsync_wait_state *state, struct thread *td) 207*03ca6dbdSKonstantin Belousov { 208*03ca6dbdSKonstantin Belousov int error; 209*03ca6dbdSKonstantin Belousov 210*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(state->owner); 211*03ca6dbdSKonstantin Belousov 212*03ca6dbdSKonstantin Belousov for (;;) { 213*03ca6dbdSKonstantin Belousov ntsync_wait_check_ready(state); 214*03ca6dbdSKonstantin Belousov if (state->ready) 215*03ca6dbdSKonstantin Belousov break; 216*03ca6dbdSKonstantin Belousov error = msleep_sbt(state, &state->owner->lock, 217*03ca6dbdSKonstantin Belousov PCATCH, "ntsync", state->sb, 0, 218*03ca6dbdSKonstantin Belousov C_ABSOLUTE /* | C_HARDCLOCK XXXKIB */); 219*03ca6dbdSKonstantin Belousov 220*03ca6dbdSKonstantin Belousov /* 221*03ca6dbdSKonstantin Belousov * Check state->ready before checking error from 222*03ca6dbdSKonstantin Belousov * msleep(). If there was a wake up that set the 223*03ca6dbdSKonstantin Belousov * readiness before us receiving a signal or timeout, 224*03ca6dbdSKonstantin Belousov * the objects states are modified to reflect wakeup. 225*03ca6dbdSKonstantin Belousov * Due to this, ready should result in normal return. 226*03ca6dbdSKonstantin Belousov */ 227*03ca6dbdSKonstantin Belousov if (state->ready) { 228*03ca6dbdSKonstantin Belousov error = 0; 229*03ca6dbdSKonstantin Belousov break; 230*03ca6dbdSKonstantin Belousov } 231*03ca6dbdSKonstantin Belousov 232*03ca6dbdSKonstantin Belousov if (error != 0) { 233*03ca6dbdSKonstantin Belousov if (error == EAGAIN) 234*03ca6dbdSKonstantin Belousov error = ETIMEDOUT; 235*03ca6dbdSKonstantin Belousov break; 236*03ca6dbdSKonstantin Belousov } 237*03ca6dbdSKonstantin Belousov } 238*03ca6dbdSKonstantin Belousov return (error); 239*03ca6dbdSKonstantin Belousov } 240*03ca6dbdSKonstantin Belousov 241*03ca6dbdSKonstantin Belousov static int 242*03ca6dbdSKonstantin Belousov ntsync_wait(struct ntsync_wait_state *state, struct thread *td) 243*03ca6dbdSKonstantin Belousov { 244*03ca6dbdSKonstantin Belousov int error; 245*03ca6dbdSKonstantin Belousov 246*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(state->owner); 247*03ca6dbdSKonstantin Belousov ntsync_wait_link_waiters(state); 248*03ca6dbdSKonstantin Belousov error = ntsync_wait_locked(state, td); 249*03ca6dbdSKonstantin Belousov ntsync_wait_unlink_waiters(state); 250*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(state->owner); 251*03ca6dbdSKonstantin Belousov return (error); 252*03ca6dbdSKonstantin Belousov } 253*03ca6dbdSKonstantin Belousov 254*03ca6dbdSKonstantin Belousov static void 255*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(struct ntsync_obj *obj) 256*03ca6dbdSKonstantin Belousov { 257*03ca6dbdSKonstantin Belousov struct ntsync_obj_waiter *w; 258*03ca6dbdSKonstantin Belousov 259*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 260*03ca6dbdSKonstantin Belousov 261*03ca6dbdSKonstantin Belousov TAILQ_FOREACH(w, &obj->waiters, link) { 262*03ca6dbdSKonstantin Belousov ntsync_wait_check_ready(w->state); 263*03ca6dbdSKonstantin Belousov if (w->state->ready) 264*03ca6dbdSKonstantin Belousov wakeup(w->state); 265*03ca6dbdSKonstantin Belousov } 266*03ca6dbdSKonstantin Belousov } 267*03ca6dbdSKonstantin Belousov 268*03ca6dbdSKonstantin Belousov static int 269*03ca6dbdSKonstantin Belousov ntsync_create_obj(struct ntsync_obj *obj, struct fileops *fops, 270*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv, struct thread *td) 271*03ca6dbdSKonstantin Belousov { 272*03ca6dbdSKonstantin Belousov struct file *fp; 273*03ca6dbdSKonstantin Belousov int error, fd; 274*03ca6dbdSKonstantin Belousov 275*03ca6dbdSKonstantin Belousov error = falloc_noinstall(td, &fp); 276*03ca6dbdSKonstantin Belousov if (error != 0) 277*03ca6dbdSKonstantin Belousov return (error); 278*03ca6dbdSKonstantin Belousov 279*03ca6dbdSKonstantin Belousov /* 280*03ca6dbdSKonstantin Belousov * The priv fd cannot be closed during object creation since 281*03ca6dbdSKonstantin Belousov * it is fget-ed around ioctl. 282*03ca6dbdSKonstantin Belousov */ 283*03ca6dbdSKonstantin Belousov obj->owner = priv; 284*03ca6dbdSKonstantin Belousov 285*03ca6dbdSKonstantin Belousov TAILQ_INIT(&obj->waiters); 286*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 287*03ca6dbdSKonstantin Belousov MPASS(!priv->closed); 288*03ca6dbdSKonstantin Belousov if (priv->objs_cnt == UINT_MAX) { 289*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 290*03ca6dbdSKonstantin Belousov fdrop(fp, td); 291*03ca6dbdSKonstantin Belousov return (EMFILE); 292*03ca6dbdSKonstantin Belousov } 293*03ca6dbdSKonstantin Belousov priv->objs_cnt++; 294*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 295*03ca6dbdSKonstantin Belousov 296*03ca6dbdSKonstantin Belousov finit(fp, FREAD | FWRITE, DTYPE_NTSYNC, obj, fops); 297*03ca6dbdSKonstantin Belousov error = finstall(td, fp, &fd, 0, NULL); 298*03ca6dbdSKonstantin Belousov if (error != 0) { 299*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 300*03ca6dbdSKonstantin Belousov MPASS(priv->objs_cnt > 0); 301*03ca6dbdSKonstantin Belousov priv->objs_cnt--; 302*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 303*03ca6dbdSKonstantin Belousov } else { 304*03ca6dbdSKonstantin Belousov td->td_retval[0] = fd; 305*03ca6dbdSKonstantin Belousov } 306*03ca6dbdSKonstantin Belousov fdrop(fp, td); 307*03ca6dbdSKonstantin Belousov return (error); 308*03ca6dbdSKonstantin Belousov } 309*03ca6dbdSKonstantin Belousov 310*03ca6dbdSKonstantin Belousov static void 311*03ca6dbdSKonstantin Belousov ntsync_close_obj(struct ntsync_obj *obj, struct thread *td) 312*03ca6dbdSKonstantin Belousov { 313*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 314*03ca6dbdSKonstantin Belousov 315*03ca6dbdSKonstantin Belousov priv = obj->owner; 316*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 317*03ca6dbdSKonstantin Belousov MPASS(priv->objs_cnt > 0); 318*03ca6dbdSKonstantin Belousov MPASS(TAILQ_EMPTY(&obj->waiters)); 319*03ca6dbdSKonstantin Belousov priv->objs_cnt--; 320*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 321*03ca6dbdSKonstantin Belousov ntsync_free_priv(priv); 322*03ca6dbdSKonstantin Belousov } 323*03ca6dbdSKonstantin Belousov 324*03ca6dbdSKonstantin Belousov static bool 325*03ca6dbdSKonstantin Belousov ntsync_sem_is_signaled(struct ntsync_obj *obj, struct ntsync_wait_state *state, 326*03ca6dbdSKonstantin Belousov int index) 327*03ca6dbdSKonstantin Belousov { 328*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 329*03ca6dbdSKonstantin Belousov 330*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM); 331*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 332*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 333*03ca6dbdSKonstantin Belousov return (sem->a.count != 0); 334*03ca6dbdSKonstantin Belousov } 335*03ca6dbdSKonstantin Belousov 336*03ca6dbdSKonstantin Belousov static void 337*03ca6dbdSKonstantin Belousov ntsync_sem_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state, 338*03ca6dbdSKonstantin Belousov int index) 339*03ca6dbdSKonstantin Belousov { 340*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 341*03ca6dbdSKonstantin Belousov 342*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM); 343*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 344*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 345*03ca6dbdSKonstantin Belousov MPASS(sem->a.count != 0); 346*03ca6dbdSKonstantin Belousov sem->a.count--; 347*03ca6dbdSKonstantin Belousov } 348*03ca6dbdSKonstantin Belousov 349*03ca6dbdSKonstantin Belousov static bool 350*03ca6dbdSKonstantin Belousov ntsync_sem_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state, 351*03ca6dbdSKonstantin Belousov int index, bool *stop) 352*03ca6dbdSKonstantin Belousov { 353*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 354*03ca6dbdSKonstantin Belousov 355*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM); 356*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 357*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 358*03ca6dbdSKonstantin Belousov if (sem->a.count == 0) 359*03ca6dbdSKonstantin Belousov return (false); 360*03ca6dbdSKonstantin Belousov sem->a1 = sem->a; 361*03ca6dbdSKonstantin Belousov sem->a1.count--; 362*03ca6dbdSKonstantin Belousov return (true); 363*03ca6dbdSKonstantin Belousov } 364*03ca6dbdSKonstantin Belousov 365*03ca6dbdSKonstantin Belousov static void 366*03ca6dbdSKonstantin Belousov ntsync_sem_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state, 367*03ca6dbdSKonstantin Belousov int index) 368*03ca6dbdSKonstantin Belousov { 369*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 370*03ca6dbdSKonstantin Belousov 371*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM); 372*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 373*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 374*03ca6dbdSKonstantin Belousov sem->a = sem->a1; 375*03ca6dbdSKonstantin Belousov } 376*03ca6dbdSKonstantin Belousov 377*03ca6dbdSKonstantin Belousov static void 378*03ca6dbdSKonstantin Belousov ntsync_sem_post_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state, 379*03ca6dbdSKonstantin Belousov int index) 380*03ca6dbdSKonstantin Belousov { 381*03ca6dbdSKonstantin Belousov } 382*03ca6dbdSKonstantin Belousov 383*03ca6dbdSKonstantin Belousov static int 384*03ca6dbdSKonstantin Belousov ntsync_sem_close(struct file *fp, struct thread *td) 385*03ca6dbdSKonstantin Belousov { 386*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 387*03ca6dbdSKonstantin Belousov 388*03ca6dbdSKonstantin Belousov sem = fp->f_data; 389*03ca6dbdSKonstantin Belousov ntsync_close_obj(&sem->obj, td); 390*03ca6dbdSKonstantin Belousov free(sem, M_NTSYNC); 391*03ca6dbdSKonstantin Belousov return (0); 392*03ca6dbdSKonstantin Belousov } 393*03ca6dbdSKonstantin Belousov 394*03ca6dbdSKonstantin Belousov int 395*03ca6dbdSKonstantin Belousov ntsync_sem_release(struct thread *td, struct file *fp, uint32_t *val) 396*03ca6dbdSKonstantin Belousov { 397*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 398*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 399*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 400*03ca6dbdSKonstantin Belousov uint32_t prev; 401*03ca6dbdSKonstantin Belousov int error; 402*03ca6dbdSKonstantin Belousov 403*03ca6dbdSKonstantin Belousov obj = fp->f_data; 404*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_SEM) 405*03ca6dbdSKonstantin Belousov return (EINVAL); 406*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 407*03ca6dbdSKonstantin Belousov priv = obj->owner; 408*03ca6dbdSKonstantin Belousov error = 0; 409*03ca6dbdSKonstantin Belousov 410*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 411*03ca6dbdSKonstantin Belousov if (sem->a.count + *val < sem->a.count || 412*03ca6dbdSKonstantin Belousov sem->a.count + *val > sem->a.max) { 413*03ca6dbdSKonstantin Belousov error = EOVERFLOW; 414*03ca6dbdSKonstantin Belousov } else { 415*03ca6dbdSKonstantin Belousov prev = sem->a.count; 416*03ca6dbdSKonstantin Belousov sem->a.count += *val; 417*03ca6dbdSKonstantin Belousov if (sem->a.count != 0) 418*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj); 419*03ca6dbdSKonstantin Belousov *val = prev; 420*03ca6dbdSKonstantin Belousov } 421*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 422*03ca6dbdSKonstantin Belousov return (error); 423*03ca6dbdSKonstantin Belousov } 424*03ca6dbdSKonstantin Belousov 425*03ca6dbdSKonstantin Belousov int 426*03ca6dbdSKonstantin Belousov ntsync_sem_read(struct thread *td, struct file *fp, struct ntsync_sem_args *a) 427*03ca6dbdSKonstantin Belousov { 428*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 429*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 430*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 431*03ca6dbdSKonstantin Belousov 432*03ca6dbdSKonstantin Belousov obj = fp->f_data; 433*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_SEM) 434*03ca6dbdSKonstantin Belousov return (EINVAL); 435*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 436*03ca6dbdSKonstantin Belousov priv = obj->owner; 437*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 438*03ca6dbdSKonstantin Belousov *a = sem->a; 439*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 440*03ca6dbdSKonstantin Belousov return (0); 441*03ca6dbdSKonstantin Belousov } 442*03ca6dbdSKonstantin Belousov 443*03ca6dbdSKonstantin Belousov static int 444*03ca6dbdSKonstantin Belousov ntsync_sem_ioctl(struct file *fp, u_long com, void *data, 445*03ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td) 446*03ca6dbdSKonstantin Belousov { 447*03ca6dbdSKonstantin Belousov int error; 448*03ca6dbdSKonstantin Belousov 449*03ca6dbdSKonstantin Belousov switch (com) { 450*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_SEM_RELEASE: 451*03ca6dbdSKonstantin Belousov error = ntsync_sem_release(td, fp, data); 452*03ca6dbdSKonstantin Belousov break; 453*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_SEM_READ: 454*03ca6dbdSKonstantin Belousov error = ntsync_sem_read(td, fp, data); 455*03ca6dbdSKonstantin Belousov break; 456*03ca6dbdSKonstantin Belousov default: 457*03ca6dbdSKonstantin Belousov error = ENOTTY; 458*03ca6dbdSKonstantin Belousov break; 459*03ca6dbdSKonstantin Belousov } 460*03ca6dbdSKonstantin Belousov return (error); 461*03ca6dbdSKonstantin Belousov } 462*03ca6dbdSKonstantin Belousov 463*03ca6dbdSKonstantin Belousov static int 464*03ca6dbdSKonstantin Belousov ntsync_sem_stat(struct file *fp, struct stat *sbp, struct ucred *cred) 465*03ca6dbdSKonstantin Belousov { 466*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 467*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 468*03ca6dbdSKonstantin Belousov 469*03ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC); 470*03ca6dbdSKonstantin Belousov obj = fp->f_data; 471*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_SEM); 472*03ca6dbdSKonstantin Belousov sem = OBJ_TO_SEM(obj); 473*03ca6dbdSKonstantin Belousov 474*03ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp)); 475*03ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR; 476*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner); 477*03ca6dbdSKonstantin Belousov sbp->st_size = sem->a.max; 478*03ca6dbdSKonstantin Belousov sbp->st_nlink = sem->a.count; 479*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner); 480*03ca6dbdSKonstantin Belousov return (0); 481*03ca6dbdSKonstantin Belousov } 482*03ca6dbdSKonstantin Belousov 483*03ca6dbdSKonstantin Belousov static int 484*03ca6dbdSKonstantin Belousov ntsync_sem_fill_kinfo(struct file *fp, struct kinfo_file *kif, 485*03ca6dbdSKonstantin Belousov struct filedesc *fdp) 486*03ca6dbdSKonstantin Belousov { 487*03ca6dbdSKonstantin Belousov // XXXKIB 488*03ca6dbdSKonstantin Belousov return (0); 489*03ca6dbdSKonstantin Belousov } 490*03ca6dbdSKonstantin Belousov 491*03ca6dbdSKonstantin Belousov struct fileops ntsync_sem_fops = { 492*03ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr, 493*03ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr, 494*03ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate, 495*03ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_sem_ioctl, 496*03ca6dbdSKonstantin Belousov .fo_poll = invfo_poll, 497*03ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter, 498*03ca6dbdSKonstantin Belousov .fo_stat = ntsync_sem_stat, 499*03ca6dbdSKonstantin Belousov .fo_close = ntsync_sem_close, 500*03ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod, 501*03ca6dbdSKonstantin Belousov .fo_chown = invfo_chown, 502*03ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile, 503*03ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_sem_fill_kinfo, 504*03ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE, 505*03ca6dbdSKonstantin Belousov }; 506*03ca6dbdSKonstantin Belousov 507*03ca6dbdSKonstantin Belousov static int 508*03ca6dbdSKonstantin Belousov ntsync_create_sem(struct ntsync_sem_args *args, struct ntsync_priv *priv, 509*03ca6dbdSKonstantin Belousov struct thread *td) 510*03ca6dbdSKonstantin Belousov { 511*03ca6dbdSKonstantin Belousov struct ntsync_obj_sem *sem; 512*03ca6dbdSKonstantin Belousov int error; 513*03ca6dbdSKonstantin Belousov 514*03ca6dbdSKonstantin Belousov if (args->count > args->max) 515*03ca6dbdSKonstantin Belousov return (EINVAL); 516*03ca6dbdSKonstantin Belousov 517*03ca6dbdSKonstantin Belousov sem = malloc(sizeof(*sem), M_NTSYNC, M_WAITOK | M_ZERO); 518*03ca6dbdSKonstantin Belousov sem->obj.type = NTSYNC_OBJ_SEM; 519*03ca6dbdSKonstantin Belousov sem->obj.is_signaled = ntsync_sem_is_signaled; 520*03ca6dbdSKonstantin Belousov sem->obj.consume = ntsync_sem_consume; 521*03ca6dbdSKonstantin Belousov sem->obj.prepare = ntsync_sem_prepare; 522*03ca6dbdSKonstantin Belousov sem->obj.commit = ntsync_sem_commit; 523*03ca6dbdSKonstantin Belousov sem->obj.post_commit = ntsync_sem_post_commit; 524*03ca6dbdSKonstantin Belousov sem->a = *args; 525*03ca6dbdSKonstantin Belousov 526*03ca6dbdSKonstantin Belousov error = ntsync_create_obj(&sem->obj, &ntsync_sem_fops, priv, td); 527*03ca6dbdSKonstantin Belousov if (error != 0) 528*03ca6dbdSKonstantin Belousov free(sem, M_NTSYNC); 529*03ca6dbdSKonstantin Belousov 530*03ca6dbdSKonstantin Belousov return (error); 531*03ca6dbdSKonstantin Belousov } 532*03ca6dbdSKonstantin Belousov 533*03ca6dbdSKonstantin Belousov static bool 534*03ca6dbdSKonstantin Belousov ntsync_mutex_can_lock(struct ntsync_obj_mutex *mutex, uint32_t nwa_owner) 535*03ca6dbdSKonstantin Belousov { 536*03ca6dbdSKonstantin Belousov return (mutex->a.owner == 0 || 537*03ca6dbdSKonstantin Belousov (mutex->a.owner == nwa_owner && mutex->a.count < UINT32_MAX) || 538*03ca6dbdSKonstantin Belousov mutex->abandoned); 539*03ca6dbdSKonstantin Belousov } 540*03ca6dbdSKonstantin Belousov 541*03ca6dbdSKonstantin Belousov static bool 542*03ca6dbdSKonstantin Belousov ntsync_mutex_is_signaled(struct ntsync_obj *obj, 543*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index) 544*03ca6dbdSKonstantin Belousov { 545*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 546*03ca6dbdSKonstantin Belousov 547*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX); 548*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 549*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 550*03ca6dbdSKonstantin Belousov return (ntsync_mutex_can_lock(mutex, state->nwa->owner)); 551*03ca6dbdSKonstantin Belousov } 552*03ca6dbdSKonstantin Belousov 553*03ca6dbdSKonstantin Belousov static void 554*03ca6dbdSKonstantin Belousov ntsync_mutex_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state, 555*03ca6dbdSKonstantin Belousov int index) 556*03ca6dbdSKonstantin Belousov { 557*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 558*03ca6dbdSKonstantin Belousov 559*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX); 560*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 561*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 562*03ca6dbdSKonstantin Belousov MPASS(ntsync_mutex_can_lock(mutex, state->nwa->owner)); 563*03ca6dbdSKonstantin Belousov if (state->nwa->owner == 0) { 564*03ca6dbdSKonstantin Belousov state->error = EINVAL; 565*03ca6dbdSKonstantin Belousov return; 566*03ca6dbdSKonstantin Belousov } 567*03ca6dbdSKonstantin Belousov if (mutex->a.owner == 0 || mutex->abandoned) 568*03ca6dbdSKonstantin Belousov mutex->a.count = 1; 569*03ca6dbdSKonstantin Belousov else 570*03ca6dbdSKonstantin Belousov mutex->a.count++; 571*03ca6dbdSKonstantin Belousov mutex->a.owner = state->nwa->owner; 572*03ca6dbdSKonstantin Belousov if (mutex->abandoned && state->error == 0) 573*03ca6dbdSKonstantin Belousov state->error = EOWNERDEAD; 574*03ca6dbdSKonstantin Belousov mutex->abandoned = false; 575*03ca6dbdSKonstantin Belousov } 576*03ca6dbdSKonstantin Belousov 577*03ca6dbdSKonstantin Belousov static bool 578*03ca6dbdSKonstantin Belousov ntsync_mutex_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state, 579*03ca6dbdSKonstantin Belousov int index, bool *stop) 580*03ca6dbdSKonstantin Belousov { 581*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 582*03ca6dbdSKonstantin Belousov 583*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX); 584*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 585*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 586*03ca6dbdSKonstantin Belousov if (!ntsync_mutex_can_lock(mutex, state->nwa->owner)) 587*03ca6dbdSKonstantin Belousov return (false); 588*03ca6dbdSKonstantin Belousov if (state->nwa->owner == 0) { 589*03ca6dbdSKonstantin Belousov state->error = EINVAL; 590*03ca6dbdSKonstantin Belousov *stop = true; 591*03ca6dbdSKonstantin Belousov return (false); 592*03ca6dbdSKonstantin Belousov } 593*03ca6dbdSKonstantin Belousov mutex->a1 = mutex->a; 594*03ca6dbdSKonstantin Belousov if (mutex->a.owner == 0 || mutex->abandoned) 595*03ca6dbdSKonstantin Belousov mutex->a1.count = 1; 596*03ca6dbdSKonstantin Belousov else 597*03ca6dbdSKonstantin Belousov mutex->a1.count++; 598*03ca6dbdSKonstantin Belousov mutex->a1.owner = state->nwa->owner; 599*03ca6dbdSKonstantin Belousov return (true); 600*03ca6dbdSKonstantin Belousov } 601*03ca6dbdSKonstantin Belousov 602*03ca6dbdSKonstantin Belousov static void 603*03ca6dbdSKonstantin Belousov ntsync_mutex_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state, 604*03ca6dbdSKonstantin Belousov int index) 605*03ca6dbdSKonstantin Belousov { 606*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 607*03ca6dbdSKonstantin Belousov 608*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX); 609*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 610*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 611*03ca6dbdSKonstantin Belousov mutex->a = mutex->a1; 612*03ca6dbdSKonstantin Belousov if (mutex->abandoned) 613*03ca6dbdSKonstantin Belousov state->error = EOWNERDEAD; 614*03ca6dbdSKonstantin Belousov mutex->abandoned = false; 615*03ca6dbdSKonstantin Belousov } 616*03ca6dbdSKonstantin Belousov 617*03ca6dbdSKonstantin Belousov static void 618*03ca6dbdSKonstantin Belousov ntsync_mutex_post_commit(struct ntsync_obj *obj, 619*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index) 620*03ca6dbdSKonstantin Belousov { 621*03ca6dbdSKonstantin Belousov } 622*03ca6dbdSKonstantin Belousov 623*03ca6dbdSKonstantin Belousov static int 624*03ca6dbdSKonstantin Belousov ntsync_mutex_close(struct file *fp, struct thread *td) 625*03ca6dbdSKonstantin Belousov { 626*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 627*03ca6dbdSKonstantin Belousov 628*03ca6dbdSKonstantin Belousov mutex = fp->f_data; 629*03ca6dbdSKonstantin Belousov ntsync_close_obj(&mutex->obj, td); 630*03ca6dbdSKonstantin Belousov free(mutex, M_NTSYNC); 631*03ca6dbdSKonstantin Belousov return (0); 632*03ca6dbdSKonstantin Belousov } 633*03ca6dbdSKonstantin Belousov 634*03ca6dbdSKonstantin Belousov int 635*03ca6dbdSKonstantin Belousov ntsync_mutex_unlock(struct thread *td, struct file *fp, 636*03ca6dbdSKonstantin Belousov struct ntsync_mutex_args *a) 637*03ca6dbdSKonstantin Belousov { 638*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 639*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 640*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 641*03ca6dbdSKonstantin Belousov uint32_t prev; 642*03ca6dbdSKonstantin Belousov int error; 643*03ca6dbdSKonstantin Belousov 644*03ca6dbdSKonstantin Belousov obj = fp->f_data; 645*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX) 646*03ca6dbdSKonstantin Belousov return (EINVAL); 647*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 648*03ca6dbdSKonstantin Belousov priv = obj->owner; 649*03ca6dbdSKonstantin Belousov 650*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 651*03ca6dbdSKonstantin Belousov if (a->owner == 0) { 652*03ca6dbdSKonstantin Belousov error = EINVAL; 653*03ca6dbdSKonstantin Belousov } else if (a->owner != mutex->a.owner) { 654*03ca6dbdSKonstantin Belousov error = EPERM; 655*03ca6dbdSKonstantin Belousov } else { 656*03ca6dbdSKonstantin Belousov error = 0; 657*03ca6dbdSKonstantin Belousov prev = mutex->a.count; 658*03ca6dbdSKonstantin Belousov MPASS(mutex->a.count > 0); 659*03ca6dbdSKonstantin Belousov mutex->a.count--; 660*03ca6dbdSKonstantin Belousov a->count = prev; 661*03ca6dbdSKonstantin Belousov if (mutex->a.count == 0) { 662*03ca6dbdSKonstantin Belousov mutex->a.owner = 0; 663*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj); 664*03ca6dbdSKonstantin Belousov } 665*03ca6dbdSKonstantin Belousov } 666*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 667*03ca6dbdSKonstantin Belousov return (error); 668*03ca6dbdSKonstantin Belousov } 669*03ca6dbdSKonstantin Belousov 670*03ca6dbdSKonstantin Belousov int 671*03ca6dbdSKonstantin Belousov ntsync_mutex_kill(struct thread *td, struct file *fp, uint32_t val) 672*03ca6dbdSKonstantin Belousov { 673*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 674*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 675*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 676*03ca6dbdSKonstantin Belousov int error; 677*03ca6dbdSKonstantin Belousov 678*03ca6dbdSKonstantin Belousov obj = fp->f_data; 679*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX) 680*03ca6dbdSKonstantin Belousov return (EINVAL); 681*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 682*03ca6dbdSKonstantin Belousov priv = obj->owner; 683*03ca6dbdSKonstantin Belousov 684*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 685*03ca6dbdSKonstantin Belousov if (val == 0) { 686*03ca6dbdSKonstantin Belousov error = EINVAL; 687*03ca6dbdSKonstantin Belousov } else if (mutex->a.owner != val) { 688*03ca6dbdSKonstantin Belousov error = EPERM; 689*03ca6dbdSKonstantin Belousov } else { 690*03ca6dbdSKonstantin Belousov error = 0; 691*03ca6dbdSKonstantin Belousov mutex->a.owner = 0; 692*03ca6dbdSKonstantin Belousov mutex->a.count = 0; 693*03ca6dbdSKonstantin Belousov mutex->abandoned = true; 694*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj); 695*03ca6dbdSKonstantin Belousov } 696*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 697*03ca6dbdSKonstantin Belousov return (error); 698*03ca6dbdSKonstantin Belousov } 699*03ca6dbdSKonstantin Belousov 700*03ca6dbdSKonstantin Belousov int 701*03ca6dbdSKonstantin Belousov ntsync_mutex_read(struct thread *td, struct file *fp, 702*03ca6dbdSKonstantin Belousov struct ntsync_mutex_args *a, bool *doco) 703*03ca6dbdSKonstantin Belousov { 704*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 705*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 706*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 707*03ca6dbdSKonstantin Belousov int error; 708*03ca6dbdSKonstantin Belousov 709*03ca6dbdSKonstantin Belousov *doco = false; 710*03ca6dbdSKonstantin Belousov obj = fp->f_data; 711*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_MUTEX) 712*03ca6dbdSKonstantin Belousov return (EINVAL); 713*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 714*03ca6dbdSKonstantin Belousov priv = obj->owner; 715*03ca6dbdSKonstantin Belousov error = 0; 716*03ca6dbdSKonstantin Belousov 717*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 718*03ca6dbdSKonstantin Belousov *a = mutex->a; 719*03ca6dbdSKonstantin Belousov if (mutex->abandoned) 720*03ca6dbdSKonstantin Belousov error = EOWNERDEAD; 721*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 722*03ca6dbdSKonstantin Belousov *doco = true; 723*03ca6dbdSKonstantin Belousov return (error); 724*03ca6dbdSKonstantin Belousov } 725*03ca6dbdSKonstantin Belousov 726*03ca6dbdSKonstantin Belousov static int 727*03ca6dbdSKonstantin Belousov ntsync_mutex_ioctl(struct file *fp, u_long com, void *data, 728*03ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td) 729*03ca6dbdSKonstantin Belousov { 730*03ca6dbdSKonstantin Belousov struct ntsync_mutex_args aa; 731*03ca6dbdSKonstantin Belousov int error, error1; 732*03ca6dbdSKonstantin Belousov bool doco; 733*03ca6dbdSKonstantin Belousov 734*03ca6dbdSKonstantin Belousov doco = false; 735*03ca6dbdSKonstantin Belousov switch (com) { 736*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_UNLOCK: 737*03ca6dbdSKonstantin Belousov error = ntsync_mutex_unlock(td, fp, data); 738*03ca6dbdSKonstantin Belousov break; 739*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_KILL: 740*03ca6dbdSKonstantin Belousov error = ntsync_mutex_kill(td, fp, *(uint32_t *)data); 741*03ca6dbdSKonstantin Belousov break; 742*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_MUTEX_READ: 743*03ca6dbdSKonstantin Belousov error = ntsync_mutex_read(td, fp, &aa, &doco); 744*03ca6dbdSKonstantin Belousov if (doco) { 745*03ca6dbdSKonstantin Belousov error1 = ntsync_ioctl_copyout(td, &aa, sizeof(aa)); 746*03ca6dbdSKonstantin Belousov if (error1 != 0) 747*03ca6dbdSKonstantin Belousov error = error1; 748*03ca6dbdSKonstantin Belousov } 749*03ca6dbdSKonstantin Belousov break; 750*03ca6dbdSKonstantin Belousov default: 751*03ca6dbdSKonstantin Belousov error = ENOTTY; 752*03ca6dbdSKonstantin Belousov break; 753*03ca6dbdSKonstantin Belousov } 754*03ca6dbdSKonstantin Belousov return (error); 755*03ca6dbdSKonstantin Belousov } 756*03ca6dbdSKonstantin Belousov 757*03ca6dbdSKonstantin Belousov static int 758*03ca6dbdSKonstantin Belousov ntsync_mutex_stat(struct file *fp, struct stat *sbp, struct ucred *cred) 759*03ca6dbdSKonstantin Belousov { 760*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 761*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 762*03ca6dbdSKonstantin Belousov 763*03ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC); 764*03ca6dbdSKonstantin Belousov obj = fp->f_data; 765*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_MUTEX); 766*03ca6dbdSKonstantin Belousov mutex = OBJ_TO_MUTEX(obj); 767*03ca6dbdSKonstantin Belousov 768*03ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp)); 769*03ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR; 770*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner); 771*03ca6dbdSKonstantin Belousov sbp->st_size = mutex->a.owner; 772*03ca6dbdSKonstantin Belousov sbp->st_nlink = mutex->a.count; 773*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner); 774*03ca6dbdSKonstantin Belousov return (0); 775*03ca6dbdSKonstantin Belousov } 776*03ca6dbdSKonstantin Belousov 777*03ca6dbdSKonstantin Belousov static int 778*03ca6dbdSKonstantin Belousov ntsync_mutex_fill_kinfo(struct file *fp, struct kinfo_file *kif, 779*03ca6dbdSKonstantin Belousov struct filedesc *fdp) 780*03ca6dbdSKonstantin Belousov { 781*03ca6dbdSKonstantin Belousov // XXXKIB 782*03ca6dbdSKonstantin Belousov return (0); 783*03ca6dbdSKonstantin Belousov } 784*03ca6dbdSKonstantin Belousov 785*03ca6dbdSKonstantin Belousov struct fileops ntsync_mutex_fops = { 786*03ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr, 787*03ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr, 788*03ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate, 789*03ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_mutex_ioctl, 790*03ca6dbdSKonstantin Belousov .fo_poll = invfo_poll, 791*03ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter, 792*03ca6dbdSKonstantin Belousov .fo_stat = ntsync_mutex_stat, 793*03ca6dbdSKonstantin Belousov .fo_close = ntsync_mutex_close, 794*03ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod, 795*03ca6dbdSKonstantin Belousov .fo_chown = invfo_chown, 796*03ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile, 797*03ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_mutex_fill_kinfo, 798*03ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE, 799*03ca6dbdSKonstantin Belousov }; 800*03ca6dbdSKonstantin Belousov 801*03ca6dbdSKonstantin Belousov static int 802*03ca6dbdSKonstantin Belousov ntsync_create_mutex(struct ntsync_mutex_args *args, struct ntsync_priv *priv, 803*03ca6dbdSKonstantin Belousov struct thread *td) 804*03ca6dbdSKonstantin Belousov { 805*03ca6dbdSKonstantin Belousov struct ntsync_obj_mutex *mutex; 806*03ca6dbdSKonstantin Belousov int error; 807*03ca6dbdSKonstantin Belousov 808*03ca6dbdSKonstantin Belousov if ((args->owner != 0 && args->count == 0) || 809*03ca6dbdSKonstantin Belousov (args->owner == 0 && args->count != 0)) 810*03ca6dbdSKonstantin Belousov return (EINVAL); 811*03ca6dbdSKonstantin Belousov 812*03ca6dbdSKonstantin Belousov mutex = malloc(sizeof(*mutex), M_NTSYNC, M_WAITOK | M_ZERO); 813*03ca6dbdSKonstantin Belousov mutex->obj.type = NTSYNC_OBJ_MUTEX; 814*03ca6dbdSKonstantin Belousov mutex->obj.is_signaled = ntsync_mutex_is_signaled; 815*03ca6dbdSKonstantin Belousov mutex->obj.consume = ntsync_mutex_consume; 816*03ca6dbdSKonstantin Belousov mutex->obj.prepare = ntsync_mutex_prepare; 817*03ca6dbdSKonstantin Belousov mutex->obj.commit = ntsync_mutex_commit; 818*03ca6dbdSKonstantin Belousov mutex->obj.post_commit = ntsync_mutex_post_commit; 819*03ca6dbdSKonstantin Belousov mutex->a = *args; 820*03ca6dbdSKonstantin Belousov mutex->abandoned = false; 821*03ca6dbdSKonstantin Belousov 822*03ca6dbdSKonstantin Belousov error = ntsync_create_obj(&mutex->obj, &ntsync_mutex_fops, priv, td); 823*03ca6dbdSKonstantin Belousov if (error != 0) 824*03ca6dbdSKonstantin Belousov free(mutex, M_NTSYNC); 825*03ca6dbdSKonstantin Belousov 826*03ca6dbdSKonstantin Belousov return (error); 827*03ca6dbdSKonstantin Belousov } 828*03ca6dbdSKonstantin Belousov 829*03ca6dbdSKonstantin Belousov static bool 830*03ca6dbdSKonstantin Belousov ntsync_event_is_signaled(struct ntsync_obj *obj, 831*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index) 832*03ca6dbdSKonstantin Belousov { 833*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 834*03ca6dbdSKonstantin Belousov 835*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 836*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 837*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 838*03ca6dbdSKonstantin Belousov return (event->a.signaled != 0); 839*03ca6dbdSKonstantin Belousov } 840*03ca6dbdSKonstantin Belousov 841*03ca6dbdSKonstantin Belousov static void 842*03ca6dbdSKonstantin Belousov ntsync_event_consume(struct ntsync_obj *obj, struct ntsync_wait_state *state, 843*03ca6dbdSKonstantin Belousov int index) 844*03ca6dbdSKonstantin Belousov { 845*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 846*03ca6dbdSKonstantin Belousov 847*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 848*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 849*03ca6dbdSKonstantin Belousov MPASS(ntsync_event_is_signaled(obj, state, index)); 850*03ca6dbdSKonstantin Belousov 851*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 852*03ca6dbdSKonstantin Belousov if (event->a.manual == 0) 853*03ca6dbdSKonstantin Belousov event->a.signaled = 0; 854*03ca6dbdSKonstantin Belousov } 855*03ca6dbdSKonstantin Belousov 856*03ca6dbdSKonstantin Belousov static bool 857*03ca6dbdSKonstantin Belousov ntsync_event_prepare(struct ntsync_obj *obj, struct ntsync_wait_state *state, 858*03ca6dbdSKonstantin Belousov int index, bool *stop) 859*03ca6dbdSKonstantin Belousov { 860*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 861*03ca6dbdSKonstantin Belousov 862*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 863*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 864*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 865*03ca6dbdSKonstantin Belousov if (!ntsync_event_is_signaled(obj, state, index)) 866*03ca6dbdSKonstantin Belousov return (false); 867*03ca6dbdSKonstantin Belousov event->a1 = event->a; 868*03ca6dbdSKonstantin Belousov return (true); 869*03ca6dbdSKonstantin Belousov } 870*03ca6dbdSKonstantin Belousov 871*03ca6dbdSKonstantin Belousov static void 872*03ca6dbdSKonstantin Belousov ntsync_event_commit(struct ntsync_obj *obj, struct ntsync_wait_state *state, 873*03ca6dbdSKonstantin Belousov int index) 874*03ca6dbdSKonstantin Belousov { 875*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 876*03ca6dbdSKonstantin Belousov 877*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 878*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 879*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 880*03ca6dbdSKonstantin Belousov event->a = event->a1; 881*03ca6dbdSKonstantin Belousov if (event->pulse && event->a.manual == 0) { 882*03ca6dbdSKonstantin Belousov event->a.signaled = 0; 883*03ca6dbdSKonstantin Belousov event->pulse = false; 884*03ca6dbdSKonstantin Belousov } 885*03ca6dbdSKonstantin Belousov } 886*03ca6dbdSKonstantin Belousov 887*03ca6dbdSKonstantin Belousov static void 888*03ca6dbdSKonstantin Belousov ntsync_event_post_commit(struct ntsync_obj *obj, 889*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state, int index) 890*03ca6dbdSKonstantin Belousov { 891*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 892*03ca6dbdSKonstantin Belousov 893*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 894*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_ASSERT(obj->owner); 895*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 896*03ca6dbdSKonstantin Belousov if (event->a.manual == 0) 897*03ca6dbdSKonstantin Belousov event->a.signaled = 0; 898*03ca6dbdSKonstantin Belousov } 899*03ca6dbdSKonstantin Belousov 900*03ca6dbdSKonstantin Belousov static int 901*03ca6dbdSKonstantin Belousov ntsync_event_close(struct file *fp, struct thread *td) 902*03ca6dbdSKonstantin Belousov { 903*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 904*03ca6dbdSKonstantin Belousov 905*03ca6dbdSKonstantin Belousov event = fp->f_data; 906*03ca6dbdSKonstantin Belousov ntsync_close_obj(&event->obj, td); 907*03ca6dbdSKonstantin Belousov free(event, M_NTSYNC); 908*03ca6dbdSKonstantin Belousov return (0); 909*03ca6dbdSKonstantin Belousov } 910*03ca6dbdSKonstantin Belousov 911*03ca6dbdSKonstantin Belousov int 912*03ca6dbdSKonstantin Belousov ntsync_event_set(struct thread *td, struct file *fp, uint32_t *val) 913*03ca6dbdSKonstantin Belousov { 914*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 915*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 916*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 917*03ca6dbdSKonstantin Belousov uint32_t prev; 918*03ca6dbdSKonstantin Belousov 919*03ca6dbdSKonstantin Belousov obj = fp->f_data; 920*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT) 921*03ca6dbdSKonstantin Belousov return (EINVAL); 922*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 923*03ca6dbdSKonstantin Belousov priv = obj->owner; 924*03ca6dbdSKonstantin Belousov 925*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 926*03ca6dbdSKonstantin Belousov prev = event->a.signaled; 927*03ca6dbdSKonstantin Belousov event->a.signaled = 1; 928*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj); 929*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 930*03ca6dbdSKonstantin Belousov 931*03ca6dbdSKonstantin Belousov *val = prev; 932*03ca6dbdSKonstantin Belousov return (0); 933*03ca6dbdSKonstantin Belousov } 934*03ca6dbdSKonstantin Belousov 935*03ca6dbdSKonstantin Belousov int 936*03ca6dbdSKonstantin Belousov ntsync_event_reset(struct thread *td, struct file *fp, uint32_t *val) 937*03ca6dbdSKonstantin Belousov { 938*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 939*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 940*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 941*03ca6dbdSKonstantin Belousov uint32_t prev; 942*03ca6dbdSKonstantin Belousov 943*03ca6dbdSKonstantin Belousov obj = fp->f_data; 944*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT) 945*03ca6dbdSKonstantin Belousov return (EINVAL); 946*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 947*03ca6dbdSKonstantin Belousov priv = obj->owner; 948*03ca6dbdSKonstantin Belousov 949*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 950*03ca6dbdSKonstantin Belousov prev = event->a.signaled; 951*03ca6dbdSKonstantin Belousov event->a.signaled = 0; 952*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 953*03ca6dbdSKonstantin Belousov 954*03ca6dbdSKonstantin Belousov *val = prev; 955*03ca6dbdSKonstantin Belousov return (0); 956*03ca6dbdSKonstantin Belousov } 957*03ca6dbdSKonstantin Belousov 958*03ca6dbdSKonstantin Belousov int 959*03ca6dbdSKonstantin Belousov ntsync_event_pulse(struct thread *td, struct file *fp, uint32_t *val) 960*03ca6dbdSKonstantin Belousov { 961*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 962*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 963*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 964*03ca6dbdSKonstantin Belousov uint32_t prev; 965*03ca6dbdSKonstantin Belousov 966*03ca6dbdSKonstantin Belousov obj = fp->f_data; 967*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT) 968*03ca6dbdSKonstantin Belousov return (EINVAL); 969*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 970*03ca6dbdSKonstantin Belousov priv = obj->owner; 971*03ca6dbdSKonstantin Belousov 972*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 973*03ca6dbdSKonstantin Belousov prev = event->a.signaled; 974*03ca6dbdSKonstantin Belousov event->a.signaled = 1; 975*03ca6dbdSKonstantin Belousov event->pulse = true; 976*03ca6dbdSKonstantin Belousov ntsync_wakeup_waiters(obj); 977*03ca6dbdSKonstantin Belousov event->a.signaled = 0; 978*03ca6dbdSKonstantin Belousov event->pulse = false; 979*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 980*03ca6dbdSKonstantin Belousov 981*03ca6dbdSKonstantin Belousov *val = prev; 982*03ca6dbdSKonstantin Belousov return (0); 983*03ca6dbdSKonstantin Belousov } 984*03ca6dbdSKonstantin Belousov 985*03ca6dbdSKonstantin Belousov int 986*03ca6dbdSKonstantin Belousov ntsync_event_read(struct thread *td, struct file *fp, 987*03ca6dbdSKonstantin Belousov struct ntsync_event_args *a) 988*03ca6dbdSKonstantin Belousov { 989*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 990*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 991*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 992*03ca6dbdSKonstantin Belousov 993*03ca6dbdSKonstantin Belousov obj = fp->f_data; 994*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT) 995*03ca6dbdSKonstantin Belousov return (EINVAL); 996*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 997*03ca6dbdSKonstantin Belousov priv = obj->owner; 998*03ca6dbdSKonstantin Belousov 999*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 1000*03ca6dbdSKonstantin Belousov *a = event->a; 1001*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 1002*03ca6dbdSKonstantin Belousov 1003*03ca6dbdSKonstantin Belousov return (0); 1004*03ca6dbdSKonstantin Belousov } 1005*03ca6dbdSKonstantin Belousov 1006*03ca6dbdSKonstantin Belousov static int 1007*03ca6dbdSKonstantin Belousov ntsync_event_ioctl(struct file *fp, u_long com, void *data, 1008*03ca6dbdSKonstantin Belousov struct ucred *active_cred, struct thread *td) 1009*03ca6dbdSKonstantin Belousov { 1010*03ca6dbdSKonstantin Belousov int error; 1011*03ca6dbdSKonstantin Belousov 1012*03ca6dbdSKonstantin Belousov switch (com) { 1013*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_SET: 1014*03ca6dbdSKonstantin Belousov error = ntsync_event_set(td, fp, data); 1015*03ca6dbdSKonstantin Belousov break; 1016*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_RESET: 1017*03ca6dbdSKonstantin Belousov error = ntsync_event_reset(td, fp, data); 1018*03ca6dbdSKonstantin Belousov break; 1019*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_PULSE: 1020*03ca6dbdSKonstantin Belousov error = ntsync_event_pulse(td, fp, data); 1021*03ca6dbdSKonstantin Belousov break; 1022*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_EVENT_READ: 1023*03ca6dbdSKonstantin Belousov error = ntsync_event_read(td, fp, data); 1024*03ca6dbdSKonstantin Belousov break; 1025*03ca6dbdSKonstantin Belousov default: 1026*03ca6dbdSKonstantin Belousov error = ENOTTY; 1027*03ca6dbdSKonstantin Belousov break; 1028*03ca6dbdSKonstantin Belousov } 1029*03ca6dbdSKonstantin Belousov return (error); 1030*03ca6dbdSKonstantin Belousov } 1031*03ca6dbdSKonstantin Belousov 1032*03ca6dbdSKonstantin Belousov static int 1033*03ca6dbdSKonstantin Belousov ntsync_event_stat(struct file *fp, struct stat *sbp, struct ucred *cred) 1034*03ca6dbdSKonstantin Belousov { 1035*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 1036*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 1037*03ca6dbdSKonstantin Belousov 1038*03ca6dbdSKonstantin Belousov MPASS(fp->f_type == DTYPE_NTSYNC); 1039*03ca6dbdSKonstantin Belousov obj = fp->f_data; 1040*03ca6dbdSKonstantin Belousov MPASS(obj->type == NTSYNC_OBJ_EVENT); 1041*03ca6dbdSKonstantin Belousov event = OBJ_TO_EVENT(obj); 1042*03ca6dbdSKonstantin Belousov 1043*03ca6dbdSKonstantin Belousov memset(sbp, 0, sizeof(*sbp)); 1044*03ca6dbdSKonstantin Belousov sbp->st_mode = S_IFREG /* XXXKIB */ | S_IRUSR | S_IWUSR; 1045*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(obj->owner); 1046*03ca6dbdSKonstantin Belousov sbp->st_size = event->a.signaled; 1047*03ca6dbdSKonstantin Belousov sbp->st_nlink = event->a.manual; 1048*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(obj->owner); 1049*03ca6dbdSKonstantin Belousov return (0); 1050*03ca6dbdSKonstantin Belousov } 1051*03ca6dbdSKonstantin Belousov 1052*03ca6dbdSKonstantin Belousov static int 1053*03ca6dbdSKonstantin Belousov ntsync_event_fill_kinfo(struct file *fp, struct kinfo_file *kif, 1054*03ca6dbdSKonstantin Belousov struct filedesc *fdp) 1055*03ca6dbdSKonstantin Belousov { 1056*03ca6dbdSKonstantin Belousov // XXXKIB 1057*03ca6dbdSKonstantin Belousov return (0); 1058*03ca6dbdSKonstantin Belousov } 1059*03ca6dbdSKonstantin Belousov 1060*03ca6dbdSKonstantin Belousov struct fileops ntsync_event_fops = { 1061*03ca6dbdSKonstantin Belousov .fo_read = invfo_rdwr, 1062*03ca6dbdSKonstantin Belousov .fo_write = invfo_rdwr, 1063*03ca6dbdSKonstantin Belousov .fo_truncate = invfo_truncate, 1064*03ca6dbdSKonstantin Belousov .fo_ioctl = ntsync_event_ioctl, 1065*03ca6dbdSKonstantin Belousov .fo_poll = invfo_poll, 1066*03ca6dbdSKonstantin Belousov .fo_kqfilter = invfo_kqfilter, 1067*03ca6dbdSKonstantin Belousov .fo_stat = ntsync_event_stat, 1068*03ca6dbdSKonstantin Belousov .fo_close = ntsync_event_close, 1069*03ca6dbdSKonstantin Belousov .fo_chmod = invfo_chmod, 1070*03ca6dbdSKonstantin Belousov .fo_chown = invfo_chown, 1071*03ca6dbdSKonstantin Belousov .fo_sendfile = invfo_sendfile, 1072*03ca6dbdSKonstantin Belousov .fo_fill_kinfo = ntsync_event_fill_kinfo, 1073*03ca6dbdSKonstantin Belousov .fo_flags = DFLAG_PASSABLE, 1074*03ca6dbdSKonstantin Belousov }; 1075*03ca6dbdSKonstantin Belousov 1076*03ca6dbdSKonstantin Belousov static int 1077*03ca6dbdSKonstantin Belousov ntsync_create_event(struct ntsync_event_args *args, struct ntsync_priv *priv, 1078*03ca6dbdSKonstantin Belousov struct thread *td) 1079*03ca6dbdSKonstantin Belousov { 1080*03ca6dbdSKonstantin Belousov struct ntsync_obj_event *event; 1081*03ca6dbdSKonstantin Belousov int error; 1082*03ca6dbdSKonstantin Belousov 1083*03ca6dbdSKonstantin Belousov event = malloc(sizeof(*event), M_NTSYNC, M_WAITOK | M_ZERO); 1084*03ca6dbdSKonstantin Belousov event->obj.type = NTSYNC_OBJ_EVENT; 1085*03ca6dbdSKonstantin Belousov event->obj.is_signaled = ntsync_event_is_signaled; 1086*03ca6dbdSKonstantin Belousov event->obj.consume = ntsync_event_consume; 1087*03ca6dbdSKonstantin Belousov event->obj.prepare = ntsync_event_prepare; 1088*03ca6dbdSKonstantin Belousov event->obj.commit = ntsync_event_commit; 1089*03ca6dbdSKonstantin Belousov event->obj.post_commit = ntsync_event_post_commit; 1090*03ca6dbdSKonstantin Belousov event->a = *args; 1091*03ca6dbdSKonstantin Belousov 1092*03ca6dbdSKonstantin Belousov error = ntsync_create_obj(&event->obj, &ntsync_event_fops, priv, td); 1093*03ca6dbdSKonstantin Belousov if (error != 0) 1094*03ca6dbdSKonstantin Belousov free(event, M_NTSYNC); 1095*03ca6dbdSKonstantin Belousov 1096*03ca6dbdSKonstantin Belousov return (error); 1097*03ca6dbdSKonstantin Belousov } 1098*03ca6dbdSKonstantin Belousov 1099*03ca6dbdSKonstantin Belousov static void 1100*03ca6dbdSKonstantin Belousov ntsync_free_priv(struct ntsync_priv *priv) 1101*03ca6dbdSKonstantin Belousov { 1102*03ca6dbdSKonstantin Belousov bool do_free; 1103*03ca6dbdSKonstantin Belousov 1104*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 1105*03ca6dbdSKonstantin Belousov do_free = priv->closed && priv->objs_cnt == 0; 1106*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 1107*03ca6dbdSKonstantin Belousov if (do_free) { 1108*03ca6dbdSKonstantin Belousov mtx_destroy(&priv->lock); 1109*03ca6dbdSKonstantin Belousov free(priv, M_NTSYNC); 1110*03ca6dbdSKonstantin Belousov } 1111*03ca6dbdSKonstantin Belousov } 1112*03ca6dbdSKonstantin Belousov 1113*03ca6dbdSKonstantin Belousov static void 1114*03ca6dbdSKonstantin Belousov ntsync_priv_dtr(void *data) 1115*03ca6dbdSKonstantin Belousov { 1116*03ca6dbdSKonstantin Belousov ntsync_free_priv(data); 1117*03ca6dbdSKonstantin Belousov } 1118*03ca6dbdSKonstantin Belousov 1119*03ca6dbdSKonstantin Belousov static int 1120*03ca6dbdSKonstantin Belousov ntsync_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 1121*03ca6dbdSKonstantin Belousov { 1122*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 1123*03ca6dbdSKonstantin Belousov 1124*03ca6dbdSKonstantin Belousov priv = malloc(sizeof(*priv), M_NTSYNC, M_WAITOK); 1125*03ca6dbdSKonstantin Belousov priv->closed = false; 1126*03ca6dbdSKonstantin Belousov priv->objs_cnt = 0; 1127*03ca6dbdSKonstantin Belousov mtx_init(&priv->lock, "ntsync", "ntsync", MTX_DEF | MTX_NEW); 1128*03ca6dbdSKonstantin Belousov devfs_set_cdevpriv(priv, ntsync_priv_dtr); 1129*03ca6dbdSKonstantin Belousov return (0); 1130*03ca6dbdSKonstantin Belousov } 1131*03ca6dbdSKonstantin Belousov 1132*03ca6dbdSKonstantin Belousov static int 1133*03ca6dbdSKonstantin Belousov ntsync_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 1134*03ca6dbdSKonstantin Belousov { 1135*03ca6dbdSKonstantin Belousov struct ntsync_priv *priv; 1136*03ca6dbdSKonstantin Belousov void *a; 1137*03ca6dbdSKonstantin Belousov int error; 1138*03ca6dbdSKonstantin Belousov 1139*03ca6dbdSKonstantin Belousov error = devfs_get_cdevpriv(&a); 1140*03ca6dbdSKonstantin Belousov if (error == 0) { 1141*03ca6dbdSKonstantin Belousov priv = a; 1142*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_LOCK(priv); 1143*03ca6dbdSKonstantin Belousov priv->closed = true; 1144*03ca6dbdSKonstantin Belousov NTSYNC_PRIV_UNLOCK(priv); 1145*03ca6dbdSKonstantin Belousov } 1146*03ca6dbdSKonstantin Belousov devfs_clear_cdevpriv(); 1147*03ca6dbdSKonstantin Belousov return (0); 1148*03ca6dbdSKonstantin Belousov } 1149*03ca6dbdSKonstantin Belousov 1150*03ca6dbdSKonstantin Belousov static int 1151*03ca6dbdSKonstantin Belousov ntsync_wait_state_get(struct ntsync_wait_args *nwa, u_long cmd, 1152*03ca6dbdSKonstantin Belousov struct ntsync_priv *owner, struct ntsync_wait_state **statep, 1153*03ca6dbdSKonstantin Belousov struct thread *td) 1154*03ca6dbdSKonstantin Belousov { 1155*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state; 1156*03ca6dbdSKonstantin Belousov struct ntsync_obj *obj; 1157*03ca6dbdSKonstantin Belousov struct bintime btb; 1158*03ca6dbdSKonstantin Belousov int error, i, j; 1159*03ca6dbdSKonstantin Belousov 1160*03ca6dbdSKonstantin Belousov if (nwa->count > NTSYNC_MAX_WAIT_COUNT) 1161*03ca6dbdSKonstantin Belousov return (EINVAL); 1162*03ca6dbdSKonstantin Belousov if ((nwa->flags & ~NTSYNC_WAIT_REALTIME) != 0) 1163*03ca6dbdSKonstantin Belousov return (EINVAL); 1164*03ca6dbdSKonstantin Belousov 1165*03ca6dbdSKonstantin Belousov state = malloc(sizeof(*state), M_NTSYNC, M_WAITOK | M_ZERO); 1166*03ca6dbdSKonstantin Belousov state->nwa = nwa; 1167*03ca6dbdSKonstantin Belousov state->owner = owner; 1168*03ca6dbdSKonstantin Belousov state->all = cmd == NTSYNC_IOC_WAIT_ALL; 1169*03ca6dbdSKonstantin Belousov state->any = !state->all; 1170*03ca6dbdSKonstantin Belousov error = copyin((void *)(uintptr_t)nwa->objs, &state->fds[0], 1171*03ca6dbdSKonstantin Belousov nwa->count * sizeof(state->fds[0])); 1172*03ca6dbdSKonstantin Belousov if (error != 0) 1173*03ca6dbdSKonstantin Belousov return (error); 1174*03ca6dbdSKonstantin Belousov 1175*03ca6dbdSKonstantin Belousov i = 0; 1176*03ca6dbdSKonstantin Belousov if (nwa->alert != 0) { 1177*03ca6dbdSKonstantin Belousov error = fget_cap(td, nwa->alert, &cap_no_rights, NULL, 1178*03ca6dbdSKonstantin Belousov &state->fp_alert, NULL); 1179*03ca6dbdSKonstantin Belousov if (error != 0) { 1180*03ca6dbdSKonstantin Belousov state->fp_alert = NULL; 1181*03ca6dbdSKonstantin Belousov goto error_out; 1182*03ca6dbdSKonstantin Belousov } 1183*03ca6dbdSKonstantin Belousov if (state->fp_alert->f_type != DTYPE_NTSYNC) { 1184*03ca6dbdSKonstantin Belousov error = EINVAL; 1185*03ca6dbdSKonstantin Belousov goto error_out; 1186*03ca6dbdSKonstantin Belousov } 1187*03ca6dbdSKonstantin Belousov obj = state->fp_alert->f_data; 1188*03ca6dbdSKonstantin Belousov if (obj->type != NTSYNC_OBJ_EVENT || obj->owner != owner) { 1189*03ca6dbdSKonstantin Belousov error = EINVAL; 1190*03ca6dbdSKonstantin Belousov goto error_out; 1191*03ca6dbdSKonstantin Belousov } 1192*03ca6dbdSKonstantin Belousov state->alert_event = OBJ_TO_EVENT(obj); 1193*03ca6dbdSKonstantin Belousov } 1194*03ca6dbdSKonstantin Belousov 1195*03ca6dbdSKonstantin Belousov for (; i < nwa->count; i++) { 1196*03ca6dbdSKonstantin Belousov error = fget_cap(td, state->fds[i], &cap_no_rights, NULL, 1197*03ca6dbdSKonstantin Belousov &state->fps[i], NULL); 1198*03ca6dbdSKonstantin Belousov if (error != 0) { 1199*03ca6dbdSKonstantin Belousov state->fps[i] = NULL; 1200*03ca6dbdSKonstantin Belousov goto error_out; 1201*03ca6dbdSKonstantin Belousov } 1202*03ca6dbdSKonstantin Belousov if (state->fps[i]->f_type != DTYPE_NTSYNC || 1203*03ca6dbdSKonstantin Belousov (obj = state->fps[i]->f_data)->owner != owner) { 1204*03ca6dbdSKonstantin Belousov i++; 1205*03ca6dbdSKonstantin Belousov error = EINVAL; 1206*03ca6dbdSKonstantin Belousov goto error_out; 1207*03ca6dbdSKonstantin Belousov } 1208*03ca6dbdSKonstantin Belousov } 1209*03ca6dbdSKonstantin Belousov 1210*03ca6dbdSKonstantin Belousov state->obj_count = nwa->count; 1211*03ca6dbdSKonstantin Belousov for (i = 0; i < nwa->count; i++) 1212*03ca6dbdSKonstantin Belousov state->objs[i] = state->fps[i]->f_data; 1213*03ca6dbdSKonstantin Belousov if (state->alert_event != NULL) { 1214*03ca6dbdSKonstantin Belousov state->objs[i] = &state->alert_event->obj; 1215*03ca6dbdSKonstantin Belousov state->obj_count++; 1216*03ca6dbdSKonstantin Belousov } 1217*03ca6dbdSKonstantin Belousov 1218*03ca6dbdSKonstantin Belousov if (state->all) { 1219*03ca6dbdSKonstantin Belousov /* Check no dups */ 1220*03ca6dbdSKonstantin Belousov for (i = 0; i < state->obj_count; i++) { 1221*03ca6dbdSKonstantin Belousov obj = state->objs[i]; 1222*03ca6dbdSKonstantin Belousov for (j = i + 1; j < state->obj_count; j++) { 1223*03ca6dbdSKonstantin Belousov if (obj == state->objs[j]) { 1224*03ca6dbdSKonstantin Belousov i = state->obj_count; 1225*03ca6dbdSKonstantin Belousov error = EINVAL; 1226*03ca6dbdSKonstantin Belousov goto error_out; 1227*03ca6dbdSKonstantin Belousov } 1228*03ca6dbdSKonstantin Belousov } 1229*03ca6dbdSKonstantin Belousov } 1230*03ca6dbdSKonstantin Belousov } 1231*03ca6dbdSKonstantin Belousov 1232*03ca6dbdSKonstantin Belousov if (nwa->timeout == UINT64_MAX) { 1233*03ca6dbdSKonstantin Belousov state->sb = 0; 1234*03ca6dbdSKonstantin Belousov } else { 1235*03ca6dbdSKonstantin Belousov state->sb = nstosbt(nwa->timeout); 1236*03ca6dbdSKonstantin Belousov if ((nwa->flags & NTSYNC_WAIT_REALTIME) != 0) { 1237*03ca6dbdSKonstantin Belousov getboottimebin(&btb); 1238*03ca6dbdSKonstantin Belousov state->sb += bttosbt(btb); 1239*03ca6dbdSKonstantin Belousov } 1240*03ca6dbdSKonstantin Belousov } 1241*03ca6dbdSKonstantin Belousov 1242*03ca6dbdSKonstantin Belousov *statep = state; 1243*03ca6dbdSKonstantin Belousov return (0); 1244*03ca6dbdSKonstantin Belousov 1245*03ca6dbdSKonstantin Belousov error_out: 1246*03ca6dbdSKonstantin Belousov for (j = 0; j < i; j++) 1247*03ca6dbdSKonstantin Belousov fdrop(state->fps[j], td); 1248*03ca6dbdSKonstantin Belousov if (state->fp_alert != NULL) 1249*03ca6dbdSKonstantin Belousov fdrop(state->fp_alert, td); 1250*03ca6dbdSKonstantin Belousov return (error); 1251*03ca6dbdSKonstantin Belousov } 1252*03ca6dbdSKonstantin Belousov 1253*03ca6dbdSKonstantin Belousov static void 1254*03ca6dbdSKonstantin Belousov ntsync_wait_state_put(struct ntsync_wait_state *state, struct thread *td) 1255*03ca6dbdSKonstantin Belousov { 1256*03ca6dbdSKonstantin Belousov int i; 1257*03ca6dbdSKonstantin Belousov 1258*03ca6dbdSKonstantin Belousov for (i = 0; i < state->nwa->count; i++) 1259*03ca6dbdSKonstantin Belousov fdrop(state->fps[i], td); 1260*03ca6dbdSKonstantin Belousov if (state->fp_alert != NULL) 1261*03ca6dbdSKonstantin Belousov fdrop(state->fp_alert, td); 1262*03ca6dbdSKonstantin Belousov free(state, M_NTSYNC); 1263*03ca6dbdSKonstantin Belousov } 1264*03ca6dbdSKonstantin Belousov 1265*03ca6dbdSKonstantin Belousov static int 1266*03ca6dbdSKonstantin Belousov ntsync_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 1267*03ca6dbdSKonstantin Belousov struct thread *td) 1268*03ca6dbdSKonstantin Belousov { 1269*03ca6dbdSKonstantin Belousov struct ntsync_priv *owner; 1270*03ca6dbdSKonstantin Belousov struct ntsync_wait_args *nwa; 1271*03ca6dbdSKonstantin Belousov struct ntsync_wait_state *state; 1272*03ca6dbdSKonstantin Belousov void *a; 1273*03ca6dbdSKonstantin Belousov int error; 1274*03ca6dbdSKonstantin Belousov 1275*03ca6dbdSKonstantin Belousov error = devfs_get_cdevpriv(&a); 1276*03ca6dbdSKonstantin Belousov if (error != 0) 1277*03ca6dbdSKonstantin Belousov return (error); 1278*03ca6dbdSKonstantin Belousov owner = a; 1279*03ca6dbdSKonstantin Belousov 1280*03ca6dbdSKonstantin Belousov switch (cmd) { 1281*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_SEM: 1282*03ca6dbdSKonstantin Belousov error = ntsync_create_sem((struct ntsync_sem_args *)data, 1283*03ca6dbdSKonstantin Belousov owner, td); 1284*03ca6dbdSKonstantin Belousov break; 1285*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_MUTEX: 1286*03ca6dbdSKonstantin Belousov error = ntsync_create_mutex((struct ntsync_mutex_args *)data, 1287*03ca6dbdSKonstantin Belousov owner, td); 1288*03ca6dbdSKonstantin Belousov break; 1289*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_CREATE_EVENT: 1290*03ca6dbdSKonstantin Belousov error = ntsync_create_event((struct ntsync_event_args *)data, 1291*03ca6dbdSKonstantin Belousov owner, td); 1292*03ca6dbdSKonstantin Belousov break; 1293*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_WAIT_ANY: 1294*03ca6dbdSKonstantin Belousov nwa = (struct ntsync_wait_args *)data; 1295*03ca6dbdSKonstantin Belousov error = ntsync_wait_state_get(nwa, cmd, owner, &state, td); 1296*03ca6dbdSKonstantin Belousov if (error != 0) 1297*03ca6dbdSKonstantin Belousov break; 1298*03ca6dbdSKonstantin Belousov error = ntsync_wait(state, td); 1299*03ca6dbdSKonstantin Belousov if (error == 0) { 1300*03ca6dbdSKonstantin Belousov nwa->index = state->index; 1301*03ca6dbdSKonstantin Belousov error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa)); 1302*03ca6dbdSKonstantin Belousov if (error == 0) 1303*03ca6dbdSKonstantin Belousov error = state->error; 1304*03ca6dbdSKonstantin Belousov } 1305*03ca6dbdSKonstantin Belousov ntsync_wait_state_put(state, td); 1306*03ca6dbdSKonstantin Belousov break; 1307*03ca6dbdSKonstantin Belousov case NTSYNC_IOC_WAIT_ALL: 1308*03ca6dbdSKonstantin Belousov nwa = (struct ntsync_wait_args *)data; 1309*03ca6dbdSKonstantin Belousov error = ntsync_wait_state_get(nwa, cmd, owner, &state, td); 1310*03ca6dbdSKonstantin Belousov if (error != 0) 1311*03ca6dbdSKonstantin Belousov break; 1312*03ca6dbdSKonstantin Belousov error = ntsync_wait(state, td); 1313*03ca6dbdSKonstantin Belousov if (error == 0) { 1314*03ca6dbdSKonstantin Belousov nwa->index = state->index; 1315*03ca6dbdSKonstantin Belousov error = ntsync_ioctl_copyout(td, nwa, sizeof(*nwa)); 1316*03ca6dbdSKonstantin Belousov if (error == 0) 1317*03ca6dbdSKonstantin Belousov error = state->error; 1318*03ca6dbdSKonstantin Belousov } 1319*03ca6dbdSKonstantin Belousov ntsync_wait_state_put(state, td); 1320*03ca6dbdSKonstantin Belousov break; 1321*03ca6dbdSKonstantin Belousov 1322*03ca6dbdSKonstantin Belousov default: 1323*03ca6dbdSKonstantin Belousov error = ENOTTY; 1324*03ca6dbdSKonstantin Belousov break; 1325*03ca6dbdSKonstantin Belousov } 1326*03ca6dbdSKonstantin Belousov return (error); 1327*03ca6dbdSKonstantin Belousov } 1328*03ca6dbdSKonstantin Belousov 1329*03ca6dbdSKonstantin Belousov struct cdevsw ntsync_cdevsw = { 1330*03ca6dbdSKonstantin Belousov .d_version = D_VERSION, 1331*03ca6dbdSKonstantin Belousov .d_flags = 0, 1332*03ca6dbdSKonstantin Belousov .d_open = ntsync_open, 1333*03ca6dbdSKonstantin Belousov .d_close = ntsync_close, 1334*03ca6dbdSKonstantin Belousov .d_ioctl = ntsync_ioctl, 1335*03ca6dbdSKonstantin Belousov .d_name = "ntsync", 1336*03ca6dbdSKonstantin Belousov }; 1337*03ca6dbdSKonstantin Belousov 1338*03ca6dbdSKonstantin Belousov static int 1339*03ca6dbdSKonstantin Belousov ntsync_modevent(module_t mod __unused, int type, void *data __unused) 1340*03ca6dbdSKonstantin Belousov { 1341*03ca6dbdSKonstantin Belousov struct make_dev_args mda; 1342*03ca6dbdSKonstantin Belousov int error; 1343*03ca6dbdSKonstantin Belousov 1344*03ca6dbdSKonstantin Belousov error = 0; 1345*03ca6dbdSKonstantin Belousov switch (type) { 1346*03ca6dbdSKonstantin Belousov case MOD_LOAD: 1347*03ca6dbdSKonstantin Belousov make_dev_args_init(&mda); 1348*03ca6dbdSKonstantin Belousov mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME; 1349*03ca6dbdSKonstantin Belousov mda.mda_devsw = &ntsync_cdevsw; 1350*03ca6dbdSKonstantin Belousov mda.mda_uid = UID_ROOT; 1351*03ca6dbdSKonstantin Belousov mda.mda_gid = GID_GAMES; 1352*03ca6dbdSKonstantin Belousov mda.mda_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 1353*03ca6dbdSKonstantin Belousov S_IROTH | S_IWOTH; 1354*03ca6dbdSKonstantin Belousov 1355*03ca6dbdSKonstantin Belousov error = make_dev_s(&mda, &ntsync_cdev, "ntsync"); 1356*03ca6dbdSKonstantin Belousov if (error != 0) { 1357*03ca6dbdSKonstantin Belousov printf("cannot create ntsync dev err %d\n", error); 1358*03ca6dbdSKonstantin Belousov break; 1359*03ca6dbdSKonstantin Belousov } 1360*03ca6dbdSKonstantin Belousov if (bootverbose) 1361*03ca6dbdSKonstantin Belousov printf("ntsync\n"); 1362*03ca6dbdSKonstantin Belousov break; 1363*03ca6dbdSKonstantin Belousov 1364*03ca6dbdSKonstantin Belousov case MOD_UNLOAD: 1365*03ca6dbdSKonstantin Belousov destroy_dev(ntsync_cdev); 1366*03ca6dbdSKonstantin Belousov break; 1367*03ca6dbdSKonstantin Belousov 1368*03ca6dbdSKonstantin Belousov case MOD_SHUTDOWN: 1369*03ca6dbdSKonstantin Belousov break; 1370*03ca6dbdSKonstantin Belousov 1371*03ca6dbdSKonstantin Belousov default: 1372*03ca6dbdSKonstantin Belousov error = EOPNOTSUPP; 1373*03ca6dbdSKonstantin Belousov } 1374*03ca6dbdSKonstantin Belousov 1375*03ca6dbdSKonstantin Belousov return (error); 1376*03ca6dbdSKonstantin Belousov } 1377*03ca6dbdSKonstantin Belousov 1378*03ca6dbdSKonstantin Belousov DEV_MODULE(ntsync, ntsync_modevent, NULL); 1379*03ca6dbdSKonstantin Belousov MODULE_VERSION(ntsync, 1); 1380