Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Jun 2011 18:27:13 +0000 (UTC)
From:      Matthew D Fleming <mdf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r222580 - in stable/7: share/man/man9 sys/dev/cxgb sys/kern sys/sys
Message-ID:  <201106011827.p51IRDbG081849@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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>
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106011827.p51IRDbG081849>