From owner-svn-src-all@FreeBSD.ORG Wed Jun 1 18:27:13 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 943CC1065676; Wed, 1 Jun 2011 18:27:13 +0000 (UTC) (envelope-from mdf@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 81AE58FC12; Wed, 1 Jun 2011 18:27:13 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p51IRDsM081856; Wed, 1 Jun 2011 18:27:13 GMT (envelope-from mdf@svn.freebsd.org) Received: (from mdf@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p51IRDbG081849; Wed, 1 Jun 2011 18:27:13 GMT (envelope-from mdf@svn.freebsd.org) Message-Id: <201106011827.p51IRDbG081849@svn.freebsd.org> From: Matthew D Fleming Date: Wed, 1 Jun 2011 18:27:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r222580 - in stable/7: share/man/man9 sys/dev/cxgb sys/kern sys/sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Jun 2011 18:27:13 -0000 Author: mdf Date: Wed Jun 1 18:27:13 2011 New Revision: 222580 URL: http://svn.freebsd.org/changeset/base/222580 Log: Partial MFC of r212370. np@ requested this functionality so I kept in the cxgb change, but otherwise MFC'd only the new function sbuf_new_for_sysctl(9) and none of the changed code. MFC r217830: Document sbuf_new_for_sysctl(9). Partial MFC of r217916: Explicitly wire the user buffer rather than doing it implicitly in sbuf_new_for_sysctl(9). This allows using an sbuf with a SYSCTL_OUT drain for extremely large amounts of data where the caller knows that appropriate references are held, and sleeping is not an issue. Modified: stable/7/share/man/man9/Makefile stable/7/share/man/man9/sbuf.9 stable/7/sys/dev/cxgb/cxgb_sge.c stable/7/sys/kern/kern_sysctl.c stable/7/sys/kern/subr_sbuf.c stable/7/sys/sys/sysctl.h Directory Properties: stable/7/share/man/man9/ (props changed) stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/share/man/man9/Makefile ============================================================================== --- stable/7/share/man/man9/Makefile Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/share/man/man9/Makefile Wed Jun 1 18:27:13 2011 (r222580) @@ -962,6 +962,7 @@ MLINKS+=sbuf.9 sbuf_bcat.9 \ sbuf.9 sbuf_finish.9 \ sbuf.9 sbuf_len.9 \ sbuf.9 sbuf_new.9 \ + sbuf.9 sbuf_new_for_sysctl.9 \ sbuf.9 sbuf_overflowed.9 \ sbuf.9 sbuf_printf.9 \ sbuf.9 sbuf_putc.9 \ Modified: stable/7/share/man/man9/sbuf.9 ============================================================================== --- stable/7/share/man/man9/sbuf.9 Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/share/man/man9/sbuf.9 Wed Jun 1 18:27:13 2011 (r222580) @@ -25,13 +25,14 @@ .\" .\" $FreeBSD$ .\" -.Dd May 17, 2009 +.Dd January 25, 2011 .Dt SBUF 9 .Os .Sh NAME .Nm sbuf , .Nm sbuf_new , .Nm sbuf_new_auto , +.Nm sbuf_new_for_sysctl , .Nm sbuf_clear , .Nm sbuf_setpos , .Nm sbuf_bcat , @@ -99,6 +100,9 @@ .Fn sbuf_done "struct sbuf *s" .Ft void .Fn sbuf_delete "struct sbuf *s" +.In sys/sysctl.h +.Ft struct sbuf * +.Fn sbuf_new_for_sysctl "struct sbuf *s" "char *buf" "int length" "struct sysctl_req *req" .Sh DESCRIPTION The .Nm @@ -169,6 +173,15 @@ and .Dv SBUF_AUTOEXTEND . .Pp The +.Fn sbuf_new_for_sysctl +function will set up an sbuf with a drain function to use +.Fn SYSCTL_OUT +when the internal buffer fills. +Note that if the various functions which append to an sbuf are used while +a non-sleepable lock is held, the user buffer should be wired using +.Fn sysctl_wire_old_buffer . +.Pp +The .Fn sbuf_delete function clears the .Fa sbuf Modified: stable/7/sys/dev/cxgb/cxgb_sge.c ============================================================================== --- stable/7/sys/dev/cxgb/cxgb_sge.c Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/sys/dev/cxgb/cxgb_sge.c Wed Jun 1 18:27:13 2011 (r222580) @@ -3070,7 +3070,6 @@ t3_dump_rspq(SYSCTL_HANDLER_ARGS) struct sge_rspq *rspq; struct sge_qset *qs; int i, err, dump_end, idx; - static int multiplier = 1; struct sbuf *sb; struct rsp_desc *rspd; uint32_t data[4]; @@ -3095,8 +3094,10 @@ t3_dump_rspq(SYSCTL_HANDLER_ARGS) err = t3_sge_read_rspq(qs->port->adapter, rspq->cntxt_id, data); if (err) return (err); -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + err = sysctl_wire_old_buffer(req, 0); + if (err) + return (err); + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " \n index=%u size=%u MSI-X/RspQ=%u intr enable=%u intr armed=%u\n", (data[0] & 0xffff), data[0] >> 16, ((data[2] >> 20) & 0x3f), @@ -3119,13 +3120,11 @@ retry_sbufops: rspd->rss_hdr.rss_hash_val, be32toh(rspd->flags), be32toh(rspd->len_cq), rspd->intr_gen); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } @@ -3136,7 +3135,6 @@ t3_dump_txq_eth(SYSCTL_HANDLER_ARGS) struct sge_txq *txq; struct sge_qset *qs; int i, j, err, dump_end; - static int multiplier = 1; struct sbuf *sb; struct tx_desc *txd; uint32_t *WR, wr_hi, wr_lo, gen; @@ -3163,10 +3161,10 @@ t3_dump_txq_eth(SYSCTL_HANDLER_ARGS) err = t3_sge_read_ecntxt(qs->port->adapter, qs->rspq.cntxt_id, data); if (err) return (err); - - -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + err = sysctl_wire_old_buffer(req, 0); + if (err) + return (err); + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " \n credits=%u GTS=%u index=%u size=%u rspq#=%u cmdq#=%u\n", (data[0] & 0x7fff), ((data[0] >> 15) & 1), (data[0] >> 16), @@ -3193,13 +3191,10 @@ retry_sbufops: WR[j], WR[j + 1], WR[j + 2], WR[j + 3]); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } @@ -3210,7 +3205,6 @@ t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS) struct sge_txq *txq; struct sge_qset *qs; int i, j, err, dump_end; - static int multiplier = 1; struct sbuf *sb; struct tx_desc *txd; uint32_t *WR, wr_hi, wr_lo, gen; @@ -3234,8 +3228,10 @@ t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS) return (EINVAL); } -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + err = sysctl_wire_old_buffer(req, 0); + if (err != 0) + return (err); + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " qid=%d start=%d -> end=%d\n", qs->idx, txq->txq_dump_start, (txq->txq_dump_start + txq->txq_dump_count) & 255); @@ -3255,13 +3251,10 @@ retry_sbufops: WR[j], WR[j + 1], WR[j + 2], WR[j + 3]); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } Modified: stable/7/sys/kern/kern_sysctl.c ============================================================================== --- stable/7/sys/kern/kern_sysctl.c Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/sys/kern/kern_sysctl.c Wed Jun 1 18:27:13 2011 (r222580) @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1585,3 +1586,28 @@ userland_sysctl(struct thread *td, int * } return (error); } + +/* + * Drain into a sysctl struct. The user buffer should be wired if a page + * fault would cause issue. + */ +static int +sbuf_sysctl_drain(void *arg, const char *data, int len) +{ + struct sysctl_req *req = arg; + int error; + + error = SYSCTL_OUT(req, data, len); + KASSERT(error >= 0, ("Got unexpected negative value %d", error)); + return (error == 0 ? len : -error); +} + +struct sbuf * +sbuf_new_for_sysctl(struct sbuf *s, char *buf, int length, + struct sysctl_req *req) +{ + + s = sbuf_new(s, buf, length, SBUF_FIXEDLEN); + sbuf_set_drain(s, sbuf_sysctl_drain, req); + return (s); +} Modified: stable/7/sys/kern/subr_sbuf.c ============================================================================== --- stable/7/sys/kern/subr_sbuf.c Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/sys/kern/subr_sbuf.c Wed Jun 1 18:27:13 2011 (r222580) @@ -324,8 +324,8 @@ sbuf_drain(struct sbuf *s) SBUF_SETFLAG(s, SBUF_OVERFLOWED); return (s->s_drain->s_error); } - - KASSERT(len > 0, ("Drain must either error or work!")); + KASSERT(len > 0 && len <= s->s_len, + ("Bad drain amount %d for sbuf %p", len, s)); s->s_len -= len; /* * Fast path for the expected case where all the data was Modified: stable/7/sys/sys/sysctl.h ============================================================================== --- stable/7/sys/sys/sysctl.h Wed Jun 1 18:26:59 2011 (r222579) +++ stable/7/sys/sys/sysctl.h Wed Jun 1 18:27:13 2011 (r222580) @@ -703,6 +703,9 @@ void sysctl_lock(void); void sysctl_unlock(void); int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len); +struct sbuf; +struct sbuf *sbuf_new_for_sysctl(struct sbuf *, char *, int, + struct sysctl_req *); #else /* !_KERNEL */ #include