/* * wput(9E) is symmetric for master and slave sides, so this handles both * without splitting the codepath. * * zc_wput() looks at the other side; if there is no process holding that * side open, it frees the message. This prevents processes from hanging * if no one is holding open the console. Otherwise, it putnext's high * priority messages, putnext's normal messages if possible, and otherwise * enqueues the messages; in the case that something is enqueued, wsrv(9E) * will take care of eventually shuttling I/O to the other side. */ static void zc_wput(queue_t *qp, mblk_t *mp) { unsigned char type = mp->b_datap->db_type; ASSERT(qp->q_ptr); DBG1("entering zc_wput, %s side", zc_side(qp)); if (zc_switch(RD(qp)) == NULL) { DBG1("wput to %s side (no one listening)", zc_side(qp)); switch (type) { case M_FLUSH: handle_mflush(qp, mp); break; case M_IOCTL: miocnak(qp, mp, 0, 0); break; default: freemsg(mp); break; } return; } if (type >= QPCTL) { DBG1("(hipri) wput, %s side", zc_side(qp)); switch (type) { case M_READ: /* supposedly from ldterm? */ DBG("zc_wput: tossing M_READ\n"); freemsg(mp); break; case M_FLUSH: handle_mflush(qp, mp); break; default: /* * Put this to the other side. */ ASSERT(zc_switch(RD(qp)) != NULL); putnext(zc_switch(RD(qp)), mp); break; } DBG1("done (hipri) wput, %s side", zc_side(qp)); return; } /* * Only putnext if there isn't already something in the queue. * otherwise things would wind up out of order. */ if (qp->q_first == NULL && bcanputnext(RD(zc_switch(qp)), mp->b_band)) { DBG("wput: putting message to other side\n"); putnext(RD(zc_switch(qp)), mp); } else { DBG("wput: putting msg onto queue\n"); (void) putq(qp, mp); } DBG1("done wput, %s side", zc_side(qp)); }
/* * wput(9E) is symmetric for master and slave sides, so this handles both * without splitting the codepath. (The only exception to this is the * processing of zcons ioctls, which is restricted to the master side.) * * zc_wput() looks at the other side; if there is no process holding that * side open, it frees the message. This prevents processes from hanging * if no one is holding open the console. Otherwise, it putnext's high * priority messages, putnext's normal messages if possible, and otherwise * enqueues the messages; in the case that something is enqueued, wsrv(9E) * will take care of eventually shuttling I/O to the other side. */ static void zc_wput(queue_t *qp, mblk_t *mp) { unsigned char type = mp->b_datap->db_type; zc_state_t *zcs; struct iocblk *iocbp; file_t *slave_filep; struct snode *slave_snodep; int slave_fd; ASSERT(qp->q_ptr); DBG1("entering zc_wput, %s side", zc_side(qp)); /* * Process zcons ioctl messages if qp is the master console's write * queue. */ zcs = (zc_state_t *)qp->q_ptr; if (zcs->zc_master_rdq != NULL && qp == WR(zcs->zc_master_rdq) && type == M_IOCTL) { iocbp = (struct iocblk *)(void *)mp->b_rptr; switch (iocbp->ioc_cmd) { case ZC_HOLDSLAVE: /* * Hold the slave's vnode and increment the refcount * of the snode. If the vnode is already held, then * indicate success. */ if (iocbp->ioc_count != TRANSPARENT) { miocack(qp, mp, 0, EINVAL); return; } if (zcs->zc_slave_vnode != NULL) { miocack(qp, mp, 0, 0); return; } /* * The process that passed the ioctl must be running in * the global zone. */ if (curzone != global_zone) { miocack(qp, mp, 0, EINVAL); return; } /* * The calling process must pass a file descriptor for * the slave device. */ slave_fd = (int)(intptr_t)*(caddr_t *)(void *)mp->b_cont-> b_rptr; slave_filep = getf(slave_fd); if (slave_filep == NULL) { miocack(qp, mp, 0, EINVAL); return; } if (ZC_STATE_TO_SLAVEDEV(zcs) != slave_filep->f_vnode->v_rdev) { releasef(slave_fd); miocack(qp, mp, 0, EINVAL); return; } /* * Get a reference to the slave's vnode. Also bump the * reference count on the associated snode. */ ASSERT(vn_matchops(slave_filep->f_vnode, spec_getvnodeops())); zcs->zc_slave_vnode = slave_filep->f_vnode; VN_HOLD(zcs->zc_slave_vnode); slave_snodep = VTOCS(zcs->zc_slave_vnode); mutex_enter(&slave_snodep->s_lock); ++slave_snodep->s_count; mutex_exit(&slave_snodep->s_lock); releasef(slave_fd); miocack(qp, mp, 0, 0); return; case ZC_RELEASESLAVE: /* * Release the master's handle on the slave's vnode. * If there isn't a handle for the vnode, then indicate * success. */ if (iocbp->ioc_count != TRANSPARENT) { miocack(qp, mp, 0, EINVAL); return; } if (zcs->zc_slave_vnode == NULL) { miocack(qp, mp, 0, 0); return; } /* * The process that passed the ioctl must be running in * the global zone. */ if (curzone != global_zone) { miocack(qp, mp, 0, EINVAL); return; } /* * The process that passed the ioctl must have provided * a file descriptor for the slave device. Make sure * this is correct. */ slave_fd = (int)(intptr_t)*(caddr_t *)(void *)mp->b_cont-> b_rptr; slave_filep = getf(slave_fd); if (slave_filep == NULL) { miocack(qp, mp, 0, EINVAL); return; } if (zcs->zc_slave_vnode->v_rdev != slave_filep->f_vnode->v_rdev) { releasef(slave_fd); miocack(qp, mp, 0, EINVAL); return; } /* * Decrement the snode's reference count and release the * vnode. */ ASSERT(vn_matchops(slave_filep->f_vnode, spec_getvnodeops())); slave_snodep = VTOCS(zcs->zc_slave_vnode); mutex_enter(&slave_snodep->s_lock); --slave_snodep->s_count; mutex_exit(&slave_snodep->s_lock); VN_RELE(zcs->zc_slave_vnode); zcs->zc_slave_vnode = NULL; releasef(slave_fd); miocack(qp, mp, 0, 0); return; default: break; } } if (zc_switch(RD(qp)) == NULL) { DBG1("wput to %s side (no one listening)", zc_side(qp)); switch (type) { case M_FLUSH: handle_mflush(qp, mp); break; case M_IOCTL: miocnak(qp, mp, 0, 0); break; default: freemsg(mp); break; } return; } if (type >= QPCTL) { DBG1("(hipri) wput, %s side", zc_side(qp)); switch (type) { case M_READ: /* supposedly from ldterm? */ DBG("zc_wput: tossing M_READ\n"); freemsg(mp); break; case M_FLUSH: handle_mflush(qp, mp); break; default: /* * Put this to the other side. */ ASSERT(zc_switch(RD(qp)) != NULL); putnext(zc_switch(RD(qp)), mp); break; } DBG1("done (hipri) wput, %s side", zc_side(qp)); return; } /* * Only putnext if there isn't already something in the queue. * otherwise things would wind up out of order. */ if (qp->q_first == NULL && bcanputnext(RD(zc_switch(qp)), mp->b_band)) { DBG("wput: putting message to other side\n"); putnext(RD(zc_switch(qp)), mp); } else { DBG("wput: putting msg onto queue\n"); (void) putq(qp, mp); } DBG1("done wput, %s side", zc_side(qp)); }