Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 Aug 2017 07:20:09 +0000 (UTC)
From:      Lawrence Stewart <lstewart@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r322614 - in head: share/man/man9 sys/kern sys/sys
Message-ID:  <201708170720.v7H7K9BO085131@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: lstewart
Date: Thu Aug 17 07:20:09 2017
New Revision: 322614
URL: https://svnweb.freebsd.org/changeset/base/322614

Log:
  Implement simple record boundary tracking in sbuf(9) to avoid record splitting
  during drain operations. When an sbuf is configured to use this feature by way
  of the SBUF_DRAINTOEOR sbuf_new() flag, top-level sections started with
  sbuf_start_section() create a record boundary marker that is used to avoid
  flushing partial records.
  
  Reviewed by:	cem,imp,wblock
  MFC after:	2 weeks
  Sponsored by:	Netflix, Inc.
  Differential Revision:	https://reviews.freebsd.org/D8536

Modified:
  head/share/man/man9/sbuf.9
  head/sys/kern/subr_sbuf.c
  head/sys/sys/sbuf.h

Modified: head/share/man/man9/sbuf.9
==============================================================================
--- head/share/man/man9/sbuf.9	Thu Aug 17 06:36:21 2017	(r322613)
+++ head/share/man/man9/sbuf.9	Thu Aug 17 07:20:09 2017	(r322614)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 5, 2017
+.Dd August 17, 2017
 .Dt SBUF 9
 .Os
 .Sh NAME
@@ -271,6 +271,14 @@ This indicates that the storage buffer may be extended
 as resources allow, to hold additional data.
 .It Dv SBUF_INCLUDENUL
 This causes the final nulterm byte to be counted in the length of the data.
+.It Dv SBUF_DRAINTOEOR
+Treat top-level sections started with
+.Fn sbuf_start_section
+as a record boundary marker that will be used during drain operations to avoid
+records being split.
+If a record grows sufficiently large such that it fills the
+.Fa sbuf
+and therefore cannot be drained without being split, an error of EDEADLK is set.
 .El
 .Pp
 Note that if

Modified: head/sys/kern/subr_sbuf.c
==============================================================================
--- head/sys/kern/subr_sbuf.c	Thu Aug 17 06:36:21 2017	(r322613)
+++ head/sys/kern/subr_sbuf.c	Thu Aug 17 07:20:09 2017	(r322614)
@@ -73,6 +73,8 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers")
 #define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
 #define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
 #define	SBUF_NULINCLUDED(s)	((s)->s_flags & SBUF_INCLUDENUL)
+#define	SBUF_ISDRAINTOEOR(s)	((s)->s_flags & SBUF_DRAINTOEOR)
+#define	SBUF_DODRAINTOEOR(s)	(SBUF_ISSECTION(s) && SBUF_ISDRAINTOEOR(s))
 
 /*
  * Set / clear flags
@@ -308,6 +310,7 @@ sbuf_clear(struct sbuf *s)
 	SBUF_CLEARFLAG(s, SBUF_FINISHED);
 	s->s_error = 0;
 	s->s_len = 0;
+	s->s_rec_off = 0;
 	s->s_sect_len = 0;
 }
 
@@ -362,7 +365,10 @@ sbuf_drain(struct sbuf *s)
 
 	KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s));
 	KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s));
-	len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
+	if (SBUF_DODRAINTOEOR(s) && s->s_rec_off == 0)
+		return (s->s_error = EDEADLK);
+	len = s->s_drain_func(s->s_drain_arg, s->s_buf,
+	    SBUF_DODRAINTOEOR(s) ? s->s_rec_off : s->s_len);
 	if (len < 0) {
 		s->s_error = -len;
 		return (s->s_error);
@@ -370,6 +376,7 @@ sbuf_drain(struct sbuf *s)
 	KASSERT(len > 0 && len <= s->s_len,
 	    ("Bad drain amount %d for sbuf %p", len, s));
 	s->s_len -= len;
+	s->s_rec_off -= len;
 	/*
 	 * Fast path for the expected case where all the data was
 	 * drained.
@@ -835,6 +842,7 @@ sbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
 		    ("s_sect_len != 0 when starting a section"));
 		if (old_lenp != NULL)
 			*old_lenp = -1;
+		s->s_rec_off = s->s_len;
 		SBUF_SETFLAG(s, SBUF_INSECTION);
 	} else {
 		KASSERT(old_lenp != NULL,
@@ -865,7 +873,7 @@ sbuf_end_section(struct sbuf *s, ssize_t old_len, size
 	}
 	len = s->s_sect_len;
 	if (old_len == -1) {
-		s->s_sect_len = 0;
+		s->s_rec_off = s->s_sect_len = 0;
 		SBUF_CLEARFLAG(s, SBUF_INSECTION);
 	} else {
 		s->s_sect_len += old_len;

Modified: head/sys/sys/sbuf.h
==============================================================================
--- head/sys/sys/sbuf.h	Thu Aug 17 06:36:21 2017	(r322613)
+++ head/sys/sys/sbuf.h	Thu Aug 17 07:20:09 2017	(r322614)
@@ -49,6 +49,7 @@ struct sbuf {
 #define	SBUF_FIXEDLEN	0x00000000	/* fixed length buffer (default) */
 #define	SBUF_AUTOEXTEND	0x00000001	/* automatically extend buffer */
 #define	SBUF_INCLUDENUL	0x00000002	/* nulterm byte is counted in len */
+#define	SBUF_DRAINTOEOR	0x00000004	/* use section 0 as drain EOR marker */
 #define	SBUF_USRFLAGMSK	0x0000ffff	/* mask of flags the user may specify */
 #define	SBUF_DYNAMIC	0x00010000	/* s_buf must be freed */
 #define	SBUF_FINISHED	0x00020000	/* set by sbuf_finish() */
@@ -56,6 +57,7 @@ struct sbuf {
 #define	SBUF_INSECTION	0x00100000	/* set by sbuf_start_section() */
 	int		 s_flags;	/* flags */
 	ssize_t		 s_sect_len;	/* current length of section */
+	ssize_t		 s_rec_off;	/* current record start offset */
 };
 
 #ifndef HD_COLUMN_MASK



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