MAJOR: buffer: finalize buffer detachment

Now the buffers only contain the header and a pointer to the storage
area which can be anywhere. This will significantly simplify buffer
swapping and will make it possible to map chunks on buffers as well.

The buf_empty variable was removed, as now it's enough to have size==0
and area==NULL to designate the empty buffer (thus a non-allocated head
is the empty buffer by default). buf_wanted for now is indicated by
size==0 and area==(void *)1.

The channels and the checks now embed the buffer's head, and the only
pointer is to the storage area. This slightly increases the unallocated
buffer size (3 extra ints for the empty buffer) but considerably
simplifies dynamic buffer management. It will also later permit to
detach unused checks.

The way the struct buffer is arranged has proven quite efficient on a
number of tests, which makes sense given that size is always accessed
and often first, followed by the othe ones.
diff --git a/include/common/buf.h b/include/common/buf.h
index bd58a4d..92db0a1 100644
--- a/include/common/buf.h
+++ b/include/common/buf.h
@@ -32,12 +32,25 @@
 
 /* Structure defining a buffer's head */
 struct buffer {
-	size_t head;                /* start offset of remaining data relative to area */
-	size_t data;                /* amount of data after head including wrapping */
 	size_t size;                /* buffer size in bytes */
-	char   area[0];             /* <size> bytes of stored data */
+	char  *area;                /* points to <size> bytes */
+	size_t data;                /* amount of data after head including wrapping */
+	size_t head;                /* start offset of remaining data relative to area */
 };
 
+/* A buffer may be in 3 different states :
+ *   - unallocated : size == 0, area == 0  (b_is_null() is true)
+ *   - waiting     : size == 0, area != 0
+ *   - allocated   : size  > 0, area  > 0
+ */
+
+/* initializers for certain buffer states. It is important that the NULL buffer
+ * remains the one with all fields initialized to zero so that a calloc() or a
+ * memset() on a struct automatically sets a NULL buffer.
+ */
+#define BUF_NULL   ((struct buffer){ })
+#define BUF_WANTED ((struct buffer){ .area = (char *)1 })
+
 
 /***************************************************************************/
 /* Functions used to compute offsets and pointers. Most of them exist in   */
@@ -46,13 +59,21 @@
 /* offset relative to the storage area.                                    */
 /***************************************************************************/
 
+/* b_is_null() : returns true if (and only if) the buffer is not yet allocated
+ * and thus points to a NULL area.
+ */
+static inline int b_is_null(const struct buffer *buf)
+{
+	return buf->area == NULL;
+}
+
 /* b_orig() : returns the pointer to the origin of the storage, which is the
  * location of byte at offset zero. This is mostly used by functions which
  * handle the wrapping by themselves.
  */
 static inline char *b_orig(const struct buffer *b)
 {
-	return (char *)b->area;
+	return b->area;
 }
 
 /* b_size() : returns the size of the buffer. */
@@ -66,7 +87,7 @@
  */
 static inline char *b_wrap(const struct buffer *b)
 {
-	return (char *)b->area + b->size;
+	return b->area + b->size;
 }
 
 /* b_data() : returns the number of bytes present in the buffer. */
diff --git a/include/common/buffer.h b/include/common/buffer.h
index 1657275..ed9f90b 100644
--- a/include/common/buffer.h
+++ b/include/common/buffer.h
@@ -43,8 +43,6 @@
 };
 
 extern struct pool_head *pool_head_buffer;
-extern struct buffer buf_empty;
-extern struct buffer buf_wanted;
 extern struct list buffer_wq;
 __decl_hathreads(extern HA_SPINLOCK_T buffer_wq_lock);
 
@@ -59,7 +57,7 @@
 /* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
 static inline int buffer_almost_full(const struct buffer *buf)
 {
-	if (buf == &buf_empty)
+	if (b_is_null(buf))
 		return 0;
 
 	return b_almost_full(buf);
@@ -69,65 +67,64 @@
 /* Functions below are used for buffer allocation */
 /**************************************************/
 
-/* Allocates a buffer and replaces *buf with this buffer. If no memory is
- * available, &buf_wanted is used instead. No control is made to check if *buf
- * already pointed to another buffer. The allocated buffer is returned, or
- * NULL in case no memory is available.
+/* Allocates a buffer and assigns it to *buf. If no memory is available,
+ * ((char *)1) is assigned instead with a zero size. No control is made to
+ * check if *buf already pointed to another buffer. The allocated buffer is
+ * returned, or NULL in case no memory is available.
  */
-static inline struct buffer *b_alloc(struct buffer **buf)
+static inline struct buffer *b_alloc(struct buffer *buf)
 {
-	struct buffer *b;
+	char *area;
 
-	*buf = &buf_wanted;
-	b = pool_alloc_dirty(pool_head_buffer);
-	if (likely(b)) {
-		b->size = pool_head_buffer->size - sizeof(struct buffer);
-		b_reset(b);
-		*buf = b;
-	}
-	return b;
+	*buf = BUF_WANTED;
+	area = pool_alloc_dirty(pool_head_buffer);
+	if (unlikely(!area))
+		return NULL;
+
+	buf->area = area;
+	buf->size = pool_head_buffer->size;
+	return buf;
 }
 
-/* Allocates a buffer and replaces *buf with this buffer. If no memory is
- * available, &buf_wanted is used instead. No control is made to check if *buf
- * already pointed to another buffer. The allocated buffer is returned, or
- * NULL in case no memory is available. The difference with b_alloc() is that
- * this function only picks from the pool and never calls malloc(), so it can
- * fail even if some memory is available.
+/* Allocates a buffer and assigns it to *buf. If no memory is available,
+ * ((char *)1) is assigned instead with a zero size. No control is made to
+ * check if *buf already pointed to another buffer. The allocated buffer is
+ * returned, or NULL in case no memory is available. The difference with
+ * b_alloc() is that this function only picks from the pool and never calls
+ * malloc(), so it can fail even if some memory is available.
  */
-static inline struct buffer *b_alloc_fast(struct buffer **buf)
+static inline struct buffer *b_alloc_fast(struct buffer *buf)
 {
-	struct buffer *b;
+	char *area;
 
-	*buf = &buf_wanted;
-	b = pool_get_first(pool_head_buffer);
-	if (likely(b)) {
-		b->size = pool_head_buffer->size - sizeof(struct buffer);
-		b_reset(b);
-		*buf = b;
-	}
-	return b;
+	*buf = BUF_WANTED;
+	area = pool_get_first(pool_head_buffer);
+	if (unlikely(!area))
+		return NULL;
+
+	buf->area = area;
+	buf->size = pool_head_buffer->size;
+	return buf;
 }
 
-/* Releases buffer *buf (no check of emptiness) */
-static inline void __b_drop(struct buffer **buf)
+/* Releases buffer <buf> (no check of emptiness) */
+static inline void __b_drop(struct buffer *buf)
 {
-	pool_free(pool_head_buffer, *buf);
+	pool_free(pool_head_buffer, buf->area);
 }
 
-/* Releases buffer *buf if allocated. */
-static inline void b_drop(struct buffer **buf)
+/* Releases buffer <buf> if allocated. */
+static inline void b_drop(struct buffer *buf)
 {
-	if (!(*buf)->size)
-		return;
-	__b_drop(buf);
+	if (buf->size)
+		__b_drop(buf);
 }
 
-/* Releases buffer *buf if allocated, and replaces it with &buf_empty. */
-static inline void b_free(struct buffer **buf)
+/* Releases buffer <buf> if allocated, and marks it empty. */
+static inline void b_free(struct buffer *buf)
 {
 	b_drop(buf);
-	*buf = &buf_empty;
+	*buf = BUF_NULL;
 }
 
 /* Ensures that <buf> is allocated. If an allocation is needed, it ensures that
@@ -141,45 +138,44 @@
  * after the allocation, regardless how many threads that doing it in the same
  * time. So, we use internal and lockless memory functions (prefixed with '__').
  */
