/* * For debugging and outputting messages. Returns the name of the side of * the relationship associated with this queue. */ static const char * zc_side(queue_t *qp) { zc_state_t *zcs = qp->q_ptr; ASSERT(zcs != NULL); if (qp == zcs->zc_master_rdq || OTHERQ(qp) == zcs->zc_master_rdq) { return ("master"); } ASSERT(qp == zcs->zc_slave_rdq || OTHERQ(qp) == zcs->zc_slave_rdq); return ("slave"); }
/* ARGSUSED1 */ static int dropen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) { struct drstate *dsp; if (sflag != MODOPEN) { /* must be a pushed module */ return (EINVAL); } if (secpolicy_net_rawaccess(crp) != 0) { return (EPERM); } if (q->q_ptr != NULL) { return (0); /* already open */ } dsp = kmem_zalloc(sizeof (*dsp), KM_SLEEP); dsp->dr_major = getmajor(*devp); mutex_init(&dsp->dr_lock, NULL, MUTEX_DEFAULT, NULL); q->q_ptr = OTHERQ(q)->q_ptr = dsp; qprocson(q); ddi_assoc_queue_with_devi(q, NULL); return (0); }
/* * Return the equivalent queue from the other side of the relationship. * e.g.: given the slave's write queue, return the master's write queue. */ static queue_t * zc_switch(queue_t *qp) { zc_state_t *zcs = qp->q_ptr; ASSERT(zcs != NULL); if (qp == zcs->zc_master_rdq) return (zcs->zc_slave_rdq); else if (OTHERQ(qp) == zcs->zc_master_rdq && zcs->zc_slave_rdq != NULL) return (OTHERQ(zcs->zc_slave_rdq)); else if (qp == zcs->zc_slave_rdq) return (zcs->zc_master_rdq); else if (OTHERQ(qp) == zcs->zc_slave_rdq && zcs->zc_master_rdq != NULL) return (OTHERQ(zcs->zc_master_rdq)); else return (NULL); }
static streamscall int spx_close(queue_t *q, int oflag, cred_t *crp) { struct spx *p; if ((p = q->q_ptr) == NULL) return (0); /* already closed */ qprocsoff(q); spin_lock(&spx_lock); if ((*(p->prev) = p->next)) p->next->prev = p->prev; p->next = NULL; p->prev = &p->next; p->init = 0; p->q = NULL; q->q_ptr = OTHERQ(q)->q_ptr = NULL; spin_unlock(&spx_lock); /* FIXME: we need to do more than this... If we are welded to another stream head we need to initiate a close on that stream head as well or at least unweld things. */ return (0); }
/* This does not work like the real version but is easy to test the result of. */ void qreply(queue_t *pQueue, mblk_t *pMBlk) { OTHERQ(pQueue)->q_first = pMBlk; }
/* * ------------------------------------------------------------------------- * * OPEN and CLOSE * * ------------------------------------------------------------------------- */ static streamscall int spx_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp) { struct spx *p, **pp = &spx_list; major_t cmajor = getmajor(*devp); minor_t cminor = getminor(*devp); if (q->q_ptr != NULL) return (0); /* already open */ if (sflag == MODOPEN || WR(q)->q_next) return (ENXIO); /* can't open as module */ if (!(p = kmem_alloc(sizeof(*p), KM_NOSLEEP))) /* we could sleep */ return (ENOMEM); /* no memory */ bzero(p, sizeof(*p)); switch (sflag) { case CLONEOPEN: if (cminor < 1) cminor = 1; case DRVOPEN: { major_t dmajor = cmajor; if (cminor < 1) return (ENXIO); spin_lock(&spx_lock); for (; *pp && (dmajor = getmajor((*pp)->dev)) < cmajor; pp = &(*pp)->next) ; for (; *pp && dmajor == getmajor((*pp)->dev) && getminor(makedevice(cmajor, cminor)) != 0; pp = &(*pp)->next) { minor_t dminor = getminor((*pp)->dev); if (cminor < dminor) break; if (cminor == dminor) { if (sflag == CLONEOPEN) cminor++; else { spin_unlock(&spx_lock); kmem_free(p, sizeof(*p)); return (EIO); /* bad error */ } } } if (getminor(makedevice(cmajor, cminor)) == 0) { spin_unlock(&spx_lock); kmem_free(p, sizeof(*p)); return (EBUSY); /* no minors left */ } p->dev = *devp = makedevice(cmajor, cminor); p->init = 0; p->q = q; if ((p->next = *pp)) p->next->prev = &p->next; p->prev = pp; *pp = p; q->q_ptr = OTHERQ(q)->q_ptr = p; spin_unlock(&spx_lock); qprocson(q); return (0); } } return (ENXIO); }