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
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to