diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-05-13 15:36:23 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-05-13 15:36:23 +0000 |
commit | d86e634c7d069328b01108134d1ed4e19ac07d45 (patch) | |
tree | dfdbc749b02dcfc11394391f6c280f9d74002b3f | |
parent | ed442b31cc98da8ad26416675e5d6df1cda086ac (diff) | |
download | illumos-joyent-d86e634c7d069328b01108134d1ed4e19ac07d45.tar.gz |
OS-5375 docker exec/attach/logs truncating output to 4096 bytes
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
-rw-r--r-- | usr/src/uts/common/io/zfd.c | 125 |
1 files changed, 47 insertions, 78 deletions
diff --git a/usr/src/uts/common/io/zfd.c b/usr/src/uts/common/io/zfd.c index 8dc6e6cfb2..2da310ab8d 100644 --- a/usr/src/uts/common/io/zfd.c +++ b/usr/src/uts/common/io/zfd.c @@ -11,7 +11,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Copyright 2015 Joyent, Inc. All rights reserved. + * Copyright 2016 Joyent, Inc. All rights reserved. */ /* @@ -737,11 +737,17 @@ handle_mflush(queue_t *qp, mblk_t *mp) /* * Evaluate the various conditionals to determine if we're teeing into a log - * stream, if that should be flow controlled, and if we can perform the tee. - * This function can set the zfd_is_flowcon flag as a side effect. + * stream and if the primary stream should be flow controlled. This function + * can set the zfd_is_flowcon flag as a side effect. + * + * When teeing with flow control, we always queue the teed msg here and if + * the queue is getting full, we set zfd_is_flowcon. The primary stream will + * always queue when zfd_is_flowcon and will also not be served when + * zfd_is_flowcon is set. This causes backpressure on the primary stream + * until the teed queue can drain. */ static void -zfd_tee_handler(queue_t *qp, zfd_state_t *zfds, unsigned char type, mblk_t *mp) +zfd_tee_handler(zfd_state_t *zfds, unsigned char type, mblk_t *mp) { queue_t *log_qp; zfd_state_t *log_zfds; @@ -769,35 +775,24 @@ zfd_tee_handler(queue_t *qp, zfd_state_t *zfds, unsigned char type, mblk_t *mp) log_qp = RD(log_zfds->zfd_slave_rdq); DTRACE_PROBE2(zfd__tee__check, void *, log_qp, void *, zfds); - if (zfds->zfd_allow_flowcon) { - /* - * If we're supposed to tee with flow control and the tee is - * over the high water mark then we want the primary stream to - * stop flowing. We'll resume teeing out of the read side of - * the primary stream when the log stream has drained. - */ - if (log_qp->q_count > log_qp->q_hiwat) { - zfds->zfd_is_flowcon = B_TRUE; - log_qp = NULL; - } - } else { + if (!zfds->zfd_allow_flowcon) { /* * We're not supposed to tee with flow control and the tee is * full so we skip teeing into the log stream. */ if ((log_qp->q_flag & QFULL) != 0) - log_qp = NULL; + return; } - if (log_qp == NULL) - return; - /* * Tee the message into the log stream. */ lmp = dupmsg(mp); - if (lmp == NULL) + if (lmp == NULL) { + if (zfds->zfd_allow_flowcon) + zfds->zfd_is_flowcon = B_TRUE; return; + } if (log_qp->q_first == NULL && bcanputnext(log_qp, lmp->b_band)) { putnext(log_qp, lmp); @@ -806,6 +801,16 @@ zfd_tee_handler(queue_t *qp, zfd_state_t *zfds, unsigned char type, mblk_t *mp) /* The logger queue is full, free the msg. */ freemsg(lmp); } + /* + * If we're supposed to tee with flow control and the tee is + * over the high water mark then we want the primary stream to + * stop flowing. We'll stop queueing the primary stream after + * the log stream has drained. + */ + if (zfds->zfd_allow_flowcon && + log_qp->q_count > log_qp->q_hiwat) { + zfds->zfd_is_flowcon = B_TRUE; + } } } @@ -959,12 +964,12 @@ zfd_wput(queue_t *qp, mblk_t *mp) /* if on the write side, may need to tee */ if (zfds->zfd_slave_rdq != NULL && qp == WR(zfds->zfd_slave_rdq)) { /* tee output to any attached log stream */ - zfd_tee_handler(qp, zfds, type, mp); - } + zfd_tee_handler(zfds, type, mp); - /* high-priority msgs are not subject to flow control */ - if (zfds->zfd_is_flowcon && type == M_DATA) - must_queue = B_TRUE; + /* high-priority msgs are not subject to flow control */ + if (zfds->zfd_is_flowcon && type == M_DATA) + must_queue = B_TRUE; + } if (zfd_switch(RD(qp)) == NULL) { DBG1("wput to %s side (no one listening)", zfd_side(qp)); @@ -1008,14 +1013,18 @@ zfd_wput(queue_t *qp, mblk_t *mp) * If the primary stream has been stopped for flow control then * enqueue the msg, otherwise only putnext if there isn't already * something in the queue. If we don't do this then things would wind - * up out of order. We may tee into the mux here based on the - * conditionals evaluated above. + * up out of order. */ if (!must_queue && qp->q_first == NULL && bcanputnext(RD(zfd_switch(qp)), mp->b_band)) { putnext(RD(zfd_switch(qp)), mp); } else { - (void) putq(RD(zfd_switch(qp)), mp); + /* + * zfd_wsrv expects msgs queued on the primary queue. Those + * will be handled by zfd_wsrv after zfd_rsrv performs the + * qenable on the proper queue. + */ + (void) putq(qp, mp); } DBG1("done wput, %s side", zfd_side(qp)); @@ -1030,10 +1039,6 @@ zfd_wput(queue_t *qp, mblk_t *mp) * enabling the write side of the partner. This triggers the partner to send * messages queued on its write side to this queue's read side. * - * However, once we've flow controlled the write side, messages will be enqueued - * in the read queue (see zfd_wput). Once flow control is turned off on the - * write side, we need to drain these queued messages out to the reader. - * * For log stream: * Internally we've queued up the msgs that we've teed off to the log stream * so when we're invoked we need to pass these along. @@ -1082,44 +1087,6 @@ zfd_rsrv(queue_t *qp) } /* - * If the master read side has data queued up due to flow control we - * try to drain that out now. This is subtly different from the code in - * zfd_wsrv since we're not switching sides for the zfd queues, instead - * we're just passing data out of this driver - */ - if (zfds->zfd_muxt == ZFD_PRIMARY_STREAM && - qp == zfds->zfd_master_rdq && - qp->q_count > 0) { - /* serve the reader */ - mblk_t *mp; - - while ((mp = getq(qp)) != NULL) { - unsigned char type = mp->b_datap->db_type; - boolean_t must_queue; - - /* high-priority msgs are not subject to flow control */ - if (zfds->zfd_is_flowcon && type == M_DATA) { - must_queue = B_TRUE; - } else { - must_queue = B_FALSE; - } - - /* - * Note that we're not switching sides here! - */ - if (!must_queue && bcanputnext(qp, mp->b_band)) { - putnext(qp, mp); - - /* tee output to any attached log stream */ - zfd_tee_handler(qp, zfds, type, mp); - } else { - (void) putbq(qp, mp); - break; - } - } - } - - /* * Care must be taken here, as either of the master or slave side * qptr could be NULL. */ @@ -1144,9 +1111,11 @@ zfd_rsrv(queue_t *qp) static void zfd_wsrv(queue_t *qp) { + queue_t *swq; mblk_t *mp; + zfd_state_t *zfds = (zfd_state_t *)qp->q_ptr; - DBG1("zfd_wsrv master (%s) side", zfd_side(qp)); + ASSERT(zfds != NULL); /* * Partner has no read queue, so take the data, and throw it away. @@ -1163,21 +1132,21 @@ zfd_wsrv(queue_t *qp) return; } + swq = RD(zfd_switch(qp)); + /* * while there are messages on this write queue... */ - while ((mp = getq(qp)) != NULL) { + while (!zfds->zfd_is_flowcon && (mp = getq(qp)) != NULL) { /* * Due to the way zfd_wput is implemented, we should never - * see a control message here. + * see a high priority control message here. */ ASSERT(mp->b_datap->db_type < QPCTL); - if (bcanputnext(RD(zfd_switch(qp)), mp->b_band)) { - DBG("wsrv: send message to other side\n"); - putnext(RD(zfd_switch(qp)), mp); + if (bcanputnext(swq, mp->b_band)) { + putnext(swq, mp); } else { - DBG("wsrv: putting msg back on queue\n"); (void) putbq(qp, mp); break; } |