svn commit: r222580 - in stable/7: share/man/man9 sys/dev/cxgb
sys/kern sys/sys
Matthew D Fleming
mdf at FreeBSD.org
Wed Jun 1 18:27:13 UTC 2011
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 <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/sbuf.h>
#include <sys/sx.h>
#include <sys/sysproto.h>
#include <sys/uio.h>
@@ -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 <sys/cdefs.h>
More information about the svn-src-stable-7
mailing list