-static inline struct buffer *b_alloc_margin(struct buffer **buf, int margin)
+static inline struct buffer *b_alloc_margin(struct buffer *buf, int margin)
 {
-	struct buffer *b;
+	char *area;
 
-	if ((*buf)->size)
-		return *buf;
+	if (buf->size)
+		return buf;
 
-	*buf = &buf_wanted;
+	*buf = BUF_WANTED;
+
 #ifndef CONFIG_HAP_LOCKLESS_POOLS
 	HA_SPIN_LOCK(POOL_LOCK, &pool_head_buffer->lock);
 #endif
 
 	/* fast path */
 	if ((pool_head_buffer->allocated - pool_head_buffer->used) > margin) {
-		b = __pool_get_first(pool_head_buffer);
-		if (likely(b)) {
+		area = __pool_get_first(pool_head_buffer);
+		if (likely(area)) {
 #ifndef CONFIG_HAP_LOCKLESS_POOLS
 			HA_SPIN_UNLOCK(POOL_LOCK, &pool_head_buffer->lock);
 #endif
-			b->size = pool_head_buffer->size - sizeof(struct buffer);
-			b_reset(b);
-			*buf = b;
-			return b;
+			goto done;
 		}
 	}
 
 	/* slow path, uses malloc() */
-	b = __pool_refill_alloc(pool_head_buffer, margin);
+	area = __pool_refill_alloc(pool_head_buffer, margin);
 
 #ifndef CONFIG_HAP_LOCKLESS_POOLS
 	HA_SPIN_UNLOCK(POOL_LOCK, &pool_head_buffer->lock);
 #endif
 
-	if (b) {
-		b->size = pool_head_buffer->size - sizeof(struct buffer);
-		b_reset(b);
-		*buf = b;
-	}
-	return b;
+	if (unlikely(!area))
+		return NULL;
+
+ done:
+	buf->area = area;
+	buf->size = pool_head_buffer->size;
+	return buf;
 }
 
 
diff --git a/include/proto/channel.h b/include/proto/channel.h
index 27023ab..d831fcc 100644
--- a/include/proto/channel.h
+++ b/include/proto/channel.h
@@ -87,31 +87,31 @@
 /* c_orig() : returns the pointer to the channel buffer's origin */
 static inline char *c_orig(const struct channel *c)
 {
-	return b_orig(c->buf);
+	return b_orig(&c->buf);
 }
 
 /* c_size() : returns the size of the channel's buffer */
 static inline size_t c_size(const struct channel *c)
 {
-	return b_size(c->buf);
+	return b_size(&c->buf);
 }
 
 /* c_wrap() : returns the pointer to the channel buffer's wrapping point */
 static inline char *c_wrap(const struct channel *c)
 {
-	return b_wrap(c->buf);
+	return b_wrap(&c->buf);
 }
 
 /* c_data() : returns the amount of data in the channel's buffer */
 static inline size_t c_data(const struct channel *c)
 {
-	return b_data(c->buf);
+	return b_data(&c->buf);
 }
 
 /* c_room() : returns the room left in the channel's buffer */
 static inline size_t c_room(const struct channel *c)
 {
-	return b_size(c->buf) - b_data(c->buf);
+	return b_size(&c->buf) - b_data(&c->buf);
 }
 
 /* c_empty() : returns a boolean indicating if the channel's buffer is empty */
@@ -145,11 +145,11 @@
  */
 static inline size_t ci_next_ofs(const struct channel *c, size_t o)
 {
-	return b_next_ofs(c->buf, o);
+	return b_next_ofs(&c->buf, o);
 }
 static inline char *ci_next(const struct channel *c, const char *p)
 {
-	return b_next(c->buf, p);
+	return b_next(&c->buf, p);
 }
 
 
@@ -161,7 +161,7 @@
  */
 static inline char *c_ptr(const struct channel *c, ssize_t ofs)
 {
-	return b_peek(c->buf, co_data(c) + ofs);
+	return b_peek(&c->buf, co_data(c) + ofs);
 }
 
 /* c_adv() : advances the channel's buffer by <adv> bytes, which means that the
@@ -187,13 +187,13 @@
 /* c_realign_if_empty() : realign the channel's buffer if it's empty */
 static inline void c_realign_if_empty(struct channel *chn)
 {
-	b_realign_if_empty(chn->buf);
+	b_realign_if_empty(&chn->buf);
 }
 
 /* Sets the amount of output for the channel */
 static inline void co_set_data(struct channel *c, size_t output)
 {
-	c->buf->data += output - c->output;
+	c->buf.data += output - c->output;
 	c->output = output;
 }
 
@@ -204,19 +204,19 @@
  */
 static inline size_t __co_head_ofs(const struct channel *c)
 {
-	return __b_peek_ofs(c->buf, 0);
+	return __b_peek_ofs(&c->buf, 0);
 }
 static inline char *__co_head(const struct channel *c)
 {
-	return __b_peek(c->buf, 0);
+	return __b_peek(&c->buf, 0);
 }
 static inline size_t co_head_ofs(const struct channel *c)
 {
-	return b_peek_ofs(c->buf, 0);
+	return b_peek_ofs(&c->buf, 0);
 }
 static inline char *co_head(const struct channel *c)
 {
-	return b_peek(c->buf, 0);
+	return b_peek(&c->buf, 0);
 }
 
 
@@ -226,19 +226,19 @@
  */
 static inline size_t __co_tail_ofs(const struct channel *c)
 {
-	return __b_peek_ofs(c->buf, co_data(c));
+	return __b_peek_ofs(&c->buf, co_data(c));
 }
 static inline char *__co_tail(const struct channel *c)
 {
-	return __b_peek(c->buf, co_data(c));
+	return __b_peek(&c->buf, co_data(c));
 }
 static inline size_t co_tail_ofs(const struct channel *c)
 {
-	return b_peek_ofs(c->buf, co_data(c));
+	return b_peek_ofs(&c->buf, co_data(c));
 }
 static inline char *co_tail(const struct channel *c)
 {
-	return b_peek(c->buf, co_data(c));
+	return b_peek(&c->buf, co_data(c));
 }
 
 
@@ -248,19 +248,19 @@
  */
 static inline size_t __ci_head_ofs(const struct channel *c)
 {
-	return __b_peek_ofs(c->buf, co_data(c));
+	return __b_peek_ofs(&c->buf, co_data(c));
 }
 static inline char *__ci_head(const struct channel *c)
 {
-	return __b_peek(c->buf, co_data(c));
+	return __b_peek(&c->buf, co_data(c));
 }
 static inline size_t ci_head_ofs(const struct channel *c)
 {
-	return b_peek_ofs(c->buf, co_data(c));
+	return b_peek_ofs(&c->buf, co_data(c));
 }
 static inline char *ci_head(const struct channel *c)
 {
-	return b_peek(c->buf, co_data(c));
+	return b_peek(&c->buf, co_data(c));
 }
 
 
@@ -270,19 +270,19 @@
  */
 static inline size_t __ci_tail_ofs(const struct channel *c)
 {
-	return __b_peek_ofs(c->buf, c_data(c));
+	return __b_peek_ofs(&c->buf, c_data(c));
 }
 static inline char *__ci_tail(const struct channel *c)
 {
-	return __b_peek(c->buf, c_data(c));
+	return __b_peek(&c->buf, c_data(c));
 }
 static inline size_t ci_tail_ofs(const struct channel *c)
 {
-	return b_peek_ofs(c->buf, c_data(c));
+	return b_peek_ofs(&c->buf, c_data(c));
 }
 static inline char *ci_tail(const struct channel *c)
 {
-	return b_peek(c->buf, c_data(c));
+	return b_peek(&c->buf, c_data(c));
 }
 
 
@@ -292,32 +292,32 @@
  */
 static inline size_t __ci_stop_ofs(const struct channel *c)
 {
-	return __b_stop_ofs(c->buf);
+	return __b_stop_ofs(&c->buf);
 }
 static inline const char *__ci_stop(const struct channel *c)
 {
-	return __b_stop(c->buf);
+	return __b_stop(&c->buf);
 }
 static inline size_t ci_stop_ofs(const struct channel *c)
 {
-	return b_stop_ofs(c->buf);
+	return b_stop_ofs(&c->buf);
 }
 static inline const char *ci_stop(const struct channel *c)
 {
-	return b_stop(c->buf);
+	return b_stop(&c->buf);
 }
 
 
 /* Returns the amount of input data that can contiguously be read at once */
 static inline size_t ci_contig_data(const struct channel *c)
 {
-	return b_contig_data(c->buf, co_data(c));
+	return b_contig_data(&c->buf, co_data(c));
 }
 
 /* Initialize all fields in the channel. */
 static inline void channel_init(struct channel *chn)
 {
-	chn->buf = &buf_empty;
+	chn->buf = BUF_NULL;
 	chn->to_forward = 0;
 	chn->last_read = now_ms;
 	chn->xfer_small = chn->xfer_large = 0;
@@ -382,9 +382,9 @@
  */
 static inline int channel_is_rewritable(const struct channel *chn)
 {
-	int rem = chn->buf->size;
+	int rem = chn->buf.size;
 
-	rem -= b_data(chn->buf);
+	rem -= b_data(&chn->buf);
 	rem -= global.tune.maxrewrite;
 	return rem >= 0;
 }
@@ -402,7 +402,7 @@
  * decide when to stop reading into a buffer when we want to ensure that we
  * leave the reserve untouched after all pending outgoing data are forwarded.
  * The reserved space is taken into account if ->to_forward indicates that an
- * end of transfer is close to happen. Note that both ->buf->o and ->to_forward
+ * end of transfer is close to happen. Note that both ->buf.o and ->to_forward
  * are considered as available since they're supposed to leave the buffer. The
  * test is optimized to avoid as many operations as possible for the fast case
  * and to be used as an "if" condition. Just like channel_recv_limit(), we
@@ -411,12 +411,12 @@
  */
 static inline int channel_may_recv(const struct channel *chn)
 {
-	int rem = chn->buf->size;
+	int rem = chn->buf.size;
 
-	if (chn->buf == &buf_empty)
+	if (b_is_null(&chn->buf))
 		return 1;
 
-	rem -= b_data(chn->buf);
+	rem -= b_data(&chn->buf);
 	if (!rem)
 		return 0; /* buffer already full */
 
@@ -433,7 +433,7 @@
 	 * the reserve, and we want to ensure they're covered by scheduled
 	 * forwards.
 	 */
-	rem = ci_data(chn) + global.tune.maxrewrite - chn->buf->size;
+	rem = ci_data(chn) + global.tune.maxrewrite - chn->buf.size;
 	return rem < 0 || (unsigned int)rem < chn->to_forward;
 }
 
@@ -476,7 +476,7 @@
 static inline void channel_erase(struct channel *chn)
 {
 	chn->to_forward = 0;
-	b_reset(chn->buf);
+	b_reset(&chn->buf);
 }
 
 /* marks the channel as "shutdown" ASAP for reads */
@@ -608,8 +608,8 @@
 	int reserve;
 
 	/* return zero if empty */
-	reserve = chn->buf->size;
-	if (chn->buf == &buf_empty)
+	reserve = chn->buf.size;
+	if (b_is_null(&chn->buf))
 		goto end;
 
 	/* return size - maxrewrite if we can't send */
@@ -630,9 +630,9 @@
 	reserve -= transit;
 	if (transit < chn->to_forward ||                 // addition overflow
 	    transit >= (unsigned)global.tune.maxrewrite) // enough transit data
-		return chn->buf->size;
+		return chn->buf.size;
  end:
-	return chn->buf->size - reserve;
+	return chn->buf.size - reserve;
 }
 
 /* Returns non-zero if the channel's INPUT buffer's is considered full, which
@@ -646,7 +646,7 @@
  */
 static inline int channel_full(const struct channel *c, unsigned int reserve)
 {
-	if (c->buf == &buf_empty)
+	if (b_is_null(&c->buf))
 		return 0;
 
 	return (ci_data(c) + reserve >= c_size(c));
@@ -662,7 +662,7 @@
 {
 	int ret;
 
-	ret = channel_recv_limit(chn) - b_data(chn->buf);
+	ret = channel_recv_limit(chn) - b_data(&chn->buf);
 	if (ret < 0)
 		ret = 0;
 	return ret;
@@ -675,7 +675,7 @@
  */
 static inline int ci_space_for_replace(const struct channel *chn)
 {
-	const struct buffer *buf = chn->buf;
+	const struct buffer *buf = &chn->buf;
 	const char *end;
 
 	/* If the input side data overflows, we cannot insert data contiguously. */
@@ -745,7 +745,7 @@
 	if (!ci_data(chn))
 		return;
 
-	chn->buf->data = co_data(chn);
+	chn->buf.data = co_data(chn);
 }
 
 /* This function realigns a possibly wrapping channel buffer so that the input
@@ -756,7 +756,7 @@
  */
 static inline void channel_slow_realign(struct channel *chn, char *swap)
 {
-	return b_slow_realign(chn->buf, swap, co_data(chn));
+	return b_slow_realign(&chn->buf, swap, co_data(chn));
 }
 
 /*
@@ -768,7 +768,7 @@
  */
 static inline void co_skip(struct channel *chn, int len)
 {
-	b_del(chn->buf, len);
+	b_del(&chn->buf, len);
 	chn->output -= len;
 	c_realign_if_empty(chn);
 
diff --git a/include/proto/stream_interface.h b/include/proto/stream_interface.h
index 3ecfa01..03756ba 100644
--- a/include/proto/stream_interface.h
+++ b/include/proto/stream_interface.h
@@ -74,13 +74,13 @@
 /* returns the buffer which receives data from this stream interface (input channel's buffer) */
 static inline struct buffer *si_ib(struct stream_interface *si)
 {
-	return si_ic(si)->buf;
+	return &si_ic(si)->buf;
 }
 
 /* returns the buffer which feeds data to this stream interface (output channel's buffer) */
 static inline struct buffer *si_ob(struct stream_interface *si)
 {
-	return si_oc(si)->buf;
+	return &si_oc(si)->buf;
 }
 
 /* returns the stream associated to a stream interface */
diff --git a/include/types/channel.h b/include/types/channel.h
index 5205bd6..7879b12 100644
--- a/include/types/channel.h
+++ b/include/types/channel.h
@@ -187,7 +187,7 @@
 struct channel {
 	unsigned int flags;             /* CF_* */
 	unsigned int analysers;         /* bit field indicating what to do on the channel */
-	struct buffer *buf;		/* buffer attached to the channel, always present but may move */
+	struct buffer buf;		/* buffer attached to the channel, always present but may move */
 	struct pipe *pipe;		/* non-NULL only when data present */
 	size_t output;                  /* part of buffer which is to be forwarded */
 	unsigned int to_forward;        /* number of bytes to forward after out without a wake-up */
diff --git a/include/types/checks.h b/include/types/checks.h
index 853a5bf..359b921 100644
--- a/include/types/checks.h
+++ b/include/types/checks.h
@@ -18,6 +18,7 @@
 #include <common/config.h>
 #include <common/mini-clist.h>
 #include <common/regex.h>
+#include <common/buffer.h>
 
 #include <types/connection.h>
 #include <types/obj_type.h>
@@ -157,7 +158,7 @@
 struct check {
 	struct xprt_ops *xprt;			/* transport layer operations for health checks */
 	struct conn_stream *cs;			/* conn_stream state for health checks */
-	struct buffer *bi, *bo;			/* input and output buffers to send/recv check */
+	struct buffer bi, bo;			/* input and output buffers to send/recv check */
 	struct task *task;			/* the task associated to the health check processing, NULL if disabled */
 	struct timeval start;			/* last health check start time */
 	long duration;				/* time in ms took to finish last health check */
diff --git a/include/types/compression.h b/include/types/compression.h
index 9a0cc78..e515aad 100644
--- a/include/types/compression.h
+++ b/include/types/compression.h
@@ -45,7 +45,7 @@
 	struct slz_stream strm;
 	const void *direct_ptr; /* NULL or pointer to beginning of data */
 	int direct_len;         /* length of direct_ptr if not NULL */
-	struct buffer *queued;  /* if not NULL, data already queued */
+	struct buffer queued;   /* if not NULL, data already queued */
 #elif defined(USE_ZLIB)
 	z_stream strm; /* zlib stream */
 	void *zlib_deflate_state;
diff --git a/include/types/spoe.h b/include/types/spoe.h
index 2f13d37..a744cd7 100644
--- a/include/types/spoe.h
+++ b/include/types/spoe.h
@@ -306,7 +306,7 @@
 	struct list        *events;       /* List of messages that will be sent during the stream processing */
 	struct list        *groups;       /* List of available SPOE group */
 
-	struct buffer      *buffer;       /* Buffer used to store a encoded messages */
+	struct buffer       buffer;       /* Buffer used to store a encoded messages */
 	struct buffer_wait  buffer_wait;  /* position in the list of ressources waiting for a buffer */
 	struct list         list;
 
@@ -357,7 +357,7 @@
 	int                 rlen;           /* reason length */
 #endif
 
-	struct buffer      *buffer;         /* Buffer used to store a encoded messages */
+	struct buffer       buffer;         /* Buffer used to store a encoded messages */
 	struct buffer_wait  buffer_wait;    /* position in the list of ressources waiting for a buffer */
 	struct list         waiting_queue;  /* list of streams waiting for a ACK frame, in sync and pipelining mode */
 	struct list         list;           /* next spoe appctx for the same agent */
diff --git a/src/backend.c b/src/backend.c
index 66fd605..b82ecbb 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -329,8 +329,8 @@
 	if (len == 0)
 		return NULL;
 
-	if (len > b_wrap(req->buf) - p)
-		len = b_wrap(req->buf) - p;
+	if (len > b_wrap(&req->buf) - p)
+		len = b_wrap(&req->buf) - p;
 
 	if (px->lbprm.tot_weight == 0)
 		return NULL;
diff --git a/src/buffer.c b/src/buffer.c
index 6f4c494..d6bd242 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -22,15 +22,6 @@
 
 struct pool_head *pool_head_buffer;
 
-/* These buffers are used to always have a valid pointer to an empty buffer in
- * channels. The first buffer is set once a buffer is empty. The second one is
- * set when a buffer is desired but no more are available. It helps knowing
- * what channel wants a buffer. They can reliably be exchanged, the split
- * between the two is only an optimization.
- */
-struct buffer buf_empty  = {  };
-struct buffer buf_wanted = {  };
-
 /* list of objects waiting for at least one buffer */
 struct list buffer_wq = LIST_HEAD_INIT(buffer_wq);
 __decl_hathreads(HA_SPINLOCK_T __attribute__((aligned(64))) buffer_wq_lock);
@@ -40,7 +31,7 @@
 {
 	void *buffer;
 
-	pool_head_buffer = create_pool("buffer", sizeof (struct buffer) + global.tune.bufsize, MEM_F_SHARED|MEM_F_EXACT);
+	pool_head_buffer = create_pool("buffer", global.tune.bufsize, MEM_F_SHARED|MEM_F_EXACT);
 	if (!pool_head_buffer)
 		return 0;
 
diff --git a/src/cache.c b/src/cache.c
index 581c408..6e7a87a 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -541,7 +541,7 @@
 		goto out;
 
 	/* Check if the input buffer is avalaible. */
-	if (res->buf->size == 0) {
+	if (res->buf.size == 0) {
 		si_applet_cant_put(si);
 		goto out;
 	}
@@ -560,7 +560,7 @@
 			si_applet_cant_put(si);
 			goto out;
 		}
-		b_add(res->buf, len);
+		b_add(&res->buf, len);
 		res->total += len;
 		appctx->st0 = HTTP_CACHE_FWD;
 	}
diff --git a/src/channel.c b/src/channel.c
index bb5e144..13184ec 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -92,12 +92,12 @@
 	}
 
 	c_realign_if_empty(chn);
-	max = b_contig_space(chn->buf);
+	max = b_contig_space(&chn->buf);
 	if (len > max)
 		return max;
 
 	memcpy(ci_tail(chn), msg, len);
-	b_add(chn->buf, len);
+	b_add(&chn->buf, len);
 	c_adv(chn, len);
 	chn->total += len;
 	return -1;
@@ -119,7 +119,7 @@
 
 	*ci_tail(chn) = c;
 
-	b_add(chn->buf, 1);
+	b_add(&chn->buf, 1);
 	chn->flags |= CF_READ_PARTIAL;
 
 	if (chn->to_forward >= 1) {
@@ -166,12 +166,12 @@
 		return 0;
 
 	/* OK so the data fits in the buffer in one or two blocks */
-	max = b_contig_space(chn->buf);
+	max = b_contig_space(&chn->buf);
 	memcpy(ci_tail(chn), blk, MIN(len, max));
 	if (len > max)
 		memcpy(c_orig(chn), blk + max, len - max);
 
-	b_add(chn->buf, len);
+	b_add(&chn->buf, len);
 	chn->total += len;
 	if (chn->to_forward) {
 		unsigned long fwd = len;
@@ -226,7 +226,7 @@
 
 		if (*p == '\n')
 			break;
-		p = b_next(chn->buf, p);
+		p = b_next(&chn->buf, p);
 	}
 	if (ret > 0 && ret < len &&
 	    (ret < co_data(chn) || channel_may_recv(chn)) &&
@@ -258,7 +258,7 @@
 		return 0;
 	}
 
-	return b_getblk(chn->buf, blk, len, offset);
+	return b_getblk(&chn->buf, blk, len, offset);
 }
 
 /* Gets one or two blocks of data at once from a channel's output buffer.
@@ -277,7 +277,7 @@
 		return 0;
 	}
 
-	return b_getblk_nc(chn->buf, blk1, len1, blk2, len2, 0, co_data(chn));
+	return b_getblk_nc(&chn->buf, blk1, len1, blk2, len2, 0, co_data(chn));
 }
 
 /* Gets one text line out of a channel's output buffer from a stream interface.
@@ -411,7 +411,7 @@
  */
 int ci_insert_line2(struct channel *c, int pos, const char *str, int len)
 {
-	struct buffer *b = c->buf;
+	struct buffer *b = &c->buf;
 	char *dst = c_ptr(c, pos);
 	int delta;
 
diff --git a/src/checks.c b/src/checks.c
index bf4c78f..6db077a 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -745,16 +745,16 @@
 	if (check->type == PR_O2_TCPCHK_CHK)
 		goto out_unlock;
 
-	if (b_data(check->bo)) {
-		b_del(check->bo, conn->mux->snd_buf(cs, check->bo, b_data(check->bo), 0));
-		b_realign_if_empty(check->bo);
+	if (b_data(&check->bo)) {
+		b_del(&check->bo, conn->mux->snd_buf(cs, &check->bo, b_data(&check->bo), 0));
+		b_realign_if_empty(&check->bo);
 
 		if (conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) {
 			chk_report_conn_err(check, errno, 0);
 			__cs_stop_both(cs);
 			goto out_wakeup;
 		}
-		if (b_data(check->bo))
+		if (b_data(&check->bo))
 			goto out_unlock;
 	}
 
@@ -824,10 +824,10 @@
 
 	done = 0;
 
-	conn->mux->rcv_buf(cs, check->bi, check->bi->size, 0);
+	conn->mux->rcv_buf(cs, &check->bi, b_size(&check->bi), 0);
 	if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH) || cs->flags & CS_FL_ERROR) {
 		done = 1;
-		if ((conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) && !b_data(check->bi)) {
+		if ((conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) && !b_data(&check->bi)) {
 			/* Report network errors only if we got no other data. Otherwise
 			 * we'll let the upper layers decide whether the response is OK
 			 * or not. It is very common that an RST sent by the server is
@@ -840,35 +840,35 @@
 
 
 	/* Intermediate or complete response received.
-	 * Terminate string in b_head(check->bi) buffer.
+	 * Terminate string in b_head(&check->bi) buffer.
 	 */
-	if (b_data(check->bi) < check->bi->size)
-		b_head(check->bi)[b_data(check->bi)] = '\0';
+	if (b_data(&check->bi) < b_size(&check->bi))
+		b_head(&check->bi)[b_data(&check->bi)] = '\0';
 	else {
-		b_head(check->bi)[b_data(check->bi) - 1] = '\0';
+		b_head(&check->bi)[b_data(&check->bi) - 1] = '\0';
 		done = 1; /* buffer full, don't wait for more data */
 	}
 
 	/* Run the checks... */
 	switch (check->type) {
 	case PR_O2_HTTP_CHK:
-		if (!done && b_data(check->bi) < strlen("HTTP/1.0 000\r"))
+		if (!done && b_data(&check->bi) < strlen("HTTP/1.0 000\r"))
 			goto wait_more_data;
 
 		/* Check if the server speaks HTTP 1.X */
-		if ((b_data(check->bi) < strlen("HTTP/1.0 000\r")) ||
-		    (memcmp(b_head(check->bi), "HTTP/1.", 7) != 0 ||
-		    (*(b_head(check->bi) + 12) != ' ' && *(b_head(check->bi) + 12) != '\r')) ||
-		    !isdigit((unsigned char) *(b_head(check->bi) + 9)) || !isdigit((unsigned char) *(b_head(check->bi) + 10)) ||
-		    !isdigit((unsigned char) *(b_head(check->bi) + 11))) {
-			cut_crlf(b_head(check->bi));
-			set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(check->bi));
+		if ((b_data(&check->bi) < strlen("HTTP/1.0 000\r")) ||
+		    (memcmp(b_head(&check->bi), "HTTP/1.", 7) != 0 ||
+		    (*(b_head(&check->bi) + 12) != ' ' && *(b_head(&check->bi) + 12) != '\r')) ||
+		    !isdigit((unsigned char) *(b_head(&check->bi) + 9)) || !isdigit((unsigned char) *(b_head(&check->bi) + 10)) ||
+		    !isdigit((unsigned char) *(b_head(&check->bi) + 11))) {
+			cut_crlf(b_head(&check->bi));
+			set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(&check->bi));
 
 			goto out_wakeup;
 		}
 
-		check->code = str2uic(b_head(check->bi) + 9);
-		desc = ltrim(b_head(check->bi) + 12, ' ');
+		check->code = str2uic(b_head(&check->bi) + 9);
+		desc = ltrim(b_head(&check->bi) + 12, ' ');
 
 		if ((s->proxy->options & PR_O_DISABLE404) &&
 			 (s->next_state != SRV_ST_STOPPED) && (check->code == 404)) {
@@ -882,7 +882,7 @@
 				goto wait_more_data;
 		}
 		/* check the reply : HTTP/1.X 2xx and 3xx are OK */
-		else if (*(b_head(check->bi) + 9) == '2' || *(b_head(check->bi) + 9) == '3') {
+		else if (*(b_head(&check->bi) + 9) == '2' || *(b_head(&check->bi) + 9) == '3') {
 			cut_crlf(desc);
 			set_server_check_status(check,  HCHK_STATUS_L7OKD, desc);
 		}
@@ -893,37 +893,37 @@
 		break;
 
 	case PR_O2_SSL3_CHK:
-		if (!done && b_data(check->bi) < 5)
+		if (!done && b_data(&check->bi) < 5)
 			goto wait_more_data;
 
 		/* Check for SSLv3 alert or handshake */
-		if ((b_data(check->bi) >= 5) && (*b_head(check->bi) == 0x15 || *b_head(check->bi) == 0x16))
+		if ((b_data(&check->bi) >= 5) && (*b_head(&check->bi) == 0x15 || *b_head(&check->bi) == 0x16))
 			set_server_check_status(check, HCHK_STATUS_L6OK, NULL);
 		else
 			set_server_check_status(check, HCHK_STATUS_L6RSP, NULL);
 		break;
 
 	case PR_O2_SMTP_CHK:
-		if (!done && b_data(check->bi) < strlen("000\r"))
+		if (!done && b_data(&check->bi) < strlen("000\r"))
 			goto wait_more_data;
 
 		/* Check if the server speaks SMTP */
-		if ((b_data(check->bi) < strlen("000\r")) ||
-		    (*(b_head(check->bi) + 3) != ' ' && *(b_head(check->bi) + 3) != '\r') ||
-		    !isdigit((unsigned char) *b_head(check->bi)) || !isdigit((unsigned char) *(b_head(check->bi) + 1)) ||
-		    !isdigit((unsigned char) *(b_head(check->bi) + 2))) {
-			cut_crlf(b_head(check->bi));
-			set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(check->bi));
+		if ((b_data(&check->bi) < strlen("000\r")) ||
+		    (*(b_head(&check->bi) + 3) != ' ' && *(b_head(&check->bi) + 3) != '\r') ||
+		    !isdigit((unsigned char) *b_head(&check->bi)) || !isdigit((unsigned char) *(b_head(&check->bi) + 1)) ||
+		    !isdigit((unsigned char) *(b_head(&check->bi) + 2))) {
+			cut_crlf(b_head(&check->bi));
+			set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(&check->bi));
 			goto out_wakeup;
 		}
 
-		check->code = str2uic(b_head(check->bi));
+		check->code = str2uic(b_head(&check->bi));
 
-		desc = ltrim(b_head(check->bi) + 3, ' ');
+		desc = ltrim(b_head(&check->bi) + 3, ' ');
 		cut_crlf(desc);
 
 		/* Check for SMTP code 2xx (should be 250) */
-		if (*b_head(check->bi) == '2')
+		if (*b_head(&check->bi) == '2')
 			set_server_check_status(check, HCHK_STATUS_L7OKD, desc);
 		else
 			set_server_check_status(check, HCHK_STATUS_L7STS, desc);
@@ -963,7 +963,7 @@
 		 * same category appear, the last one wins.
 		 */
 
-		p = b_head(check->bi);
+		p = b_head(&check->bi);
 		while (*p && *p != '\n' && *p != '\r')
 			p++;
 
@@ -977,7 +977,7 @@
 		}
 
 		*p = 0;
-		cmd = b_head(check->bi);
+		cmd = b_head(&check->bi);
 
 		while (*cmd) {
 			/* look for next word */
@@ -1135,15 +1135,15 @@
 	}
 
 	case PR_O2_PGSQL_CHK:
-		if (!done && b_data(check->bi) < 9)
+		if (!done && b_data(&check->bi) < 9)
 			goto wait_more_data;
 
-		if (b_head(check->bi)[0] == 'R') {
+		if (b_head(&check->bi)[0] == 'R') {
 			set_server_check_status(check, HCHK_STATUS_L7OKD, "PostgreSQL server is ok");
 		}
 		else {
-			if ((b_head(check->bi)[0] == 'E') && (b_head(check->bi)[5]!=0) && (b_head(check->bi)[6]!=0))
-				desc = &b_head(check->bi)[6];
+			if ((b_head(&check->bi)[0] == 'E') && (b_head(&check->bi)[5]!=0) && (b_head(&check->bi)[6]!=0))
+				desc = &b_head(&check->bi)[6];
 			else
 				desc = "PostgreSQL unknown error";
 
@@ -1152,29 +1152,29 @@
 		break;
 
 	case PR_O2_REDIS_CHK:
-		if (!done && b_data(check->bi) < 7)
+		if (!done && b_data(&check->bi) < 7)
 			goto wait_more_data;
 
-		if (strcmp(b_head(check->bi), "+PONG\r\n") == 0) {
+		if (strcmp(b_head(&check->bi), "+PONG\r\n") == 0) {
 			set_server_check_status(check, HCHK_STATUS_L7OKD, "Redis server is ok");
 		}
 		else {
-			set_server_check_status(check, HCHK_STATUS_L7STS, b_head(check->bi));
+			set_server_check_status(check, HCHK_STATUS_L7STS, b_head(&check->bi));
 		}
 		break;
 
 	case PR_O2_MYSQL_CHK:
-		if (!done && b_data(check->bi) < 5)
+		if (!done && b_data(&check->bi) < 5)
 			goto wait_more_data;
 
 		if (s->proxy->check_len == 0) { // old mode
-			if (*(b_head(check->bi) + 4) != '\xff') {
+			if (*(b_head(&check->bi) + 4) != '\xff') {
 				/* We set the MySQL Version in description for information purpose
 				 * FIXME : it can be cool to use MySQL Version for other purpose,
 				 * like mark as down old MySQL server.
 				 */
-				if (b_data(check->bi) > 51) {
-					desc = ltrim(b_head(check->bi) + 5, ' ');
+				if (b_data(&check->bi) > 51) {
+					desc = ltrim(b_head(&check->bi) + 5, ' ');
 					set_server_check_status(check, HCHK_STATUS_L7OKD, desc);
 				}
 				else {
@@ -1184,48 +1184,48 @@
 					/* it seems we have a OK packet but without a valid length,
 					 * it must be a protocol error
 					 */
-					set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(check->bi));
+					set_server_check_status(check, HCHK_STATUS_L7RSP, b_head(&check->bi));
 				}
 			}
 			else {
 				/* An error message is attached in the Error packet */
-				desc = ltrim(b_head(check->bi) + 7, ' ');
+				desc = ltrim(b_head(&check->bi) + 7, ' ');
 				set_server_check_status(check, HCHK_STATUS_L7STS, desc);
 			}
 		} else {
-			unsigned int first_packet_len = ((unsigned int) *b_head(check->bi)) +
-			                                (((unsigned int) *(b_head(check->bi) + 1)) << 8) +
-			                                (((unsigned int) *(b_head(check->bi) + 2)) << 16);
+			unsigned int first_packet_len = ((unsigned int) *b_head(&check->bi)) +
+			                                (((unsigned int) *(b_head(&check->bi) + 1)) << 8) +
+			                                (((unsigned int) *(b_head(&check->bi) + 2)) << 16);
 
-			if (b_data(check->bi) == first_packet_len + 4) {
+			if (b_data(&check->bi) == first_packet_len + 4) {
 				/* MySQL Error packet always begin with field_count = 0xff */
-				if (*(b_head(check->bi) + 4) != '\xff') {
+				if (*(b_head(&check->bi) + 4) != '\xff') {
 					/* We have only one MySQL packet and it is a Handshake Initialization packet
 					* but we need to have a second packet to know if it is alright
 					*/
-					if (!done && b_data(check->bi) < first_packet_len + 5)
+					if (!done && b_data(&check->bi) < first_packet_len + 5)
 						goto wait_more_data;
 				}
 				else {
 					/* We have only one packet and it is an Error packet,
 					* an error message is attached, so we can display it
 					*/
-					desc = &b_head(check->bi)[7];
+					desc = &b_head(&check->bi)[7];
 					//ha_warning("onlyoneERR: %s\n", desc);
 					set_server_check_status(check, HCHK_STATUS_L7STS, desc);
 				}
-			} else if (b_data(check->bi) > first_packet_len + 4) {
-				unsigned int second_packet_len = ((unsigned int) *(b_head(check->bi) + first_packet_len + 4)) +
-				                                 (((unsigned int) *(b_head(check->bi) + first_packet_len + 5)) << 8) +
-				                                 (((unsigned int) *(b_head(check->bi) + first_packet_len + 6)) << 16);
+			} else if (b_data(&check->bi) > first_packet_len + 4) {
+				unsigned int second_packet_len = ((unsigned int) *(b_head(&check->bi) + first_packet_len + 4)) +
+				                                 (((unsigned int) *(b_head(&check->bi) + first_packet_len + 5)) << 8) +
+				                                 (((unsigned int) *(b_head(&check->bi) + first_packet_len + 6)) << 16);
 
-				if (b_data(check->bi) == first_packet_len + 4 + second_packet_len + 4 ) {
+				if (b_data(&check->bi) == first_packet_len + 4 + second_packet_len + 4 ) {
 					/* We have 2 packets and that's good */
 					/* Check if the second packet is a MySQL Error packet or not */
-					if (*(b_head(check->bi) + first_packet_len + 8) != '\xff') {
+					if (*(b_head(&check->bi) + first_packet_len + 8) != '\xff') {
 						/* No error packet */
 						/* We set the MySQL Version in description for information purpose */
-						desc = &b_head(check->bi)[5];
+						desc = &b_head(&check->bi)[5];
 						//ha_warning("2packetOK: %s\n", desc);
 						set_server_check_status(check, HCHK_STATUS_L7OKD, desc);
 					}
@@ -1233,7 +1233,7 @@
 						/* An error message is attached in the Error packet
 						* so we can display it ! :)
 						*/
-						desc = &b_head(check->bi)[first_packet_len+11];
+						desc = &b_head(&check->bi)[first_packet_len+11];
 						//ha_warning("2packetERR: %s\n", desc);
 						set_server_check_status(check, HCHK_STATUS_L7STS, desc);
 					}
@@ -1246,7 +1246,7 @@
 				/* it seems we have a Handshake Initialization packet but without a valid length,
 				 * it must be a protocol error
 				 */
-				desc = &b_head(check->bi)[5];
+				desc = &b_head(&check->bi)[5];
 				//ha_warning("protoerr: %s\n", desc);
 				set_server_check_status(check, HCHK_STATUS_L7RSP, desc);
 			}
@@ -1254,7 +1254,7 @@
 		break;
 
 	case PR_O2_LDAP_CHK:
-		if (!done && b_data(check->bi) < 14)
+		if (!done && b_data(&check->bi) < 14)
 			goto wait_more_data;
 
 		/* Check if the server speaks LDAP (ASN.1/BER)
@@ -1265,31 +1265,31 @@
 		/* http://tools.ietf.org/html/rfc4511#section-4.1.1
 		 *   LDAPMessage: 0x30: SEQUENCE
 		 */
-		if ((b_data(check->bi) < 14) || (*(b_head(check->bi)) != '\x30')) {
+		if ((b_data(&check->bi) < 14) || (*(b_head(&check->bi)) != '\x30')) {
 			set_server_check_status(check, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 		}
 		else {
 			 /* size of LDAPMessage */
-			msglen = (*(b_head(check->bi) + 1) & 0x80) ? (*(b_head(check->bi) + 1) & 0x7f) : 0;
+			msglen = (*(b_head(&check->bi) + 1) & 0x80) ? (*(b_head(&check->bi) + 1) & 0x7f) : 0;
 
 			/* http://tools.ietf.org/html/rfc4511#section-4.2.2
 			 *   messageID: 0x02 0x01 0x01: INTEGER 1
 			 *   protocolOp: 0x61: bindResponse
 			 */
 			if ((msglen > 2) ||
-			    (memcmp(b_head(check->bi) + 2 + msglen, "\x02\x01\x01\x61", 4) != 0)) {
+			    (memcmp(b_head(&check->bi) + 2 + msglen, "\x02\x01\x01\x61", 4) != 0)) {
 				set_server_check_status(check, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 				goto out_wakeup;
 			}
 
 			/* size of bindResponse */
-			msglen += (*(b_head(check->bi) + msglen + 6) & 0x80) ? (*(b_head(check->bi) + msglen + 6) & 0x7f) : 0;
+			msglen += (*(b_head(&check->bi) + msglen + 6) & 0x80) ? (*(b_head(&check->bi) + msglen + 6) & 0x7f) : 0;
 
 			/* http://tools.ietf.org/html/rfc4511#section-4.1.9
 			 *   ldapResult: 0x0a 0x01: ENUMERATION
 			 */
 			if ((msglen > 4) ||
-			    (memcmp(b_head(check->bi) + 7 + msglen, "\x0a\x01", 2) != 0)) {
+			    (memcmp(b_head(&check->bi) + 7 + msglen, "\x0a\x01", 2) != 0)) {
 				set_server_check_status(check, HCHK_STATUS_L7RSP, "Not LDAPv3 protocol");
 				goto out_wakeup;
 			}
@@ -1297,7 +1297,7 @@
 			/* http://tools.ietf.org/html/rfc4511#section-4.1.9
 			 *   resultCode
 			 */
-			check->code = *(b_head(check->bi) + msglen + 9);
+			check->code = *(b_head(&check->bi) + msglen + 9);
 			if (check->code) {
 				set_server_check_status(check, HCHK_STATUS_L7STS, "See RFC: http://tools.ietf.org/html/rfc4511#section-4.1.9");
 			} else {
@@ -1310,16 +1310,16 @@
 		unsigned int framesz;
 		char	     err[HCHK_DESC_LEN];
 
-		if (!done && b_data(check->bi) < 4)
+		if (!done && b_data(&check->bi) < 4)
 			goto wait_more_data;
 
-		memcpy(&framesz, b_head(check->bi), 4);
+		memcpy(&framesz, b_head(&check->bi), 4);
 		framesz = ntohl(framesz);
 
-		if (!done && b_data(check->bi) < (4+framesz))
+		if (!done && b_data(&check->bi) < (4+framesz))
 		    goto wait_more_data;
 
-		if (!spoe_handle_healthcheck_response(b_head(check->bi)+4, framesz, err, HCHK_DESC_LEN-1))
+		if (!spoe_handle_healthcheck_response(b_head(&check->bi)+4, framesz, err, HCHK_DESC_LEN-1))
 			set_server_check_status(check, HCHK_STATUS_L7OKD, "SPOA server is ok");
 		else
 			set_server_check_status(check, HCHK_STATUS_L7STS, err);
@@ -1337,8 +1337,8 @@
 		chk_report_conn_err(check, 0, 0);
 
 	/* Reset the check buffer... */
-	*b_head(check->bi) = '\0';
-	b_reset(check->bi);
+	*b_head(&check->bi) = '\0';
+	b_reset(&check->bi);
 
 	/* Close the connection... We still attempt to nicely close if,
 	 * for instance, SSL needs to send a "close notify." Later, we perform
@@ -1518,7 +1518,7 @@
 	 * its own strings.
 	 */
 	if (check->type && check->type != PR_O2_TCPCHK_CHK && !(check->state & CHK_ST_AGENT)) {
-		b_putblk(check->bo, s->proxy->check_req, s->proxy->check_len);
+		b_putblk(&check->bo, s->proxy->check_req, s->proxy->check_len);
 
 		/* we want to check if this host replies to HTTP or SSLv3 requests
 		 * so we'll send the request, and won't wake the checker up now.
@@ -1526,21 +1526,21 @@
 		if ((check->type) == PR_O2_SSL3_CHK) {
 			/* SSL requires that we put Unix time in the request */
 			int gmt_time = htonl(date.tv_sec);
-			memcpy(b_head(check->bo) + 11, &gmt_time, 4);
+			memcpy(b_head(&check->bo) + 11, &gmt_time, 4);
 		}
 		else if ((check->type) == PR_O2_HTTP_CHK) {
 			if (s->proxy->options2 & PR_O2_CHK_SNDST)
-				b_putblk(check->bo, trash.str, httpchk_build_status_header(s, trash.str, trash.size));
+				b_putblk(&check->bo, trash.str, httpchk_build_status_header(s, trash.str, trash.size));
 			/* prevent HTTP keep-alive when "http-check expect" is used */
 			if (s->proxy->options2 & PR_O2_EXP_TYPE)
-				b_putist(check->bo, ist("Connection: close\r\n"));
-			b_putist(check->bo, ist("\r\n"));
-			*b_tail(check->bo) = '\0'; /* to make gdb output easier to read */
+				b_putist(&check->bo, ist("Connection: close\r\n"));
+			b_putist(&check->bo, ist("\r\n"));
+			*b_tail(&check->bo) = '\0'; /* to make gdb output easier to read */
 		}
 	}
 
 	if ((check->type & PR_O2_LB_AGENT_CHK) && check->send_string_len) {
-		b_putblk(check->bo, check->send_string, check->send_string_len);
+		b_putblk(&check->bo, check->send_string, check->send_string_len);
 	}
 
 	/* for tcp-checks, the initial connection setup is handled separately as
@@ -2129,8 +2129,8 @@
 		set_server_check_status(check, HCHK_STATUS_START, NULL);
 
 		check->state |= CHK_ST_INPROGRESS;
-		b_reset(check->bi);
-		b_reset(check->bo);
+		b_reset(&check->bi);
+		b_reset(&check->bo);
 
 		ret = connect_conn_chk(t);
 		cs = check->cs;
@@ -2424,8 +2424,8 @@
 	switch (s->proxy->options2 & PR_O2_EXP_TYPE) {
 	case PR_O2_EXP_STS:
 	case PR_O2_EXP_RSTS:
-		memcpy(status_code, b_head(s->check.bi) + 9, 3);
-		memcpy(status_msg + strlen(status_msg) - 4, b_head(s->check.bi) + 9, 3);
+		memcpy(status_code, b_head(&s->check.bi) + 9, 3);
+		memcpy(status_msg + strlen(status_msg) - 4, b_head(&s->check.bi) + 9, 3);
 
 		if ((s->proxy->options2 & PR_O2_EXP_TYPE) == PR_O2_EXP_STS)
 			ret = strncmp(s->proxy->expect_str, status_code, 3) == 0;
@@ -2446,7 +2446,7 @@
 		 * to '\0' if crlf < 2.
 		 */
 		crlf = 0;
-		for (contentptr = b_head(s->check.bi); *contentptr; contentptr++) {
+		for (contentptr = b_head(&s->check.bi); *contentptr; contentptr++) {
 			if (crlf >= 2)
 				break;
 			if (*contentptr == '\r')
@@ -2645,8 +2645,8 @@
 	/* no step means first step initialisation */
 	if (check->current_step == NULL) {
 		check->last_started_step = NULL;
-		b_reset(check->bo);
-		b_reset(check->bi);
+		b_reset(&check->bo);
+		b_reset(&check->bi);
 		check->current_step = next;
 		t->expire = tick_add(now_ms, MS_TO_TICKS(check->inter));
 		if (s->proxy->timeout.check)
@@ -2663,16 +2663,16 @@
 		 * in the remaining space. That explains why we break out of the
 		 * loop after this control. If we have data, conn is valid.
 		 */
-		if (b_data(check->bo) &&
+		if (b_data(&check->bo) &&
 		    (&check->current_step->list == head ||
 		     check->current_step->action != TCPCHK_ACT_SEND ||
-		     check->current_step->string_len >= b_room(check->bo))) {
+		     check->current_step->string_len >= b_room(&check->bo))) {
 			int ret;
 
 			__cs_want_send(cs);
-			ret = conn->mux->snd_buf(cs, check->bo, b_data(check->bo), 0);
-			b_del(check->bo, ret);
-			b_realign_if_empty(check->bo);
+			ret = conn->mux->snd_buf(cs, &check->bo, b_data(&check->bo), 0);
+			b_del(&check->bo, ret);
+			b_realign_if_empty(&check->bo);
 
 			if (ret <= 0) {
 				if (conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) {
@@ -2845,9 +2845,9 @@
 			check->last_started_step = check->current_step;
 
 			/* reset the read buffer */
-			if (*b_head(check->bi) != '\0') {
-				*b_head(check->bi) = '\0';
-				b_reset(check->bi);
+			if (*b_head(&check->bi) != '\0') {
+				*b_head(&check->bi) = '\0';
+				b_reset(&check->bi);
 			}
 
 			if (conn->flags & CO_FL_SOCK_WR_SH) {
@@ -2856,20 +2856,20 @@
 				goto out_end_tcpcheck;
 			}
 
-			if (check->current_step->string_len >= check->bo->size) {
+			if (check->current_step->string_len >= b_size(&check->bo)) {
 				chunk_printf(&trash, "tcp-check send : string too large (%d) for buffer size (%u) at step %d",
-					     check->current_step->string_len, (unsigned int)check->bo->size,
+					     check->current_step->string_len, (unsigned int)b_size(&check->bo),
 					     tcpcheck_get_step_id(check));
 				set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
 				goto out_end_tcpcheck;
 			}
 
 			/* do not try to send if there is no space */
-			if (check->current_step->string_len >= b_room(check->bo))
+			if (check->current_step->string_len >= b_room(&check->bo))
 				continue;
 
-			b_putblk(check->bo, check->current_step->string, check->current_step->string_len);
-			*b_tail(check->bo) = '\0'; /* to make gdb output easier to read */
+			b_putblk(&check->bo, check->current_step->string, check->current_step->string_len);
+			*b_tail(&check->bo) = '\0'; /* to make gdb output easier to read */
 
 			/* go to next rule and try to send */
 			check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
@@ -2885,10 +2885,10 @@
 				goto out_end_tcpcheck;
 
 			__cs_want_recv(cs);
-			if (conn->mux->rcv_buf(cs, check->bi, check->bi->size, 0) <= 0) {
+			if (conn->mux->rcv_buf(cs, &check->bi, b_size(&check->bi), 0) <= 0) {
 				if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH) || cs->flags & CS_FL_ERROR) {
 					done = 1;
-					if ((conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) && !b_data(check->bi)) {
+					if ((conn->flags & CO_FL_ERROR || cs->flags & CS_FL_ERROR) && !b_data(&check->bi)) {
 						/* Report network errors only if we got no other data. Otherwise
 						 * we'll let the upper layers decide whether the response is OK
 						 * or not. It is very common that an RST sent by the server is
@@ -2907,20 +2907,20 @@
 
 
 			/* Intermediate or complete response received.
-			 * Terminate string in b_head(check->bi) buffer.
+			 * Terminate string in b_head(&check->bi) buffer.
 			 */
-			if (b_data(check->bi) < check->bi->size) {
-				b_head(check->bi)[b_data(check->bi)] = '\0';
+			if (b_data(&check->bi) < b_size(&check->bi)) {
+				b_head(&check->bi)[b_data(&check->bi)] = '\0';
 			}
 			else {
-				b_head(check->bi)[b_data(check->bi) - 1] = '\0';
+				b_head(&check->bi)[b_data(&check->bi) - 1] = '\0';
 				done = 1; /* buffer full, don't wait for more data */
 			}
 
-			contentptr = b_head(check->bi);
+			contentptr = b_head(&check->bi);
 
 			/* Check that response body is not empty... */
-			if (!b_data(check->bi)) {
+			if (!b_data(&check->bi)) {
 				if (!done)
 					continue;
 
@@ -2935,12 +2935,12 @@
 				goto out_end_tcpcheck;
 			}
 
-			if (!done && (check->current_step->string != NULL) && (b_data(check->bi) < check->current_step->string_len) )
+			if (!done && (check->current_step->string != NULL) && (b_data(&check->bi) < check->current_step->string_len) )
 				continue; /* try to read more */
 
 		tcpcheck_expect:
 			if (check->current_step->string != NULL)
-				ret = my_memmem(contentptr, b_data(check->bi), check->current_step->string, check->current_step->string_len) != NULL;
+				ret = my_memmem(contentptr, b_data(&check->bi), check->current_step->string, check->current_step->string_len) != NULL;
 			else if (check->current_step->expect_regex != NULL)
 				ret = regex_exec(check->current_step->expect_regex, contentptr);
 
@@ -3048,13 +3048,13 @@
 	/* We're waiting for some I/O to complete, we've reached the end of the
 	 * rules, or both. Do what we have to do, otherwise we're done.
 	 */
-	if (&check->current_step->list == head && !b_data(check->bo)) {
+	if (&check->current_step->list == head && !b_data(&check->bo)) {
 		set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
 		goto out_end_tcpcheck;
 	}
 
 	/* warning, current_step may now point to the head */
-	if (b_data(check->bo))
+	if (b_data(&check->bo))
 		__cs_want_send(cs);
 
 	if (&check->current_step->list != head &&
@@ -3083,26 +3083,22 @@
 {
 	check->type = type;
 
-	/* Allocate buffer for requests... */
-	if ((check->bi = calloc(sizeof(struct buffer) + global.tune.chksize, sizeof(char))) == NULL) {
-		return "out of memory while allocating check buffer";
-	}
-	check->bi->size = global.tune.chksize;
+	b_reset(&check->bi); check->bi.size = global.tune.chksize;
+	b_reset(&check->bo); check->bo.size = global.tune.chksize;
 
-	/* Allocate buffer for responses... */
-	if ((check->bo = calloc(sizeof(struct buffer) + global.tune.chksize, sizeof(char))) == NULL) {
+	check->bi.area = calloc(check->bi.size, sizeof(char));
+	check->bo.area = calloc(check->bo.size, sizeof(char));
+
+	if (!check->bi.area || !check->bo.area)
 		return "out of memory while allocating check buffer";
-	}
-	check->bo->size = global.tune.chksize;
+
 	return NULL;
 }
 
 void free_check(struct check *check)
 {
-	free(check->bi);
-	check->bi = NULL;
-	free(check->bo);
-	check->bo = NULL;
+	free(check->bi.area);
+	free(check->bo.area);
 	if (check->cs) {
 		free(check->cs->conn);
 		check->cs->conn = NULL;
diff --git a/src/cli.c b/src/cli.c
index c656e4b..0bc4722 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -524,7 +524,7 @@
 		goto out;
 
 	/* Check if the input buffer is avalaible. */
-	if (res->buf->size == 0) {
+	if (res->buf.size == 0) {
 		si_applet_cant_put(si);
 		goto out;
 	}
diff --git a/src/compression.c b/src/compression.c
index eb74661..3e98402 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -172,7 +172,7 @@
 #if defined(USE_SLZ)
 	(*comp_ctx)->direct_ptr = NULL;
 	(*comp_ctx)->direct_len = 0;
-	(*comp_ctx)->queued = NULL;
+	(*comp_ctx)->queued = BUF_NULL;
 #elif defined(USE_ZLIB)
 	HA_ATOMIC_ADD(&zlib_used_memory, sizeof(struct comp_ctx));
 
@@ -291,34 +291,34 @@
  */
 static int rfc195x_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out)
 {
-	static THREAD_LOCAL struct buffer *tmpbuf = &buf_empty;
+	static THREAD_LOCAL struct buffer tmpbuf = BUF_NULL;
 
 	if (in_len <= 0)
 		return 0;
 
-	if (comp_ctx->direct_ptr && !comp_ctx->queued) {
+	if (comp_ctx->direct_ptr && b_is_null(&comp_ctx->queued)) {
 		/* data already being pointed to, we're in front of fragmented
 		 * data and need a buffer now. We reuse the same buffer, as it's
 		 * not used out of the scope of a series of add_data()*, end().
 		 */
-		if (unlikely(!tmpbuf->size)) {
+		if (unlikely(!tmpbuf.size)) {
 			/* this is the first time we need the compression buffer */
 			if (b_alloc(&tmpbuf) == NULL)
 				return -1; /* no memory */
 		}
-		b_reset(tmpbuf);
-		memcpy(b_tail(tmpbuf), comp_ctx->direct_ptr, comp_ctx->direct_len);
-		b_add(tmpbuf, comp_ctx->direct_len);
+		b_reset(&tmpbuf);
+		memcpy(b_tail(&tmpbuf), comp_ctx->direct_ptr, comp_ctx->direct_len);
+		b_add(&tmpbuf, comp_ctx->direct_len);
 		comp_ctx->direct_ptr = NULL;
 		comp_ctx->direct_len = 0;
 		comp_ctx->queued = tmpbuf;
 		/* fall through buffer copy */
 	}
 
-	if (comp_ctx->queued) {
+	if (!b_is_null(&comp_ctx->queued)) {
 		/* data already pending */
-		memcpy(b_tail(comp_ctx->queued), in_data, in_len);
-		b_add(comp_ctx->queued, in_len);
+		memcpy(b_tail(&comp_ctx->queued), in_data, in_len);
+		b_add(&comp_ctx->queued, in_len);
 		return in_len;
 	}
 
@@ -342,9 +342,9 @@
 	in_ptr = comp_ctx->direct_ptr;
 	in_len = comp_ctx->direct_len;
 
-	if (comp_ctx->queued) {
-		in_ptr = b_head(comp_ctx->queued);
-		in_len = b_data(comp_ctx->queued);
+	if (!b_is_null(&comp_ctx->queued)) {
+		in_ptr = b_head(&comp_ctx->queued);
+		in_len = b_data(&comp_ctx->queued);
 	}
 
 	out_len = b_data(out);
@@ -360,7 +360,7 @@
 	/* very important, we must wipe the data we've just flushed */
 	comp_ctx->direct_len = 0;
 	comp_ctx->direct_ptr = NULL;
-	comp_ctx->queued     = NULL;
+	comp_ctx->queued     = BUF_NULL;
 
 	/* Verify compression rate limiting and CPU usage */
 	if ((global.comp_rate_lim > 0 && (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim)) ||    /* rate */
diff --git a/src/filters.c b/src/filters.c
index 03534f7..a4005ed 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -569,7 +569,7 @@
 			/* And set this value as the bound for the next
 			 * filter. It will not able to parse more data than this
 			 * one. */
-			b_set_data(msg->chn->buf, co_data(msg->chn) + *nxt);
+			b_set_data(&msg->chn->buf, co_data(msg->chn) + *nxt);
 		}
 		else {
 			/* Consume all available data and update the next offset
@@ -580,7 +580,7 @@
 	}
 
 	/* Restore the original buffer state */
-	b_set_data(msg->chn->buf, co_data(msg->chn) + buf_i + delta);
+	b_set_data(&msg->chn->buf, co_data(msg->chn) + buf_i + delta);
 
 	return ret;
 }
@@ -981,7 +981,7 @@
 			/* And set this value as the bound for the next
 			 * filter. It will not able to parse more data than the
 			 * current one. */
-			b_set_data(chn->buf, co_data(chn) + *nxt);
+			b_set_data(&chn->buf, co_data(chn) + *nxt);
 		}
 		else {
 			/* Consume all available data */
@@ -995,7 +995,7 @@
 	}
 
 	/* Restore the original buffer state */
-	b_set_data(chn->buf, co_data(chn) + buf_i + delta);
+	b_set_data(&chn->buf, co_data(chn) + buf_i + delta);
 
 	return ret;
 }
diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
index f54feb2..86d0866 100644
--- a/src/flt_http_comp.c
+++ b/src/flt_http_comp.c
@@ -36,8 +36,8 @@
 /* Pools used to allocate comp_state structs */
 static struct pool_head *pool_head_comp_state = NULL;
 
-static THREAD_LOCAL struct buffer *tmpbuf = &buf_empty;
-static THREAD_LOCAL struct buffer *zbuf   = &buf_empty;
+static THREAD_LOCAL struct buffer tmpbuf;
+static THREAD_LOCAL struct buffer zbuf;
 static THREAD_LOCAL unsigned int buf_output;
 
 struct comp_state {
@@ -63,16 +63,16 @@
 					    int in_out,
 					    struct buffer *out, int sz);
 static int http_compression_buffer_end(struct comp_state *st, struct stream *s,
-				       struct channel *chn, struct buffer **out,
+				       struct channel *chn, struct buffer *out,
 				       unsigned int *out_len, int end);
 
 /***********************************************************************/
 static int
 comp_flt_init_per_thread(struct proxy *px, struct flt_conf *fconf)
 {
-	if (!tmpbuf->size && b_alloc(&tmpbuf) == NULL)
+	if (!tmpbuf.size && b_alloc(&tmpbuf) == NULL)
 		return -1;
-	if (!zbuf->size && b_alloc(&zbuf) == NULL)
+	if (!zbuf.size && b_alloc(&zbuf) == NULL)
 		return -1;
 	return 0;
 }
@@ -80,9 +80,9 @@
 static void
 comp_flt_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
 {
-	if (tmpbuf->size)
+	if (tmpbuf.size)
 		b_free(&tmpbuf);
-	if (zbuf->size)
+	if (zbuf.size)
 		b_free(&zbuf);
 }
 
@@ -191,9 +191,9 @@
 	if (!st->initialized) {
 		unsigned int fwd = flt_rsp_fwd(filter) + st->hdrs_len;
 
-		b_reset(tmpbuf);
+		b_reset(&tmpbuf);
 		c_adv(chn, fwd);
-		ret = http_compression_buffer_init(chn, zbuf, &buf_output);
+		ret = http_compression_buffer_init(chn, &zbuf, &buf_output);
 		c_rew(chn, fwd);
 		if (ret < 0) {
 			msg->chn->flags |= CF_WAKE_WRITE;
@@ -204,21 +204,21 @@
 	if (msg->flags & HTTP_MSGF_TE_CHNK) {
 		int block;
 
-		len = MIN(b_room(tmpbuf), len);
+		len = MIN(b_room(&tmpbuf), len);
 
 		c_adv(chn, *nxt);
 		block = ci_contig_data(chn);
-		memcpy(b_tail(tmpbuf), ci_head(chn), block);
+		memcpy(b_tail(&tmpbuf), ci_head(chn), block);
 		if (len > block)
-			memcpy(b_tail(tmpbuf)+block, b_orig(chn->buf), len-block);
+			memcpy(b_tail(&tmpbuf)+block, b_orig(&chn->buf), len-block);
 		c_rew(chn, *nxt);
 
-		b_add(tmpbuf, len);
+		b_add(&tmpbuf, len);
 		ret        = len;
 	}
 	else {
 		c_adv(chn, *nxt);
-		ret = http_compression_buffer_add_data(st, chn->buf, co_data(chn), zbuf, len);
+		ret = http_compression_buffer_add_data(st, &chn->buf, co_data(chn), &zbuf, len);
 		c_rew(chn, *nxt);
 		if (ret < 0)
 			return ret;
@@ -242,9 +242,9 @@
 			struct channel *chn = msg->chn;
 			unsigned int   fwd = flt_rsp_fwd(filter) + st->hdrs_len;
 
-			b_reset(tmpbuf);
+			b_reset(&tmpbuf);
 			c_adv(chn, fwd);
-			http_compression_buffer_init(chn, zbuf, &buf_output);
+			http_compression_buffer_init(chn, &zbuf, &buf_output);
 			c_rew(chn, fwd);
 			st->initialized = 1;
 		}
@@ -298,11 +298,11 @@
 	}
 
 	if (msg->flags & HTTP_MSGF_TE_CHNK) {
-		ret = http_compression_buffer_add_data(st, tmpbuf, 0,
-		    zbuf, b_data(tmpbuf));
-		if (ret != b_data(tmpbuf)) {
+		ret = http_compression_buffer_add_data(st, &tmpbuf, 0,
+		    &zbuf, b_data(&tmpbuf));
+		if (ret != b_data(&tmpbuf)) {
 			ha_warning("HTTP compression failed: Must consume %u bytes but only %d bytes consumed\n",
-				   (unsigned int)b_data(tmpbuf), ret);
+				   (unsigned int)b_data(&tmpbuf), ret);
 			return -1;
 		}
 	}
@@ -668,10 +668,10 @@
  */
 static int
 http_compression_buffer_end(struct comp_state *st, struct stream *s,
-			    struct channel *chn, struct buffer **out,
+			    struct channel *chn, struct buffer *out,
 			    unsigned int *buf_out, int end)
 {
-	struct buffer *ob = *out;
+	struct buffer tmp_buf;
 	char *tail;
 	int   to_forward, left;
 	unsigned int tmp_out;
@@ -681,22 +681,22 @@
 
 	/* flush data here */
 	if (end)
-		ret = st->comp_algo->finish(st->comp_ctx, ob); /* end of data */
+		ret = st->comp_algo->finish(st->comp_ctx, out); /* end of data */
 	else
-		ret = st->comp_algo->flush(st->comp_ctx, ob); /* end of buffer */
+		ret = st->comp_algo->flush(st->comp_ctx, out); /* end of buffer */
 
 	if (ret < 0)
 		return -1; /* flush failed */
 
 #endif /* USE_ZLIB */
-	if (b_data(ob) == 0) {
+	if (b_data(out) == 0) {
 		/* No data were appended, let's drop the output buffer and
 		 * keep the input buffer unchanged.
 		 */
 		return 0;
 	}
 
-	/* OK so at this stage, we have an output buffer <ob> looking like this :
+	/* OK so at this stage, we have an output buffer <out> looking like this :
 	 *
 	 *        <-- o --> <------ i ----->
 	 *       +---------+---+------------+-----------+
@@ -705,7 +705,7 @@
 	 *     data        p                           size
 	 *
 	 * <out> is the room reserved to copy the channel output. It starts at
-	 * ob->area and has not yet been filled. <c> is the room reserved to
+	 * out->area and has not yet been filled. <c> is the room reserved to
 	 * write the chunk size (10 bytes). <comp_in> is the compressed
 	 * equivalent of the data part of ib->len. <empty> is the amount of
 	 * empty bytes at the end of  the buffer, into which we may have to
@@ -714,28 +714,28 @@
 	 */
 
 	/* Write real size at the begining of the chunk, no need of wrapping.
-	 * We write the chunk using a dynamic length and adjust ob->p and ob->i
+	 * We write the chunk using a dynamic length and adjust out->p and out->i
 	 * accordingly afterwards. That will move <out> away from <data>.
 	 */
-	left = http_emit_chunk_size(b_head(ob), b_data(ob));
-	b_add(ob, left);
-	ob->head -= *buf_out + (left);
-	/* Copy previous data from chn into ob */
+	left = http_emit_chunk_size(b_head(out), b_data(out));
+	b_add(out, left);
+	out->head -= *buf_out + (left);
+	/* Copy previous data from chn into out */
 	if (co_data(chn) > 0) {
-		left = b_contig_data(chn->buf, 0);
+		left = b_contig_data(&chn->buf, 0);
 		if (left > *buf_out)
 			left = *buf_out;
 
-		memcpy(b_head(ob), co_head(chn), left);
-		b_add(ob, left);
+		memcpy(b_head(out), co_head(chn), left);
+		b_add(out, left);
 		if (co_data(chn) - left) {/* second part of the buffer */
-			memcpy(b_head(ob) + left, b_orig(chn->buf), co_data(chn) - left);
-			b_add(ob, co_data(chn) - left);
+			memcpy(b_head(out) + left, b_orig(&chn->buf), co_data(chn) - left);
+			b_add(out, co_data(chn) - left);
 		}
 	}
 
 	/* chunked encoding requires CRLF after data */
-	tail = b_tail(ob);
+	tail = b_tail(out);
 	*tail++ = '\r';
 	*tail++ = '\n';
 
@@ -757,8 +757,8 @@
 		}
 	}
 
-	b_add(ob, tail - b_tail(ob));
-	to_forward = b_data(ob) - *buf_out;
+	b_add(out, tail - b_tail(out));
+	to_forward = b_data(out) - *buf_out;
 
 	/* update input rate */
 	if (st->comp_ctx && st->comp_ctx->cur_lvl > 0) {
@@ -772,18 +772,20 @@
 
 	/* copy the remaining data in the tmp buffer. */
 	c_adv(chn, st->consumed);
-	if (b_data(chn->buf) - co_data(chn) > 0) {
+	if (b_data(&chn->buf) - co_data(chn) > 0) {
 		left = ci_contig_data(chn);
-		memcpy(b_tail(ob), ci_head(chn), left);
-		b_add(ob, left);
-		if (b_data(chn->buf) - (co_data(chn) + left)) {
-			memcpy(b_tail(ob), b_orig(chn->buf), b_data(chn->buf) - left);
-			b_add(ob, b_data(chn->buf) - left);
+		memcpy(b_tail(out), ci_head(chn), left);
+		b_add(out, left);
+		if (b_data(&chn->buf) - (co_data(chn) + left)) {
+			memcpy(b_tail(out), b_orig(&chn->buf), b_data(&chn->buf) - left);
+			b_add(out, b_data(&chn->buf) - left);
 		}
 	}
 	/* swap the buffers */
-	*out = chn->buf;
-	chn->buf = ob;
+	tmp_buf = chn->buf;
+	chn->buf = *out;
+	*out = tmp_buf;
+
 	tmp_out = chn->output;
 	chn->output = *buf_out;
 	*buf_out = tmp_out;
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 2a4f05e..b0f25fa 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -105,8 +105,8 @@
 struct flt_ops spoe_ops;
 
 static int  spoe_queue_context(struct spoe_context *ctx);
-static int  spoe_acquire_buffer(struct buffer **buf, struct buffer_wait *buffer_wait);
-static void spoe_release_buffer(struct buffer **buf, struct buffer_wait *buffer_wait);
+static int  spoe_acquire_buffer(struct buffer *buf, struct buffer_wait *buffer_wait);
+static void spoe_release_buffer(struct buffer *buf, struct buffer_wait *buffer_wait);
 
 /********************************************************************
  * helper functions/globals
@@ -573,10 +573,10 @@
 		goto too_big;
 
 	/* Copy encoded messages, if possible */
-	sz = b_data(ctx->buffer);
+	sz = b_data(&ctx->buffer);
 	if (p + sz >= end)
 		goto too_big;
-	memcpy(p, b_head(ctx->buffer), sz);
+	memcpy(p, b_head(&ctx->buffer), sz);
 	p += sz;
 
 	return (p - frame);
@@ -633,10 +633,10 @@
 		goto end;
 
 	/* Copy encoded messages, if possible */
-	sz = b_data(ctx->buffer);
+	sz = b_data(&ctx->buffer);
 	if (p + sz >= end)
 		goto too_big;
-	memcpy(p, b_head(ctx->buffer), sz);
+	memcpy(p, b_head(&ctx->buffer), sz);
 	p += sz;
 
   end:
@@ -1044,13 +1044,13 @@
 
 	/* Copy encoded actions */
 	len = (end - p);
-	memcpy(b_head(SPOE_APPCTX(appctx)->buffer), p, len);
-	b_set_data(SPOE_APPCTX(appctx)->buffer, len);
+	memcpy(b_head(&SPOE_APPCTX(appctx)->buffer), p, len);
+	b_set_data(&SPOE_APPCTX(appctx)->buffer, len);
 	p += len;
 
 	/* Transfer the buffer ownership to the SPOE context */
 	(*ctx)->buffer = SPOE_APPCTX(appctx)->buffer;
-	SPOE_APPCTX(appctx)->buffer = &buf_empty;
+	SPOE_APPCTX(appctx)->buffer = BUF_NULL;
 
 	(*ctx)->state = SPOE_CTX_ST_DONE;
 
@@ -1154,7 +1154,7 @@
 	memcpy(buf, (char *)&netint, 4);
 	ret = ci_putblk(si_ic(si), buf, framesz+4);
 	if (ret <= 0) {
-		if ((ret == -3 && si_ic(si)->buf == &buf_empty) || ret == -1) {
+		if ((ret == -3 && b_is_null(&si_ic(si)->buf)) || ret == -1) {
 			si_applet_cant_put(si);
 			return 1; /* retry */
 		}
@@ -1976,7 +1976,7 @@
 	SPOE_APPCTX(appctx)->max_frame_size  = conf->agent->max_frame_size;
 	SPOE_APPCTX(appctx)->flags           = 0;
 	SPOE_APPCTX(appctx)->status_code     = SPOE_FRM_ERR_NONE;
-	SPOE_APPCTX(appctx)->buffer          = &buf_empty;
+	SPOE_APPCTX(appctx)->buffer          = BUF_NULL;
 	SPOE_APPCTX(appctx)->cur_fpa         = 0;
 
 	LIST_INIT(&SPOE_APPCTX(appctx)->buffer_wait.list);
@@ -2212,7 +2212,7 @@
 	struct spoe_message *msg;
 	char   *p, *end;
 
-	p   = b_head(ctx->buffer);
+	p   = b_head(&ctx->buffer);
 	end =  p + agent->rt[tid].frame_size - FRAME_HDR_SIZE;
 
 	if (type == SPOE_MSGS_BY_EVENT) { /* Loop on messages by event */
@@ -2254,7 +2254,7 @@
 
 
 	/* nothing has been encoded for an unfragmented payload */
-	if (!(ctx->flags & SPOE_CTX_FL_FRAGMENTED) && p == b_head(ctx->buffer))
+	if (!(ctx->flags & SPOE_CTX_FL_FRAGMENTED) && p == b_head(&ctx->buffer))
 		goto skip;
 
 	SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
@@ -2266,7 +2266,7 @@
 		    ctx->spoe_appctx, (agent->rt[tid].frame_size - FRAME_HDR_SIZE),
 		    p - ctx->buffer->p);
 
-	b_set_data(ctx->buffer, p - b_head(ctx->buffer));
+	b_set_data(&ctx->buffer, p - b_head(&ctx->buffer));
 	ctx->frag_ctx.curmsg = NULL;
 	ctx->frag_ctx.curarg = NULL;
 	ctx->frag_ctx.curoff = 0;
@@ -2287,9 +2287,9 @@
 		    (int)now.tv_sec, (int)now.tv_usec,
 		    agent->id, __FUNCTION__, s, ctx->spoe_appctx,
 		    ctx->frag_ctx.curmsg, ctx->frag_ctx.curarg, ctx->frag_ctx.curoff,
-		    (agent->rt[tid].frame_size - FRAME_HDR_SIZE), p - b_head(ctx->buffer));
+		    (agent->rt[tid].frame_size - FRAME_HDR_SIZE), p - b_head(&ctx->buffer));
 
-	b_set_data(ctx->buffer, p - b_head(ctx->buffer));
+	b_set_data(&ctx->buffer, p - b_head(&ctx->buffer));
 	ctx->flags |= SPOE_CTX_FL_FRAGMENTED;
 	ctx->frag_ctx.flags &= ~SPOE_FRM_FL_FIN;
 	return 1;
@@ -2445,8 +2445,8 @@
 	char *p, *end;
 	int   ret;
 
-	p   = b_head(ctx->buffer);
-	end = p + b_data(ctx->buffer);
+	p   = b_head(&ctx->buffer);
+	end = p + b_data(&ctx->buffer);
 
 	while (p < end)  {
 		enum spoe_action_type type;
@@ -2809,9 +2809,9 @@
  * Functions that create/destroy SPOE contexts
  **************************************************************************/
 static int
-spoe_acquire_buffer(struct buffer **buf, struct buffer_wait *buffer_wait)
+spoe_acquire_buffer(struct buffer *buf, struct buffer_wait *buffer_wait)
 {
-	if ((*buf)->size)
+	if (buf->size)
 		return 1;
 
 	if (!LIST_ISEMPTY(&buffer_wait->list)) {
@@ -2831,7 +2831,7 @@
 }
 
 static void
-spoe_release_buffer(struct buffer **buf, struct buffer_wait *buffer_wait)
+spoe_release_buffer(struct buffer *buf, struct buffer_wait *buffer_wait)
 {
 	if (!LIST_ISEMPTY(&buffer_wait->list)) {
 		HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
@@ -2841,7 +2841,7 @@
 	}
 
 	/* Release the buffer if needed */
-	if ((*buf)->size) {
+	if (buf->size) {
 		b_free(buf);
 		offer_buffers(buffer_wait->target, tasks_run_queue);
 	}
@@ -2871,7 +2871,7 @@
 	ctx->flags       = 0;
 	ctx->events      = conf->agent->events;
 	ctx->groups      = &conf->agent->groups;
-	ctx->buffer      = &buf_empty;
+	ctx->buffer      = BUF_NULL;
 	LIST_INIT(&ctx->buffer_wait.list);
 	ctx->buffer_wait.target = ctx;
 	ctx->buffer_wait.wakeup_cb = (int (*)(void *))spoe_wakeup_context;
diff --git a/src/flt_trace.c b/src/flt_trace.c
index 0115129..5d24a41 100644
--- a/src/flt_trace.c
+++ b/src/flt_trace.c
@@ -466,7 +466,7 @@
 
 	if (conf->hexdump) {
 		c_adv(msg->chn, FLT_FWD(filter, msg->chn));
-		trace_hexdump(msg->chn->buf, ret, co_data(msg->chn));
+		trace_hexdump(&msg->chn->buf, ret, co_data(msg->chn));
 		c_rew(msg->chn, FLT_FWD(filter, msg->chn));
 	}
 
@@ -516,7 +516,7 @@
 
 	if (conf->hexdump) {
 		c_adv(chn, FLT_FWD(filter, chn));
-		trace_hexdump(chn->buf, ret, co_data(chn));
+		trace_hexdump(&chn->buf, ret, co_data(chn));
 		c_rew(chn, FLT_FWD(filter, chn));
 	}
 
diff --git a/src/h1.c b/src/h1.c
index 7e19679..0d41d0b 100644
--- a/src/h1.c
+++ b/src/h1.c
@@ -461,7 +461,7 @@
 	struct buffer *buf;
 
 	state = msg->msg_state;
-	buf = msg->chn->buf;
+	buf = &msg->chn->buf;
 	ptr = input + msg->next;
 	end = b_stop(buf);
 
@@ -1276,7 +1276,7 @@
  */
 int http_forward_trailers(struct http_msg *msg)
 {
-	const struct buffer *buf = msg->chn->buf;
+	const struct buffer *buf = &msg->chn->buf;
 	const char *parse = ci_head(msg->chn);
 	const char *stop  = b_tail(buf);
 
diff --git a/src/haproxy.c b/src/haproxy.c
index e19d89a..768034a 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2204,10 +2204,10 @@
 
 			free(s->id);
 			free(s->cookie);
-			free(s->check.bi);
-			free(s->check.bo);
-			free(s->agent.bi);
-			free(s->agent.bo);
+			free(s->check.bi.area);
+			free(s->check.bo.area);
+			free(s->agent.bi.area);
+			free(s->agent.bo.area);
 			free(s->agent.send_string);
 			free(s->hostname_dn);
 			free((char*)s->conf.file);
diff --git a/src/hlua.c b/src/hlua.c
index 3fd4d15..32cb66d 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2019,13 +2019,13 @@
 	/* Check if the buffer is avalaible because HAProxy doesn't allocate
 	 * the request buffer if its not required.
 	 */
-	if (s->req.buf->size == 0) {
+	if (s->req.buf.size == 0) {
 		if (!channel_alloc_buffer(&s->req, &appctx->buffer_wait))
 			goto hlua_socket_write_yield_return;
 	}
 
 	/* Check for avalaible space. */
-	len = b_room(s->req.buf);
+	len = b_room(&s->req.buf);
 	if (len <= 0) {
 		goto hlua_socket_write_yield_return;
 	}
@@ -2840,7 +2840,7 @@
 	if (unlikely(ret == -1))
 		return 1;
 
-	b_sub(chn->buf, ret);
+	b_sub(&chn->buf, ret);
 	hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
 	return 1;
 }
@@ -2888,7 +2888,7 @@
 		len += len2;
 	}
 	luaL_pushresult(&b);
-	b_rep_blk(chn->buf, ci_head(chn), ci_head(chn) + len,  NULL, 0);
+	b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn) + len,  NULL, 0);
 	hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
 	return 1;
 }
@@ -2920,12 +2920,12 @@
 	/* Check if the buffer is avalaible because HAProxy doesn't allocate
 	 * the request buffer if its not required.
 	 */
-	if (chn->buf->size == 0) {
+	if (chn->buf.size == 0) {
 		si_applet_cant_put(chn_prod(chn));
 		WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
 	}
 
-	max = channel_recv_limit(chn) - b_data(chn->buf);
+	max = channel_recv_limit(chn) - b_data(&chn->buf);
 	if (max > len - l)
 		max = len - l;
 
@@ -2943,7 +2943,7 @@
 	lua_pushinteger(L, l);
 	hlua_resynchonize_proto(chn_strm(chn), !!(chn->flags & CF_ISRESP));
 
-	max = channel_recv_limit(chn) - b_data(chn->buf);
+	max = channel_recv_limit(chn) - b_data(&chn->buf);
 	if (max == 0 && co_data(chn) == 0) {
 		/* There are no space avalaible, and the output buffer is empty.
 		 * in this case, we cannot add more data, so we cannot yield,
@@ -2987,7 +2987,7 @@
 	chn = MAY_LJMP(hlua_checkchannel(L, 1));
 	lua_pushinteger(L, 0);
 
-	b_set_data(chn->buf, co_data(chn));
+	b_set_data(&chn->buf, co_data(chn));
 
 	return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
 }
@@ -3014,7 +3014,7 @@
 	/* Check if the buffer is avalaible because HAProxy doesn't allocate
 	 * the request buffer if its not required.
 	 */
-	if (chn->buf->size == 0) {
+	if (chn->buf.size == 0) {
 		si_applet_cant_put(chn_prod(chn));
 		WILL_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
 	}
@@ -3024,7 +3024,7 @@
 	 * The reserve is guaranted for the processing of incoming
 	 * data, because the buffer will be flushed.
 	 */
-	max = b_room(chn->buf);
+	max = b_room(&chn->buf);
 
 	/* If there are no space avalaible, and the output buffer is empty.
 	 * in this case, we cannot add more data, so we cannot yield,
@@ -3044,7 +3044,7 @@
 		channel_slow_realign(chn, trash.str);
 
 	/* Copy input data in the buffer. */
-	max = b_rep_blk(chn->buf, ci_head(chn), ci_head(chn), str + l, max);
+	max = b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn), str + l, max);
 
 	/* buffer replace considers that the input part is filled.
 	 * so, I must forward these new data in the output part.
@@ -3059,7 +3059,7 @@
 	 * in this case, we cannot add more data, so we cannot yield,
 	 * we return the amount of copyied data.
 	 */
-	max = b_room(chn->buf);
+	max = b_room(&chn->buf);
 	if (max == 0 && co_data(chn) == 0)
 		return 1;
 
@@ -3177,7 +3177,7 @@
 	MAY_LJMP(check_args(L, 1, "is_full"));
 	chn = MAY_LJMP(hlua_checkchannel(L, 1));
 
-	rem = b_room(chn->buf);
+	rem = b_room(&chn->buf);
 	rem -= global.tune.maxrewrite; /* Rewrite reserved size */
 
 	lua_pushboolean(L, rem <= 0);
@@ -5405,7 +5405,7 @@
 
 	if (htxn->s->txn) {
 		/* HTTP mode, let's stay in sync with the stream */
-		b_del(ic->buf, htxn->s->txn->req.sov);
+		b_del(&ic->buf, htxn->s->txn->req.sov);
 		htxn->s->txn->req.next -= htxn->s->txn->req.sov;
 		htxn->s->txn->req.sov = 0;
 		ic->analysers &= AN_REQ_HTTP_XFER_BODY;
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 8bb6c6c..35c7865 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -90,7 +90,7 @@
 
 	/* states for the demux direction */
 	struct hpack_dht *ddht; /* demux dynamic header table */
-	struct buffer *dbuf;    /* demux buffer */
+	struct buffer dbuf;    /* demux buffer */
 
 	int32_t dsi; /* demux stream ID (<0 = idle) */
 	int32_t dfl; /* demux frame length (if dsi >= 0) */
@@ -101,7 +101,7 @@
 	int32_t last_sid; /* last processed stream ID for GOAWAY, <0 before preface */
 
 	/* states for the mux direction */
-	struct buffer *mbuf;    /* mux buffer */
+	struct buffer mbuf;    /* mux buffer */
 	int32_t msi; /* mux stream ID (<0 = idle) */
 	int32_t mfl; /* mux frame length (if dsi >= 0) */
 	int8_t  mft; /* mux frame type   (if dsi >= 0) */
@@ -239,7 +239,7 @@
  */
 static inline int h2_recv_allowed(const struct h2c *h2c)
 {
-	if (b_data(h2c->dbuf) == 0 &&
+	if (b_data(&h2c->dbuf) == 0 &&
 	    (h2c->st0 >= H2_CS_ERROR ||
 	     h2c->conn->flags & CO_FL_ERROR ||
 	     conn_xprt_read0_pending(h2c->conn)))
@@ -289,7 +289,7 @@
 	return 0;
 }
 
-static inline struct buffer *h2_get_buf(struct h2c *h2c, struct buffer **bptr)
+static inline struct buffer *h2_get_buf(struct h2c *h2c, struct buffer *bptr)
 {
 	struct buffer *buf = NULL;
 
@@ -305,9 +305,9 @@
 	return buf;
 }
 
-static inline void h2_release_buf(struct h2c *h2c, struct buffer **bptr)
+static inline void h2_release_buf(struct h2c *h2c, struct buffer *bptr)
 {
-	if ((*bptr)->size) {
+	if (bptr->size) {
 		b_free(bptr);
 		offer_buffers(h2c->buf_wait.target, tasks_run_queue);
 	}
@@ -361,12 +361,12 @@
 	h2c->nb_streams = 0;
 	h2c->nb_cs = 0;
 
-	h2c->dbuf = &buf_empty;
+	h2c->dbuf = BUF_NULL;
 	h2c->dsi = -1;
 	h2c->msi = -1;
 	h2c->last_sid = -1;
 
-	h2c->mbuf = &buf_empty;
+	h2c->mbuf = BUF_NULL;
 	h2c->miw = 65535; /* mux initial window size */
 	h2c->mws = 65535; /* mux window size */
 	h2c->mfs = 16384; /* initial max frame size */
@@ -752,7 +752,7 @@
 	int ret1;
 	int ret2;
 
-	ret1 = b_isteq(h2c->dbuf, 0, b_data(h2c->dbuf), ist(H2_CONN_PREFACE));
+	ret1 = b_isteq(&h2c->dbuf, 0, b_data(&h2c->dbuf), ist(H2_CONN_PREFACE));
 
 	if (unlikely(ret1 <= 0)) {
 		if (ret1 < 0 || conn_xprt_read0_pending(h2c->conn))
@@ -762,7 +762,7 @@
 
 	ret2 = h2c_snd_settings(h2c);
 	if (ret2 > 0)
-		b_del(h2c->dbuf, ret1);
+		b_del(&h2c->dbuf, ret1);
 
 	return ret2;
 }
@@ -1109,13 +1109,13 @@
 	}
 
 	/* process full frame only */
-	if (b_data(h2c->dbuf) < h2c->dfl)
+	if (b_data(&h2c->dbuf) < h2c->dfl)
 		return 0;
 
 	/* parse the frame */
 	for (offset = 0; offset < h2c->dfl; offset += 6) {
-		uint16_t type = h2_get_n16(h2c->dbuf, offset);
-		int32_t  arg  = h2_get_n32(h2c->dbuf, offset + 2);
+		uint16_t type = h2_get_n16(&h2c->dbuf, offset);
+		int32_t  arg  = h2_get_n32(&h2c->dbuf, offset + 2);
 
 		switch (type) {
 		case H2_SETTINGS_INITIAL_WINDOW_SIZE:
@@ -1302,7 +1302,7 @@
 	char str[17];
 	int ret = -1;
 
-	if (b_data(h2c->dbuf) < 8)
+	if (b_data(&h2c->dbuf) < 8)
 		return 0;
 
 	if (h2c_mux_busy(h2c, NULL)) {
@@ -1323,7 +1323,7 @@
 	       "\x00\x00\x00\x00" /* stream ID */, 9);
 
 	/* copy the original payload */
-	h2_get_buf_bytes(str + 9, 8, h2c->dbuf, 0);
+	h2_get_buf_bytes(str + 9, 8, &h2c->dbuf, 0);
 
 	ret = b_istput(res, ist2(str, 17));
 	if (unlikely(ret <= 0)) {
@@ -1355,10 +1355,10 @@
 	}
 
 	/* process full frame only */
-	if (b_data(h2c->dbuf) < h2c->dfl)
+	if (b_data(&h2c->dbuf) < h2c->dfl)
 		return 0;
 
-	inc = h2_get_n32(h2c->dbuf, 0);
+	inc = h2_get_n32(&h2c->dbuf, 0);
 
 	if (h2c->dsi != 0) {
 		/* stream window update */
@@ -1441,11 +1441,11 @@
 	}
 
 	/* process full frame only */
-	if (b_data(h2c->dbuf) < h2c->dfl)
+	if (b_data(&h2c->dbuf) < h2c->dfl)
 		return 0;
 
-	last = h2_get_n32(h2c->dbuf, 0);
-	h2c->errcode = h2_get_n32(h2c->dbuf, 4);
+	last = h2_get_n32(&h2c->dbuf, 0);
+	h2c->errcode = h2_get_n32(&h2c->dbuf, 4);
 	h2_wake_some_streams(h2c, last, CS_FL_ERROR);
 	if (h2c->last_sid < 0)
 		h2c->last_sid = last;
@@ -1475,10 +1475,10 @@
 	}
 
 	/* process full frame only */
-	if (b_data(h2c->dbuf) < h2c->dfl)
+	if (b_data(&h2c->dbuf) < h2c->dfl)
 		return 0;
 
-	if (h2_get_n32(h2c->dbuf, 0) == h2c->dsi) {
+	if (h2_get_n32(&h2c->dbuf, 0) == h2c->dsi) {
 		/* 7540#5.3 : can't depend on itself */
 		error = H2_ERR_PROTOCOL_ERROR;
 		goto conn_err;
@@ -1509,14 +1509,14 @@
 	}
 
 	/* process full frame only */
-	if (b_data(h2c->dbuf) < h2c->dfl)
+	if (b_data(&h2c->dbuf) < h2c->dfl)
 		return 0;
 
 	/* late RST, already handled */
 	if (h2s->st == H2_SS_CLOSED)
 		return 1;
 
-	h2s->errcode = h2_get_n32(h2c->dbuf, 0);
+	h2s->errcode = h2_get_n32(&h2c->dbuf, 0);
 	h2s_close(h2s);
 
 	if (h2s->cs) {
@@ -1550,10 +1550,10 @@
 		goto strm_err;
 	}
 
-	if (!b_size(h2c->dbuf))
+	if (!b_size(&h2c->dbuf))
 		return 0; // empty buffer
 
-	if (b_data(h2c->dbuf) < h2c->dfl && !b_full(h2c->dbuf))
+	if (b_data(&h2c->dbuf) < h2c->dfl && !b_full(&h2c->dbuf))
 		return 0; // incomplete frame
 
 	if (h2c->flags & H2_CF_DEM_TOOMANY)
@@ -1636,10 +1636,10 @@
 	 * to signal an end of stream (with the ES flag).
 	 */
 
-	if (!b_size(h2c->dbuf) && h2c->dfl)
+	if (!b_size(&h2c->dbuf) && h2c->dfl)
 		return 0; // empty buffer
 
-	if (b_data(h2c->dbuf) < h2c->dfl && !b_full(h2c->dbuf))
+	if (b_data(&h2c->dbuf) < h2c->dfl && !b_full(&h2c->dbuf))
 		return 0; // incomplete frame
 
 	/* now either the frame is complete or the buffer is complete */
@@ -1736,7 +1736,7 @@
 			/* ensure that what is pending is a valid SETTINGS frame
 			 * without an ACK.
 			 */
-			if (!h2_get_frame_hdr(h2c->dbuf, &hdr)) {
+			if (!h2_get_frame_hdr(&h2c->dbuf, &hdr)) {
 				/* RFC7540#3.5: a GOAWAY frame MAY be omitted */
 				if (h2c->st0 == H2_CS_ERROR)
 					h2c->st0 = H2_CS_ERROR2;
@@ -1768,7 +1768,7 @@
 	}
 
 	/* process as many incoming frames as possible below */
-	while (b_data(h2c->dbuf)) {
+	while (b_data(&h2c->dbuf)) {
 		int ret = 0;
 
 		if (h2c->st0 >= H2_CS_ERROR)
@@ -1777,7 +1777,7 @@
 		if (h2c->st0 == H2_CS_FRAME_H) {
 			struct h2_fh hdr;
 
-			if (!h2_peek_frame_hdr(h2c->dbuf, &hdr))
+			if (!h2_peek_frame_hdr(&h2c->dbuf, &hdr))
 				break;
 
 			if ((int)hdr.len < 0 || (int)hdr.len > global.tune.bufsize) {
@@ -1792,7 +1792,7 @@
 			h2c->dff = hdr.ff;
 			h2c->dpl = 0;
 			h2c->st0 = H2_CS_FRAME_P;
-			h2_skip_frame_hdr(h2c->dbuf);
+			h2_skip_frame_hdr(&h2c->dbuf);
 		}
 
 		/* Only H2_CS_FRAME_P and H2_CS_FRAME_A here */
@@ -1900,8 +1900,8 @@
 		 * the one advertised in GOAWAY. RFC7540#6.8.
 		 */
 		if (unlikely(h2c->last_sid >= 0) && h2c->dsi > h2c->last_sid) {
-			ret = MIN(b_data(h2c->dbuf), h2c->dfl);
-			b_del(h2c->dbuf, ret);
+			ret = MIN(b_data(&h2c->dbuf), h2c->dfl);
+			b_del(&h2c->dbuf, ret);
 			h2c->dfl -= ret;
 			ret = h2c->dfl == 0;
 			goto strm_err;
@@ -1980,8 +1980,8 @@
 			 * the buffer so we drain all of their contents until
 			 * we reach the end.
 			 */
-			ret = MIN(b_data(h2c->dbuf), h2c->dfl);
-			b_del(h2c->dbuf, ret);
+			ret = MIN(b_data(&h2c->dbuf), h2c->dfl);
+			b_del(&h2c->dbuf, ret);
 			h2c->dfl -= ret;
 			ret = h2c->dfl == 0;
 		}
@@ -1999,7 +1999,7 @@
 			break;
 
 		if (h2c->st0 != H2_CS_FRAME_H) {
-			b_del(h2c->dbuf, h2c->dfl);
+			b_del(&h2c->dbuf, h2c->dfl);
 			h2c->st0 = H2_CS_FRAME_H;
 		}
 	}
@@ -2212,12 +2212,12 @@
 		if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MBUSY | H2_CF_DEM_MROOM))
 			flags |= CO_SFL_MSG_MORE;
 
-		if (b_data(h2c->mbuf)) {
-			int ret = conn->xprt->snd_buf(conn, h2c->mbuf, b_data(h2c->mbuf), flags);
+		if (b_data(&h2c->mbuf)) {
+			int ret = conn->xprt->snd_buf(conn, &h2c->mbuf, b_data(&h2c->mbuf), flags);
 			if (!ret)
 				break;
-			b_del(h2c->mbuf, ret);
-			b_realign_if_empty(h2c->mbuf);
+			b_del(&h2c->mbuf, ret);
+			b_realign_if_empty(&h2c->mbuf);
 		}
 
 		/* wrote at least one byte, the buffer is not full anymore */
@@ -2226,7 +2226,7 @@
 
 	if (conn->flags & CO_FL_SOCK_WR_SH) {
 		/* output closed, nothing to send, clear the buffer to release it */
-		b_reset(h2c->mbuf);
+		b_reset(&h2c->mbuf);
 	}
 }
 
@@ -2239,13 +2239,13 @@
 	struct h2c *h2c = conn->mux_ctx;
 	struct session *sess = conn->owner;
 
-	if (b_data(h2c->dbuf) && !(h2c->flags & H2_CF_DEM_BLOCK_ANY)) {
+	if (b_data(&h2c->dbuf) && !(h2c->flags & H2_CF_DEM_BLOCK_ANY)) {
 		h2_process_demux(h2c);
 
 		if (h2c->st0 >= H2_CS_ERROR || conn->flags & CO_FL_ERROR)
-			b_reset(h2c->dbuf);
+			b_reset(&h2c->dbuf);
 
-		if (!b_full(h2c->dbuf))
+		if (!b_full(&h2c->dbuf))
 			h2c->flags &= ~H2_CF_DEM_DFULL;
 	}
 
@@ -2302,7 +2302,7 @@
 		}
 	}
 
-	if (!b_data(h2c->dbuf))
+	if (!b_data(&h2c->dbuf))
 		h2_release_buf(h2c, &h2c->dbuf);
 
 	/* stop being notified of incoming data if we can't process them */
@@ -2316,7 +2316,7 @@
 	/* adjust output polling */
 	if (!(conn->flags & CO_FL_SOCK_WR_SH) &&
 	    (h2c->st0 == H2_CS_ERROR ||
-	     b_data(h2c->mbuf) ||
+	     b_data(&h2c->mbuf) ||
 	     (h2c->mws > 0 && !LIST_ISEMPTY(&h2c->fctl_list)) ||
 	     (!(h2c->flags & H2_CF_MUX_BLOCK_ANY) && !LIST_ISEMPTY(&h2c->send_list)))) {
 		__conn_xprt_want_send(conn);
@@ -2327,7 +2327,7 @@
 	}
 
 	if (h2c->task) {
-		if (eb_is_empty(&h2c->streams_by_id) || b_data(h2c->mbuf)) {
+		if (eb_is_empty(&h2c->streams_by_id) || b_data(&h2c->mbuf)) {
 			h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
 			task_queue(h2c->task);
 		}
@@ -2363,7 +2363,7 @@
 	h2c_error(h2c, H2_ERR_NO_ERROR);
 	h2_wake_some_streams(h2c, 0, 0);
 
-	if (b_data(h2c->mbuf)) {
+	if (b_data(&h2c->mbuf)) {
 		/* don't even try to send a GOAWAY, the buffer is stuck */
 		h2c->flags |= H2_CF_GOAWAY_FAILED;
 	}
@@ -2373,11 +2373,11 @@
 	if (h2c_send_goaway_error(h2c, NULL) <= 0)
 		h2c->flags |= H2_CF_GOAWAY_FAILED;
 
-	if (b_data(h2c->mbuf) && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn)) {
-		int ret = h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, b_data(h2c->mbuf), 0);
+	if (b_data(&h2c->mbuf) && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn)) {
+		int ret = h2c->conn->xprt->snd_buf(h2c->conn, &h2c->mbuf, b_data(&h2c->mbuf), 0);
 		if (ret > 0) {
-			b_del(h2c->mbuf, ret);
-			b_realign_if_empty(h2c->mbuf);
+			b_del(&h2c->mbuf, ret);
+			b_realign_if_empty(&h2c->mbuf);
 		}
 	}
 
@@ -2436,7 +2436,7 @@
 	if (cs->flags & CS_FL_DATA_WR_ENA) {
 		if (LIST_ISEMPTY(&h2s->list)) {
 			if (LIST_ISEMPTY(&h2s->h2c->send_list) &&
-			    !b_data(h2s->h2c->mbuf) && // not yet subscribed
+			    !b_data(&h2s->h2c->mbuf) && // not yet subscribed
 			    !(cs->conn->flags & CO_FL_SOCK_WR_SH))
 				conn_xprt_want_send(cs->conn);
 			LIST_ADDQ(&h2s->h2c->send_list, &h2s->list);
@@ -2449,7 +2449,7 @@
 	}
 
 	/* this can happen from within si_chk_snd() */
-	if (b_data(h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
+	if (b_data(&h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
 		conn_xprt_want_send(cs->conn);
 }
 
@@ -2506,14 +2506,14 @@
 	    ((h2c->conn->flags & CO_FL_ERROR) ||    /* errors close immediately */
 	     (h2c->st0 >= H2_CS_ERROR && !h2c->task) || /* a timeout stroke earlier */
 	     (h2c->flags & H2_CF_GOAWAY_FAILED) ||
-	     (!b_data(h2c->mbuf) &&  /* mux buffer empty, also process clean events below */
+	     (!b_data(&h2c->mbuf) &&  /* mux buffer empty, also process clean events below */
 	      (conn_xprt_read0_pending(h2c->conn) ||
 	       (h2c->last_sid >= 0 && h2c->max_id >= h2c->last_sid))))) {
 		/* no more stream will come, kill it now */
 		h2_release(h2c->conn);
 	}
 	else if (h2c->task) {
-		if (eb_is_empty(&h2c->streams_by_id) || b_data(h2c->mbuf)) {
+		if (eb_is_empty(&h2c->streams_by_id) || b_data(&h2c->mbuf)) {
 			h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout);
 			task_queue(h2c->task);
 		}
@@ -2546,7 +2546,7 @@
 	    h2c_send_goaway_error(h2s->h2c, h2s) <= 0)
 		goto add_to_list;
 
-	if (b_data(h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
+	if (b_data(&h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
 		conn_xprt_want_send(cs->conn);
 
 	h2s_close(h2s);
@@ -2596,7 +2596,7 @@
 		h2s_close(h2s);
 	}
 
-	if (b_data(h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
+	if (b_data(&h2s->h2c->mbuf) && !(cs->conn->flags & CO_FL_XPRT_WR_ENA))
 		conn_xprt_want_send(cs->conn);
 
  add_to_list:
@@ -2616,7 +2616,7 @@
 static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count, int flags)
 {
 	struct h2c *h2c = h2s->h2c;
-	const uint8_t *hdrs = (uint8_t *)b_head(h2c->dbuf);
+	const uint8_t *hdrs = (uint8_t *)b_head(&h2c->dbuf);
 	struct chunk *tmp = get_trash_chunk();
 	struct http_hdr list[MAX_HTTP_HDR * 2];
 	struct chunk *copy = NULL;
@@ -2632,19 +2632,19 @@
 		return 0;
 	}
 
-	if (b_data(h2c->dbuf) < h2c->dfl && !b_full(h2c->dbuf))
+	if (b_data(&h2c->dbuf) < h2c->dfl && !b_full(&h2c->dbuf))
 		return 0; // incomplete input frame
 
 	/* if the input buffer wraps, take a temporary copy of it (rare) */
-	wrap = b_wrap(h2c->dbuf) - b_head(h2c->dbuf);
+	wrap = b_wrap(&h2c->dbuf) - b_head(&h2c->dbuf);
 	if (wrap < h2c->dfl) {
 		copy = alloc_trash_chunk();
 		if (!copy) {
 			h2c_error(h2c, H2_ERR_INTERNAL_ERROR);
 			goto fail;
 		}
-		memcpy(copy->str, b_head(h2c->dbuf), wrap);
-		memcpy(copy->str + wrap, b_orig(h2c->dbuf), h2c->dfl - wrap);
+		memcpy(copy->str, b_head(&h2c->dbuf), wrap);
+		memcpy(copy->str + wrap, b_orig(&h2c->dbuf), h2c->dfl - wrap);
 		hdrs = (uint8_t *)copy->str;
 	}
 
@@ -2734,7 +2734,7 @@
 	}
 
 	/* now consume the input data */
-	b_del(h2c->dbuf, h2c->dfl);
+	b_del(&h2c->dbuf, h2c->dfl);
 	h2c->st0 = H2_CS_FRAME_H;
 	b_add(buf, outlen);
 
@@ -2783,10 +2783,10 @@
 	 * after data. padlen+data+padding are included in flen.
 	 */
 	if (h2c->dff & H2_F_DATA_PADDED) {
-		if (b_data(h2c->dbuf) < 1)
+		if (b_data(&h2c->dbuf) < 1)
 			return 0;
 
-		h2c->dpl = *(uint8_t *)b_head(h2c->dbuf);
+		h2c->dpl = *(uint8_t *)b_head(&h2c->dbuf);
 		if (h2c->dpl >= h2c->dfl) {
 			/* RFC7540#6.1 : pad length = length of frame payload or greater */
 			h2c_error(h2c, H2_ERR_PROTOCOL_ERROR);
@@ -2794,7 +2794,7 @@
 		}
 
 		/* skip the padlen byte */
-		b_del(h2c->dbuf, 1);
+		b_del(&h2c->dbuf, 1);
 		h2c->dfl--;
 		h2c->rcvd_c++; h2c->rcvd_s++;
 		h2c->dff &= ~H2_F_DATA_PADDED;
@@ -2804,8 +2804,8 @@
 	if (!flen)
 		goto end_transfer;
 
-	if (flen > b_data(h2c->dbuf)) {
-		flen = b_data(h2c->dbuf);
+	if (flen > b_data(&h2c->dbuf)) {
+		flen = b_data(&h2c->dbuf);
 		if (!flen)
 			return 0;
 	}
@@ -2844,16 +2844,16 @@
 	/* Block1 is the length of the first block before the buffer wraps,
 	 * block2 is the optional second block to reach the end of the frame.
 	 */
-	block1 = b_contig_data(h2c->dbuf, 0);
+	block1 = b_contig_data(&h2c->dbuf, 0);
 	if (block1 > flen)
 		block1 = flen;
 	block2 = flen - block1;
 
 	if (block1)
-		b_putblk(buf, b_head(h2c->dbuf), block1);
+		b_putblk(buf, b_head(&h2c->dbuf), block1);
 
 	if (block2)
-		b_putblk(buf, b_peek(h2c->dbuf, block1), block2);
+		b_putblk(buf, b_peek(&h2c->dbuf, block1), block2);
 
 	if (h2s->flags & H2_SF_DATA_CHNK) {
 		/* emit the CRLF */
@@ -2863,7 +2863,7 @@
 	/* now mark the input data as consumed (will be deleted from the buffer
 	 * by the caller when seeing FRAME_A after sending the window update).
 	 */
-	b_del(h2c->dbuf, flen);
+	b_del(&h2c->dbuf, flen);
 	h2c->dfl    -= flen;
 	h2c->rcvd_c += flen;
 	h2c->rcvd_s += flen;  // warning, this can also affect the closed streams!
@@ -2926,7 +2926,7 @@
 	if (h2c->dsi != h2s->id)
 		return 0; // not for us
 
-	if (!b_size(h2c->dbuf))
+	if (!b_size(&h2c->dbuf))
 		return 0; // empty buffer
 
 	switch (h2c->dft) {
@@ -2994,14 +2994,14 @@
 	chunk_reset(&outbuf);
 
 	while (1) {
-		outbuf.str  = b_tail(h2c->mbuf);
-		outbuf.size = b_contig_space(h2c->mbuf);
+		outbuf.str  = b_tail(&h2c->mbuf);
+		outbuf.size = b_contig_space(&h2c->mbuf);
 		outbuf.len = 0;
 
-		if (outbuf.size >= 9 || !b_space_wraps(h2c->mbuf))
+		if (outbuf.size >= 9 || !b_space_wraps(&h2c->mbuf))
 			break;
 	realign_again:
-		b_slow_realign(h2c->mbuf, trash.str, b_data(h2c->mbuf));
+		b_slow_realign(&h2c->mbuf, trash.str, b_data(&h2c->mbuf));
 	}
 
 	if (outbuf.size < 9) {
@@ -3036,7 +3036,7 @@
 		outbuf.str[outbuf.len++] = list[0].v.ptr[2];
 	}
 	else {
-		if (b_space_wraps(h2c->mbuf))
+		if (b_space_wraps(&h2c->mbuf))
 			goto realign_again;
 
 		h2c->flags |= H2_CF_MUX_MFULL;
@@ -3060,7 +3060,7 @@
 
 		if (!hpack_encode_header(&outbuf, list[hdr].n, list[hdr].v)) {
 			/* output full */
-			if (b_space_wraps(h2c->mbuf))
+			if (b_space_wraps(&h2c->mbuf))
 				goto realign_again;
 
 			h2c->flags |= H2_CF_MUX_MFULL;
@@ -3084,7 +3084,7 @@
 	max -= ret;
 
 	/* commit the H2 response */
-	b_add(h2c->mbuf, outbuf.len);
+	b_add(&h2c->mbuf, outbuf.len);
 	h2s->flags |= H2_SF_HEADERS_SENT;
 
 	/* for now we don't implemented CONTINUATION, so we wait for a
@@ -3151,14 +3151,14 @@
 	chunk_reset(&outbuf);
 
 	while (1) {
-		outbuf.str  = b_tail(h2c->mbuf);
-		outbuf.size = b_contig_space(h2c->mbuf);
+		outbuf.str  = b_tail(&h2c->mbuf);
+		outbuf.size = b_contig_space(&h2c->mbuf);
 		outbuf.len = 0;
 
-		if (outbuf.size >= 9 || !b_space_wraps(h2c->mbuf))
+		if (outbuf.size >= 9 || !b_space_wraps(&h2c->mbuf))
 			break;
 	realign_again:
-		b_slow_realign(h2c->mbuf, trash.str, b_data(h2c->mbuf));
+		b_slow_realign(&h2c->mbuf, trash.str, b_data(&h2c->mbuf));
 	}
 
 	if (outbuf.size < 9) {
@@ -3256,7 +3256,7 @@
 		/* we have an opportunity for enlarging the too small
 		 * available space, let's try.
 		 */
-		if (b_space_wraps(h2c->mbuf))
+		if (b_space_wraps(&h2c->mbuf))
 			goto realign_again;
 		size = outbuf.size - 9;
 	}
@@ -3329,7 +3329,7 @@
 		outbuf.str[4] |= H2_F_DATA_END_STREAM;
 
 	/* commit the H2 response */
-	b_add(h2c->mbuf, size + 9);
+	b_add(&h2c->mbuf, size + 9);
 
 	/* consume incoming H1 response */
 	if (size > 0) {
@@ -3476,7 +3476,7 @@
 	}
 
 	chunk_appendf(msg, " st0=%d flg=0x%08x nbst=%u nbcs=%u fctl_cnt=%d send_cnt=%d tree_cnt=%d orph_cnt=%d dbuf=%u/%u mbuf=%u/%u",
-		      h2c->st0, h2c->flags, h2c->nb_streams, h2c->nb_cs, fctl_cnt, send_cnt, tree_cnt, orph_cnt, (unsigned int)b_data(h2c->dbuf), (unsigned int)b_size(h2c->dbuf), (unsigned int)b_data(h2c->mbuf), (unsigned int)b_size(h2c->mbuf));
+		      h2c->st0, h2c->flags, h2c->nb_streams, h2c->nb_cs, fctl_cnt, send_cnt, tree_cnt, orph_cnt, (unsigned int)b_data(&h2c->dbuf), (unsigned int)b_size(&h2c->dbuf), (unsigned int)b_data(&h2c->mbuf), (unsigned int)b_size(&h2c->mbuf));
 }
 
 /*******************************************************/
diff --git a/src/payload.c b/src/payload.c
index 3aac561..cf5b883 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -466,8 +466,8 @@
 	 * all the part of the request which fits in a buffer is already
 	 * there.
 	 */
-	if (msg_len > channel_recv_limit(req) + b_orig(req->buf) - ci_head(req))
-		msg_len = channel_recv_limit(req) + b_orig(req->buf) - ci_head(req);
+	if (msg_len > channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req))
+		msg_len = channel_recv_limit(req) + b_orig(&req->buf) - ci_head(req);
 
 	if (bleft < msg_len)
 		goto too_short;
@@ -935,10 +935,10 @@
 	while (1) {
 		if (ofs + 12 > ci_data(chn)) {
 			/* not there yet but could it at least fit ? */
-			if (!chn->buf->size)
+			if (!chn->buf.size)
 				goto too_short;
 
-			if (ofs + 12 <= channel_recv_limit(chn) + b_orig(chn->buf) - ci_head(chn))
+			if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
 				goto too_short;
 
 			goto no_match;
@@ -1011,10 +1011,10 @@
 	ofs = 0; occ = 0;
 	while (1) {
 		if (ofs + 12 > ci_data(chn)) {
-			if (!chn->buf->size)
+			if (!chn->buf.size)
 				goto too_short;
 
-			if (ofs + 12 <= channel_recv_limit(chn) + b_orig(chn->buf) - ci_head(chn))
+			if (ofs + 12 <= channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn))
 				goto too_short;
 
 			goto no_match;
@@ -1048,13 +1048,13 @@
 				smp->data.type = SMP_T_BIN;
 				smp->flags = SMP_F_VOLATILE | SMP_F_CONST;
 
-				if (ofs + body > ci_head(chn) - b_orig(chn->buf) + ci_data(chn)) {
+				if (ofs + body > ci_head(chn) - b_orig(&chn->buf) + ci_data(chn)) {
 					/* incomplete body */
 
-					if (ofs + body > channel_recv_limit(chn) + b_orig(chn->buf) - ci_head(chn)) {
+					if (ofs + body > channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn)) {
 						/* truncate it to whatever will fit */
 						smp->flags |= SMP_F_MAY_CHANGE;
-						body = channel_recv_limit(chn) + b_orig(chn->buf) - ci_head(chn) - ofs;
+						body = channel_recv_limit(chn) + b_orig(&chn->buf) - ci_head(chn) - ofs;
 					}
 				}
 
diff --git a/src/peers.c b/src/peers.c
index 6d5a556..6e549f0 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -576,7 +576,7 @@
 	unsigned int maj_ver, min_ver;
 
 	/* Check if the input buffer is avalaible. */
-	if (si_ic(si)->buf->size == 0)
+	if (si_ic(si)->buf.size == 0)
 		goto full;
 
 	while (1) {
diff --git a/src/proto_http.c b/src/proto_http.c
index 9407542..1d798e6 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -880,7 +880,7 @@
 	hdr = &idx->v[cur_idx];
 	if (sol[ctx->del] == ':' && ctx->val + ctx->vlen + ctx->tws == hdr->len) {
 		/* This was the only value of the header, we must now remove it entirely. */
-		delta = b_rep_blk(msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
+		delta = b_rep_blk(&msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
 		http_msg_move_end(msg, delta);
 		idx->used--;
 		hdr->len = 0;   /* unused entry */
@@ -900,7 +900,7 @@
 	 */
 
 	skip_comma = (ctx->val + ctx->vlen + ctx->tws == hdr->len) ? 0 : 1;
-	delta = b_rep_blk(msg->chn->buf, sol + ctx->del + skip_comma,
+	delta = b_rep_blk(&msg->chn->buf, sol + ctx->del + skip_comma,
 				sol + ctx->val + ctx->vlen + ctx->tws + skip_comma,
 				NULL, 0);
 	hdr->len += delta;
@@ -1103,7 +1103,7 @@
 	c_rew(&s->req, rewind = http_hdr_rewind(&txn->req));
 
 	path = http_get_path(txn);
-	len = b_dist(s->req.buf, path, c_ptr(&s->req, txn->req.sl.rq.u + txn->req.sl.rq.u_l));
+	len = b_dist(&s->req.buf, path, c_ptr(&s->req, txn->req.sl.rq.u + txn->req.sl.rq.u_l));
 
 	c_adv(&s->req, rewind);
 
@@ -1354,7 +1354,7 @@
 		return 0;
 	}
 	/* add HTTP version */
-	delta = b_rep_blk(msg->chn->buf, cur_end, cur_end, " HTTP/1.0\r\n", 11);
+	delta = b_rep_blk(&msg->chn->buf, cur_end, cur_end, " HTTP/1.0\r\n", 11);
 	http_msg_move_end(msg, delta);
 	cur_end += delta;
 	cur_end = (char *)http_parse_reqline(msg,
@@ -1616,7 +1616,7 @@
 		req,
 		req->rex, req->wex,
 		req->flags,
-		req->buf->i,
+		req->buf.i,
 		req->analysers);
 
 	/* we're speaking HTTP here, so let's speak HTTP to the client */
@@ -1643,7 +1643,7 @@
 				return 0;
 			}
 			if (unlikely(ci_tail(req) < c_ptr(req, msg->next) ||
-			             ci_tail(req) > b_wrap(req->buf) - global.tune.maxrewrite))
+			             ci_tail(req) > b_wrap(&req->buf) - global.tune.maxrewrite))
 				channel_slow_realign(req, trash.str);
 		}
 
@@ -1870,7 +1870,7 @@
 
 	/* OK now we have a complete HTTP request with indexed headers. Let's
 	 * complete the request parsing by setting a few fields we will need
-	 * later. At this point, we have the last CRLF at req->buf->data + msg->eoh.
+	 * later. At this point, we have the last CRLF at req->buf.data + msg->eoh.
 	 * If the request is in HTTP/0.9 form, the rule is still true, and eoh
 	 * points to the CRLF of the request line. msg->next points to the first
 	 * byte after the last LF. msg->sov points to the first byte of data.
@@ -2429,7 +2429,7 @@
 		if (output->len == -1)
 			return -1;
 
-		delta = b_rep_blk(msg->chn->buf, val, val_end, output->str, output->len);
+		delta = b_rep_blk(&msg->chn->buf, val, val_end, output->str, output->len);
 
 		hdr->len += delta;
 		http_msg_move_end(msg, delta);
@@ -3377,7 +3377,7 @@
 		FLT_STRM_CB(s, flt_http_reply(s, txn->status, chunk));
 		co_inject(res->chn, chunk->str, chunk->len);
 		/* "eat" the request */
-		b_del(req->chn->buf, req->sov);
+		b_del(&req->chn->buf, req->sov);
 		req->next -= req->sov;
 		req->sov = 0;
 		s->req.analysers = AN_REQ_HTTP_XFER_BODY | (s->req.analysers & AN_REQ_FLT_END);
@@ -3385,7 +3385,7 @@
 		req->msg_state = HTTP_MSG_CLOSED;
 		res->msg_state = HTTP_MSG_DONE;
 		/* Trim any possible response */
-		b_set_data(res->chn->buf, co_data(res->chn));
+		b_set_data(&res->chn->buf, co_data(res->chn));
 		res->next = res->sov = 0;
 		/* let the server side turn to SI_ST_CLO */
 		channel_shutw_now(req->chn);
@@ -3442,7 +3442,7 @@
 		req,
 		req->rex, req->wex,
 		req->flags,
-		req->buf->i,
+		req->buf.i,
 		req->analysers);
 
 	/* just in case we have some per-backend tracking */
@@ -3714,7 +3714,7 @@
 		req,
 		req->rex, req->wex,
 		req->flags,
-		req->buf->i,
+		req->buf.i,
 		req->analysers);
 
 	/*
@@ -3765,7 +3765,7 @@
 			char *cur_end = cur_ptr + txn->req.sl.rq.l;
 			int delta;
 
-			delta = b_rep_blk(req->buf, cur_ptr + msg->sl.rq.u, path, NULL, 0);
+			delta = b_rep_blk(&req->buf, cur_ptr + msg->sl.rq.u, path, NULL, 0);
 			http_msg_move_end(&txn->req, delta);
 			cur_end += delta;
 			if (http_parse_reqline(&txn->req, HTTP_MSG_RQMETH,  cur_ptr, cur_end + 1, NULL, NULL) == NULL)
@@ -3776,7 +3776,7 @@
 			char *cur_end = cur_ptr + txn->req.sl.rq.l;
 			int delta;
 
-			delta = b_rep_blk(req->buf, cur_ptr + msg->sl.rq.u,
+			delta = b_rep_blk(&req->buf, cur_ptr + msg->sl.rq.u,
 						cur_ptr + msg->sl.rq.u + msg->sl.rq.u_l, "/", 1);
 			http_msg_move_end(&txn->req, delta);
 			cur_end += delta;
@@ -4134,14 +4134,14 @@
 		 * TRAILERS state.
 		 */
 		unsigned int chunk;
-		int ret = h1_parse_chunk_size(req->buf, co_data(req) + msg->next, c_data(req), &chunk);
+		int ret = h1_parse_chunk_size(&req->buf, co_data(req) + msg->next, c_data(req), &chunk);
 
 		if (!ret)
 			goto missing_data;
 		else if (ret < 0) {
 			msg->err_pos = ci_data(req) + ret;
 			if (msg->err_pos < 0)
-				msg->err_pos += req->buf->size;
+				msg->err_pos += req->buf.size;
 			stream_inc_http_err_ctr(s);
 			goto return_bad_req;
 		}
@@ -4857,7 +4857,7 @@
 		req,
 		req->rex, req->wex,
 		req->flags,
-		req->buf->i,
+		req->buf.i,
 		req->analysers);
 
 	if (unlikely(msg->msg_state < HTTP_MSG_BODY))
@@ -5130,7 +5130,7 @@
 		}
 
 		if (unlikely(ci_tail(rep) < c_ptr(rep, msg->next) ||
-		             ci_tail(rep) > b_wrap(rep->buf) - global.tune.maxrewrite))
+		             ci_tail(rep) > b_wrap(&rep->buf) - global.tune.maxrewrite))
 			channel_slow_realign(rep, trash.str);
 
 		if (likely(msg->next < ci_data(rep)))
@@ -6072,7 +6072,7 @@
 		res,
 		res->rex, res->wex,
 		res->flags,
-		res->buf->i,
+		res->buf.i,
 		res->analysers);
 
 	if (unlikely(msg->msg_state < HTTP_MSG_BODY))
@@ -6276,7 +6276,7 @@
 	msg->msg_state = HTTP_MSG_ENDING;
 
   ending:
-	/* we may have some pending data starting at res->buf->p such as a last
+	/* we may have some pending data starting at res->buf.p such as a last
 	 * chunk of data or trailers. */
 	ret = FLT_STRM_DATA_CB(s, chn, flt_http_forward_data(s, msg, msg->next),
 			       /* default_ret */ msg->next,
@@ -6297,7 +6297,7 @@
 	return 1;
 
   missing_data_or_waiting:
-	/* we may have some pending data starting at chn->buf->p */
+	/* we may have some pending data starting at chn->buf.p */
 	ret = FLT_STRM_DATA_CB(s, chn, flt_http_forward_data(s, msg, msg->next),
 			       /* default_ret */ msg->next,
 			       /* on_error    */ goto error);
@@ -6345,13 +6345,13 @@
 
 		case HTTP_MSG_CHUNK_CRLF:
 			/* we want the CRLF after the data */
-			ret = h1_skip_chunk_crlf(chn->buf, co_data(chn) + msg->next, c_data(chn));
+			ret = h1_skip_chunk_crlf(&chn->buf, co_data(chn) + msg->next, c_data(chn));
 			if (ret == 0)
 				goto missing_data_or_waiting;
 			if (ret < 0) {
 				msg->err_pos = ci_data(chn) + ret;
 				if (msg->err_pos < 0)
-					msg->err_pos += chn->buf->size;
+					msg->err_pos += chn->buf.size;
 				goto chunk_parsing_error;
 			}
 			msg->next += ret;
@@ -6363,13 +6363,13 @@
 			 * then set ->next to point to the body and switch to
 			 * DATA or TRAILERS state.
 			 */
-			ret = h1_parse_chunk_size(chn->buf, co_data(chn) + msg->next, c_data(chn), &chunk);
+			ret = h1_parse_chunk_size(&chn->buf, co_data(chn) + msg->next, c_data(chn), &chunk);
 			if (ret == 0)
 				goto missing_data_or_waiting;
 			if (ret < 0) {
 				msg->err_pos = ci_data(chn) + ret;
 				if (msg->err_pos < 0)
-					msg->err_pos += chn->buf->size;
+					msg->err_pos += chn->buf.size;
 				goto chunk_parsing_error;
 			}
 
@@ -6407,7 +6407,7 @@
 
 	msg->msg_state = HTTP_MSG_ENDING;
   ending:
-	/* we may have some pending data starting at res->buf->p such as a last
+	/* we may have some pending data starting at res->buf.p such as a last
 	 * chunk of data or trailers. */
 	ret = FLT_STRM_DATA_CB(s, chn, flt_http_forward_data(s, msg, msg->next),
 			  /* default_ret */ msg->next,
@@ -6427,7 +6427,7 @@
 	return 1;
 
   missing_data_or_waiting:
-	/* we may have some pending data starting at chn->buf->p */
+	/* we may have some pending data starting at chn->buf.p */
 	ret = FLT_STRM_DATA_CB(s, chn, flt_http_forward_data(s, msg, msg->next),
 			  /* default_ret */ msg->next,
 			  /* on_error    */ goto error);
@@ -6516,7 +6516,7 @@
 				if (trash.len < 0)
 					return -1;
 
-				delta = b_rep_blk(req->buf, cur_ptr, cur_end, trash.str, trash.len);
+				delta = b_rep_blk(&req->buf, cur_ptr, cur_end, trash.str, trash.len);
 				/* FIXME: if the user adds a newline in the replacement, the
 				 * index will not be recalculated for now, and the new line
 				 * will not be counted as a new header.
@@ -6529,7 +6529,7 @@
 				break;
 
 			case ACT_REMOVE:
-				delta = b_rep_blk(req->buf, cur_ptr, cur_next, NULL, 0);
+				delta = b_rep_blk(&req->buf, cur_ptr, cur_next, NULL, 0);
 				cur_next += delta;
 
 				http_msg_move_end(&txn->req, delta);
@@ -6604,7 +6604,7 @@
 			if (trash.len < 0)
 				return -1;
 
-			delta = b_rep_blk(req->buf, cur_ptr, cur_end, trash.str, trash.len);
+			delta = b_rep_blk(&req->buf, cur_ptr, cur_end, trash.str, trash.len);
 			/* FIXME: if the user adds a newline in the replacement, the
 			 * index will not be recalculated for now, and the new line
 			 * will not be counted as a new header.
@@ -6912,7 +6912,7 @@
 				 */
 				preserve_hdr = 1;
 				if (del_from != NULL) {
-					int delta = del_hdr_value(req->buf, &del_from, prev);
+					int delta = del_hdr_value(&req->buf, &del_from, prev);
 					val_end  += delta;
 					next     += delta;
 					hdr_end  += delta;
@@ -6935,13 +6935,13 @@
 				int stripped_after = 0;
 
 				if (att_end != equal) {
-					stripped_before = b_rep_blk(req->buf, att_end, equal, NULL, 0);
+					stripped_before = b_rep_blk(&req->buf, att_end, equal, NULL, 0);
 					equal   += stripped_before;
 					val_beg += stripped_before;
 				}
 
 				if (val_beg > equal + 1) {
-					stripped_after = b_rep_blk(req->buf, equal + 1, val_beg, NULL, 0);
+					stripped_after = b_rep_blk(&req->buf, equal + 1, val_beg, NULL, 0);
 					val_beg += stripped_after;
 					stripped_before += stripped_after;
 				}
@@ -7122,7 +7122,7 @@
 				if ((s->be->ck_opts & PR_CK_PFX) && (delim != val_end)) {
 					int delta; /* negative */
 
-					delta = b_rep_blk(req->buf, val_beg, delim + 1, NULL, 0);
+					delta = b_rep_blk(&req->buf, val_beg, delim + 1, NULL, 0);
 					val_end  += delta;
 					next     += delta;
 					hdr_end  += delta;
@@ -7145,7 +7145,7 @@
 				preserve_hdr = 1;
 
 				if (del_from != NULL) {
-					int delta = del_hdr_value(req->buf, &del_from, prev);
+					int delta = del_hdr_value(&req->buf, &del_from, prev);
 					if (att_beg >= del_from)
 						att_beg += delta;
 					if (att_end >= del_from)
@@ -7176,11 +7176,11 @@
 		if (del_from) {
 			int delta;
 			if (preserve_hdr) {
-				delta = del_hdr_value(req->buf, &del_from, hdr_end);
+				delta = del_hdr_value(&req->buf, &del_from, hdr_end);
 				hdr_end = del_from;
 				cur_hdr->len += delta;
 			} else {
-				delta = b_rep_blk(req->buf, hdr_beg, hdr_next, NULL, 0);
+				delta = b_rep_blk(&req->buf, hdr_beg, hdr_next, NULL, 0);
 
 				/* FIXME: this should be a separate function */
 				txn->hdr_idx.v[old_idx].next = cur_hdr->next;
@@ -7252,7 +7252,7 @@
 				if (trash.len < 0)
 					return -1;
 
-				delta = b_rep_blk(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
+				delta = b_rep_blk(&rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
 				/* FIXME: if the user adds a newline in the replacement, the
 				 * index will not be recalculated for now, and the new line
 				 * will not be counted as a new header.
@@ -7265,7 +7265,7 @@
 				break;
 
 			case ACT_REMOVE:
-				delta = b_rep_blk(rtr->buf, cur_ptr, cur_next, NULL, 0);
+				delta = b_rep_blk(&rtr->buf, cur_ptr, cur_next, NULL, 0);
 				cur_next += delta;
 
 				http_msg_move_end(&txn->rsp, delta);
@@ -7333,7 +7333,7 @@
 			if (trash.len < 0)
 				return -1;
 
-			delta = b_rep_blk(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
+			delta = b_rep_blk(&rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
 			/* FIXME: if the user adds a newline in the replacement, the
 			 * index will not be recalculated for now, and the new line
 			 * will not be counted as a new header.
@@ -7588,13 +7588,13 @@
 				int stripped_after = 0;
 
 				if (att_end != equal) {
-					stripped_before = b_rep_blk(res->buf, att_end, equal, NULL, 0);
+					stripped_before = b_rep_blk(&res->buf, att_end, equal, NULL, 0);
 					equal   += stripped_before;
 					val_beg += stripped_before;
 				}
 
 				if (val_beg > equal + 1) {
-					stripped_after = b_rep_blk(res->buf, equal + 1, val_beg, NULL, 0);
+					stripped_after = b_rep_blk(&res->buf, equal + 1, val_beg, NULL, 0);
 					val_beg += stripped_after;
 					stripped_before += stripped_after;
 				}
@@ -7652,7 +7652,7 @@
 					/* this cookie must be deleted */
 					if (*prev == ':' && next == hdr_end) {
 						/* whole header */
-						delta = b_rep_blk(res->buf, hdr_beg, hdr_next, NULL, 0);
+						delta = b_rep_blk(&res->buf, hdr_beg, hdr_next, NULL, 0);
 						txn->hdr_idx.v[old_idx].next = cur_hdr->next;
 						txn->hdr_idx.used--;
 						cur_hdr->len = 0;
@@ -7664,7 +7664,7 @@
 						 */
 					} else {
 						/* just remove the value */
-						int delta = del_hdr_value(res->buf, &prev, next);
+						int delta = del_hdr_value(&res->buf, &prev, next);
 						next      = prev;
 						hdr_end  += delta;
 						hdr_next += delta;
@@ -7679,7 +7679,7 @@
 					/* replace bytes val_beg->val_end with the cookie name associated
 					 * with this server since we know it.
 					 */
-					delta = b_rep_blk(res->buf, val_beg, val_end, srv->cookie, srv->cklen);
+					delta = b_rep_blk(&res->buf, val_beg, val_end, srv->cookie, srv->cklen);
 					next     += delta;
 					hdr_end  += delta;
 					hdr_next += delta;
@@ -7693,7 +7693,7 @@
 					/* insert the cookie name associated with this server
 					 * before existing cookie, and insert a delimiter between them..
 					 */
-					delta = b_rep_blk(res->buf, val_beg, val_beg, srv->cookie, srv->cklen + 1);
+					delta = b_rep_blk(&res->buf, val_beg, val_beg, srv->cookie, srv->cklen + 1);
 					next     += delta;
 					hdr_end  += delta;
 					hdr_next += delta;
@@ -7955,7 +7955,7 @@
 
 	HA_SPIN_LOCK(PROXY_LOCK, &proxy->lock);
 	es->len = MIN(ci_data(chn), global.tune.bufsize);
-	len1 = b_wrap(chn->buf) - ci_head(chn);
+	len1 = b_wrap(&chn->buf) - ci_head(chn);
 	len1 = MIN(len1, es->len);
 	len2 = es->len - len1; /* remaining data if buffer wraps */
 
@@ -7965,7 +7965,7 @@
 	if (es->buf) {
 		memcpy(es->buf, ci_head(chn), len1);
 		if (len2)
-			memcpy(es->buf + len1, b_orig(chn->buf), len2);
+			memcpy(es->buf + len1, b_orig(&chn->buf), len2);
 	}
 
 	if (msg->err_pos >= 0)
@@ -7989,7 +7989,7 @@
 	es->t_flags = s->txn->flags;
 	es->m_flags = msg->flags;
 	es->b_out = co_data(chn);
-	es->b_wrap = b_wrap(chn->buf) - ci_head(chn);
+	es->b_wrap = b_wrap(&chn->buf) - ci_head(chn);
 	es->b_tot = chn->total;
 	es->m_clen = msg->chunk_len;
 	es->m_blen = msg->body_len;
@@ -8307,7 +8307,7 @@
 	 * content-length.
 	 */
 	if (unlikely(ci_data(&s->res)))
-		b_set_data(s->res.buf, co_data(&s->res));
+		b_set_data(&s->res.buf, co_data(&s->res));
 
 	/* Now we can realign the response buffer */
 	c_realign_if_empty(&s->res);
@@ -9507,8 +9507,8 @@
 		/* If the buffer does not leave enough free space at the end,
 		 * we must first realign it.
 		 */
-		if (ci_head(&s->req) > b_orig(s->req.buf) &&
-		    ci_head(&s->req) + ci_data(&s->req) > b_wrap(s->req.buf) - global.tune.maxrewrite)
+		if (ci_head(&s->req) > b_orig(&s->req.buf) &&
+		    ci_head(&s->req) + ci_data(&s->req) > b_wrap(&s->req.buf) - global.tune.maxrewrite)
 			channel_slow_realign(&s->req, trash.str);
 
 		if (unlikely(txn->req.msg_state < HTTP_MSG_BODY)) {
@@ -9541,7 +9541,7 @@
 			 * we want this check to be maintained.
 			 */
 			if (unlikely(ci_head(&s->req) + ci_data(&s->req) >
-				     b_wrap(s->req.buf) - global.tune.maxrewrite)) {
+				     b_wrap(&s->req.buf) - global.tune.maxrewrite)) {
 				msg->err_state = msg->msg_state;
 				msg->msg_state = HTTP_MSG_ERROR;
 				smp->data.u.sint = 1;
@@ -9914,8 +9914,8 @@
 	body = c_ptr(msg->chn, -http_data_rewind(msg));
 
 	block1 = len;
-	if (block1 > b_wrap(msg->chn->buf) - body)
-		block1 = b_wrap(msg->chn->buf) - body;
+	if (block1 > b_wrap(&msg->chn->buf) - body)
+		block1 = b_wrap(&msg->chn->buf) - body;
 
 	if (block1 == len) {
 		/* buffer is not wrapped (or empty) */
@@ -9928,7 +9928,7 @@
 		/* buffer is wrapped, we need to defragment it */
 		temp = get_trash_chunk();
 		memcpy(temp->str, body, block1);
-		memcpy(temp->str + block1, b_orig(msg->chn->buf), len - block1);
+		memcpy(temp->str + block1, b_orig(&msg->chn->buf), len - block1);
 		smp->data.type = SMP_T_BIN;
 		smp->data.u.str.str = temp->str;
 		smp->data.u.str.len = len;
@@ -11385,8 +11385,8 @@
 		body = c_ptr(msg->chn, -http_data_rewind(msg));
 
 		block1 = len;
-		if (block1 > b_wrap(msg->chn->buf) - body)
-			block1 = b_wrap(msg->chn->buf) - body;
+		if (block1 > b_wrap(&msg->chn->buf) - body)
+			block1 = b_wrap(&msg->chn->buf) - body;
 
 		if (block1 == len) {
 			/* buffer is not wrapped (or empty) */
@@ -11403,8 +11403,8 @@
 			/* buffer is wrapped, we need to defragment it */
 			smp->ctx.a[0] = body;
 			smp->ctx.a[1] = body + block1;
-			smp->ctx.a[2] = b_orig(msg->chn->buf);
-			smp->ctx.a[3] = b_orig(msg->chn->buf) + ( len - block1 );
+			smp->ctx.a[2] = b_orig(&msg->chn->buf);
+			smp->ctx.a[3] = b_orig(&msg->chn->buf) + ( len - block1 );
 		}
 	}
 	return smp_fetch_param('&', name, name_len, args, smp, kw, private);
@@ -11927,7 +11927,7 @@
 	}
 
 	/* commit changes and adjust end of message */
-	delta = b_rep_blk(s->req.buf, cur_ptr, cur_end, replace + offset, len - offset);
+	delta = b_rep_blk(&s->req.buf, cur_ptr, cur_end, replace + offset, len - offset);
 	txn->req.sl.rq.l += delta;
 	txn->hdr_idx.v[0].len += delta;
 	http_msg_move_end(&txn->req, delta);
@@ -11966,7 +11966,7 @@
 	cur_end = ci_head(&s->res) + txn->rsp.sl.st.r + txn->rsp.sl.st.r_l;
 
 	/* commit changes and adjust message */
-	delta = b_rep_blk(s->res.buf, cur_ptr, cur_end, trash.str, trash.len);
+	delta = b_rep_blk(&s->res.buf, cur_ptr, cur_end, trash.str, trash.len);
 
 	/* adjust res line offsets and lengths */
 	txn->rsp.sl.st.r += c_l - txn->rsp.sl.st.c_l;
diff --git a/src/stats.c b/src/stats.c
index c0c1b35..443024b 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -2045,7 +2045,7 @@
 	case STAT_PX_ST_LI:
 		/* stats.l has been initialized above */
 		for (; appctx->ctx.stats.l != &px->conf.listeners; appctx->ctx.stats.l = l->by_fe.n) {
-			if (buffer_almost_full(rep->buf)) {
+			if (buffer_almost_full(&rep->buf)) {
 				si_applet_cant_put(si);
 				return 0;
 			}
@@ -2078,7 +2078,7 @@
 	case STAT_PX_ST_SV:
 		/* stats.sv has been initialized above */
 		for (; appctx->ctx.stats.sv != NULL; appctx->ctx.stats.sv = sv->next) {
-			if (buffer_almost_full(rep->buf)) {
+			if (buffer_almost_full(&rep->buf)) {
 				si_applet_cant_put(si);
 				return 0;
 			}
@@ -2570,7 +2570,7 @@
 	case STAT_ST_LIST:
 		/* dump proxies */
 		while (appctx->ctx.stats.px) {
-			if (buffer_almost_full(rep->buf)) {
+			if (buffer_almost_full(&rep->buf)) {
 				si_applet_cant_put(si);
 				return 0;
 			}
@@ -3034,7 +3034,7 @@
 		goto out;
 
 	/* Check if the input buffer is avalaible. */
-	if (res->buf->size == 0) {
+	if (res->buf.size == 0) {
 		si_applet_cant_put(si);
 		goto out;
 	}
diff --git a/src/stream.c b/src/stream.c
index cda5d54..d6ba173 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -180,7 +180,8 @@
 	 * when the default backend is assigned.
 	 */
 	s->be  = sess->fe;
-	s->req.buf = s->res.buf = NULL;
+	s->req.buf = BUF_NULL;
+	s->res.buf = BUF_NULL;
 	s->req_cap = NULL;
 	s->res_cap = NULL;
 
@@ -336,7 +337,7 @@
 		LIST_INIT(&s->buffer_wait.list);
 		HA_SPIN_UNLOCK(BUF_WQ_LOCK, &buffer_wq_lock);
 	}
-	if (s->req.buf->size || s->res.buf->size) {
+	if (s->req.buf.size || s->res.buf.size) {
 		b_drop(&s->req.buf);
 		b_drop(&s->res.buf);
 		offer_buffers(NULL, tasks_run_queue);
@@ -856,7 +857,7 @@
 		req, &s->res,
 		req->rex, s->res.wex,
 		req->flags, s->res.flags,
-		req->buf->i, req->buf->o, s->res.buf->i, s->res.buf->o, s->si[0].state, s->si[1].state);
+		req->buf->i, req->buf->o, s->res.buf.i, s->res.buf.o, s->si[0].state, s->si[1].state);
 
 	if (si->state == SI_ST_ASS) {
 		/* Server assigned to connection request, we have to try to connect now */
@@ -1051,7 +1052,7 @@
 		&s->req, &s->res,
 		s->req.rex, s->res.wex,
 		s->req.flags, s->res.flags,
-		s->req.buf->i, s->req.buf->o, s->res.buf->i, s->res.buf->o, s->si[0].state, s->si[1].state);
+		s->req.buf.i, s->req.buf.o, s->res.buf.i, s->res.buf.o, s->si[0].state, s->si[1].state);
 
 	if (si->state != SI_ST_REQ)
 		return;
@@ -2978,11 +2979,11 @@
 			     strm->req.wex ?
 			     human_time(TICKS_TO_MS(strm->req.wex - now_ms),
 					TICKS_TO_MS(1000)) : "<NEVER>",
-			     strm->req.buf,
-		             b_orig(strm->req.buf), (unsigned int)co_data(&strm->req),
+			     &strm->req.buf,
+		             b_orig(&strm->req.buf), (unsigned int)co_data(&strm->req),
 			     (unsigned int)ci_head_ofs(&strm->req),
 		             strm->txn ? strm->txn->req.next : 0, (unsigned int)ci_data(&strm->req),
-			     (unsigned int)strm->req.buf->size);
+			     (unsigned int)strm->req.buf.size);
 
 		chunk_appendf(&trash,
 			     "  res=%p (f=0x%06x an=0x%x pipe=%d tofwd=%d total=%lld)\n"
@@ -3007,11 +3008,11 @@
 			     strm->res.wex ?
 			     human_time(TICKS_TO_MS(strm->res.wex - now_ms),
 					TICKS_TO_MS(1000)) : "<NEVER>",
-			     strm->res.buf,
-		             b_orig(strm->res.buf), (unsigned int)co_data(&strm->res),
+			     &strm->res.buf,
+		             b_orig(&strm->res.buf), (unsigned int)co_data(&strm->res),
 		             (unsigned int)ci_head_ofs(&strm->res),
 		             strm->txn ? strm->txn->rsp.next : 0, (unsigned int)ci_data(&strm->res),
-			     (unsigned int)strm->res.buf->size);
+			     (unsigned int)strm->res.buf.size);
 
 		if (ci_putchk(si_ic(si), &trash) == -1) {
 			si_applet_cant_put(si);
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 4b86102..8190108 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -683,7 +683,7 @@
 		if (oc->flags & CF_STREAMER)
 			send_flag |= CO_SFL_STREAMER;
 
-		ret = conn->mux->snd_buf(cs, oc->buf, co_data(oc), send_flag);
+		ret = conn->mux->snd_buf(cs, &oc->buf, co_data(oc), send_flag);
 		if (ret > 0) {
 			oc->flags |= CF_WRITE_PARTIAL | CF_WROTE_DATA | CF_WRITE_EVENT;
 
@@ -1189,7 +1189,7 @@
 			break;
 		}
 
-		ret = conn->mux->rcv_buf(cs, ic->buf, max, co_data(ic) ? CO_RFL_BUF_WET : 0);
+		ret = conn->mux->rcv_buf(cs, &ic->buf, max, co_data(ic) ? CO_RFL_BUF_WET : 0);
 		if (cs->flags & CS_FL_RCV_MORE)
 			si->flags |= SI_FL_WAIT_ROOM;
 
@@ -1250,7 +1250,7 @@
 
 	if (cur_read) {
 		if ((ic->flags & (CF_STREAMER | CF_STREAMER_FAST)) &&
-		    (cur_read <= ic->buf->size / 2)) {
+		    (cur_read <= ic->buf.size / 2)) {
 			ic->xfer_large = 0;
 			ic->xfer_small++;
 			if (ic->xfer_small >= 3) {
@@ -1269,7 +1269,7 @@
 			}
 		}
 		else if (!(ic->flags & CF_STREAMER_FAST) &&
-			 (cur_read >= ic->buf->size - global.tune.maxrewrite)) {
+			 (cur_read >= ic->buf.size - global.tune.maxrewrite)) {
 			/* we read a full buffer at once */
 			ic->xfer_small = 0;
 			ic->xfer_large++;