diff options
author | Lawrence Stewart <lstewart@FreeBSD.org> | 2017-08-17 07:20:09 +0000 |
---|---|---|
committer | Lawrence Stewart <lstewart@FreeBSD.org> | 2017-08-17 07:20:09 +0000 |
commit | a8ec96af28bf1e84f88039e68ff89c82e600f96b (patch) | |
tree | ce576138e0a1aab297378eedbecd86059e3b384b /sys/kern/subr_sbuf.c | |
parent | 1e781c6f96614a362924113f91d28bd32dc60c7e (diff) | |
download | src-a8ec96af28bf1e84f88039e68ff89c82e600f96b.tar.gz src-a8ec96af28bf1e84f88039e68ff89c82e600f96b.zip |
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
Notes
Notes:
svn path=/head/; revision=322614
Diffstat (limited to 'sys/kern/subr_sbuf.c')
-rw-r--r-- | sys/kern/subr_sbuf.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index d7465f9dd758..80c95dc917d2 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -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_t pad, int c) } 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; |