[PATCH]: talloc_pooled_object patchset

Jeremy Allison jra at samba.org
Sat Sep 7 01:10:41 CEST 2013


On Mon, Aug 26, 2013 at 07:11:13PM +0200, Stefan (metze) Metzmacher wrote:
> Hi Jeremy,
> hi Volker,
> 
> > On Thu, Aug 22, 2013 at 09:00:42PM -0700, Jeremy Allison wrote:
> >> Ok - here is a patchset I think is pushable to
> >> master if you agree :-).
> >>
> >> I took the liberty of adding your 'Signed-off-by'
> >> line as well as my 'Reviewed-by' tag.
> >>
> >> Turns out the only 3 changes needed to make this
> >> patchset valgrind-clean from my posted changes
> >> were the following :
> > 
> > Thanks a lot for fixing those! Before pushing, I would like
> > metze to also give his blessing to the patchset. He will be
> > available on monday again, so I will ping him then.
> 
> I reviewed the patches, I'm almost happy with them.
> 
> I just found a few minor things we need to discuss/fix.
> 
> The attached patches have TODO comments in their commit message.

Ok, here is a rebased and partly rewritten patchset
on top of the fixes I put into talloc to make the
memlimit code work with talloc pools.

It's valgrind-clean and is careful to keep the memlimit
code working. It also contains the squashes you requested
squashed, and the TODO's you wanted done fixing.

Please review and push (or give me a +1 :-) if you're
happy with it.

Cheers,

	Jeremy
-------------- next part --------------
From 2777e279dab35d0424758112ee755e61f29210aa Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 10:54:43 -0700
Subject: [PATCH 1/9] talloc: Decouple the dual use of chunk->pool

If we want nested pools, we will have pools that are pool members. So
we will have to have a separate "next object" pointer  for pools. As
we have struct talloc_pool_chunk now, this additional pointer does not
affect normal talloc objects.

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/talloc/talloc.c | 48 +++++++++++++++++++++++-------------------------
 1 file changed, 23 insertions(+), 25 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 69d5a16..74db284 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -244,6 +244,8 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc);
 
 typedef int (*talloc_destructor_t)(void *);
 
+union talloc_pool_chunk;
+
 struct talloc_chunk {
 	struct talloc_chunk *next, *prev;
 	struct talloc_chunk *parent, *child;
@@ -263,17 +265,12 @@ struct talloc_chunk {
 	struct talloc_memlimit *limit;
 
 	/*
-	 * "pool" has dual use:
-	 *
-	 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
-	 * marks the end of the currently allocated area.
-	 *
-	 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
+	 * For members of a pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
 	 * is a pointer to the struct talloc_chunk of the pool that it was
 	 * allocated from. This way children can quickly find the pool to chew
 	 * from.
 	 */
-	void *pool;
+	union talloc_pool_chunk *pool;
 };
 
 /* 16 byte alignment seems to keep everyone happy */
@@ -466,6 +463,7 @@ union talloc_pool_chunk {
 	 * on 32-bit platforms. */
 	struct tc_pool_hdr {
 		struct talloc_chunk c;
+		void *next;
 		unsigned int object_count;
 	} hdr;
 	/* This makes it always 16 byte aligned. */
@@ -479,7 +477,7 @@ static void *tc_pool_end(union talloc_pool_chunk *pool_tc)
 
 static size_t tc_pool_space_left(union talloc_pool_chunk *pool_tc)
 {
-	return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.c.pool;
+	return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.next;
 }
 
 static void *tc_pool_first_chunk(union talloc_pool_chunk *pool_tc)
@@ -499,11 +497,11 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc)
 	size_t flen = tc_pool_space_left(pool_tc);
 
 	if (unlikely(talloc_fill.enabled)) {
-		memset(pool_tc->hdr.c.pool, talloc_fill.fill_value, flen);
+		memset(pool_tc->hdr.next, talloc_fill.fill_value, flen);
 	}
 
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
-	VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.c.pool, flen);
+	VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.next, flen);
 #endif
 }
 
@@ -527,7 +525,7 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 		pool_ctx = (union talloc_pool_chunk *)parent;
 	}
 	else if (parent->flags & TALLOC_FLAG_POOLMEM) {
-		pool_ctx = (union talloc_pool_chunk *)parent->pool;
+		pool_ctx = parent->pool;
 	}
 
 	if (pool_ctx == NULL) {
@@ -545,13 +543,13 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 		return NULL;
 	}
 
-	result = (struct talloc_chunk *)pool_ctx->hdr.c.pool;
+	result = (struct talloc_chunk *)pool_ctx->hdr.next;
 
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
 	VALGRIND_MAKE_MEM_UNDEFINED(result, size);
 #endif
 
-	pool_ctx->hdr.c.pool = (void *)((char *)result + chunk_size);
+	pool_ctx->hdr.next = (void *)((char *)result + chunk_size);
 
 	result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
 	result->pool = pool_ctx;
@@ -653,7 +651,7 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size)
 		return NULL;
 	}
 	pool_tc->hdr.c.flags |= TALLOC_FLAG_POOL;
-	pool_tc->hdr.c.pool = tc_pool_first_chunk(pool_tc);
+	pool_tc->hdr.next = tc_pool_first_chunk(pool_tc);
 
 	pool_tc->hdr.object_count = 1;
 
@@ -763,7 +761,7 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 	union talloc_pool_chunk *pool;
 	void *next_tc;
 
-	pool = (union talloc_pool_chunk *)tc->pool;
+	pool = tc->pool;
 	next_tc = tc_next_chunk(tc);
 
 	tc->flags |= TALLOC_FLAG_FREE;
@@ -792,7 +790,7 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		 * the rest is available for new objects
 		 * again.
 		 */
-		pool->hdr.c.pool = tc_pool_first_chunk(pool);
+		pool->hdr.next = tc_pool_first_chunk(pool);
 		tc_invalidate_pool(pool);
 		return;
 	}
@@ -812,13 +810,13 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		return;
 	}
 
-	if (pool->hdr.c.pool == next_tc) {
+	if (pool->hdr.next == next_tc) {
 		/*
 		 * if pool->pool still points to end of
 		 * 'tc' (which is stored in the 'next_tc' variable),
 		 * we can reclaim the memory of 'tc'.
 		 */
-		pool->hdr.c.pool = tc;
+		pool->hdr.next = tc;
 		return;
 	}
 
@@ -1516,7 +1514,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 
 	/* handle realloc inside a talloc_pool */
 	if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) {
-		pool_tc = (union talloc_pool_chunk *)tc->pool;
+		pool_tc = tc->pool;
 	}
 
 #if (ALWAYS_REALLOC == 0)
@@ -1526,9 +1524,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			void *next_tc = tc_next_chunk(tc);
 			TC_INVALIDATE_SHRINK_CHUNK(tc, size);
 			tc->size = size;
-			if (next_tc == pool_tc->hdr.c.pool) {
+			if (next_tc == pool_tc->hdr.next) {
 				/* note: tc->size has changed, so this works */
-				pool_tc->hdr.c.pool = tc_next_chunk(tc);
+				pool_tc->hdr.next = tc_next_chunk(tc);
 			}
 			return ptr;
 		} else if ((tc->size - size) < 1024) {
@@ -1640,11 +1638,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 				 * because we want to invalidate the padding
 				 * too.
 				 */
-				pool_tc->hdr.c.pool = new_used + (char *)new_ptr;
+				pool_tc->hdr.next = new_used + (char *)new_ptr;
 				tc_invalidate_pool(pool_tc);
 
 				/* now the aligned pointer */
-				pool_tc->hdr.c.pool = new_chunk_size + (char *)new_ptr;
+				pool_tc->hdr.next = new_chunk_size + (char *)new_ptr;
 				goto got_new_ptr;
 			}
 
@@ -1658,7 +1656,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			return ptr;
 		}
 
-		if (next_tc == pool_tc->hdr.c.pool) {
+		if (next_tc == pool_tc->hdr.next) {
 			/*
 			 * optimize for the case where 'tc' is the last
 			 * chunk in the pool.
@@ -1670,7 +1668,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 				TC_UNDEFINE_GROW_CHUNK(tc, size);
 				tc->flags &= ~TALLOC_FLAG_FREE;
 				tc->size = size;
-				pool_tc->hdr.c.pool = tc_next_chunk(tc);
+				pool_tc->hdr.next = tc_next_chunk(tc);
 				return ptr;
 			}
 		}
-- 
1.8.4


From e2000fe30adad5599f0f63db13426939686a2d92 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 12:18:26 -0700
Subject: [PATCH 2/9] talloc: Introduce __talloc_with_prefix

This will allow to exchange the extra talloc pool header with the
talloc_chunk structure

Signed-off-by: Volker Lendecke <vl at samba.org>
Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 74db284..21d675d 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -510,7 +510,7 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc)
 */
 
 static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
-					      size_t size)
+					      size_t size, size_t prefix_len)
 {
 	union talloc_pool_chunk *pool_ctx = NULL;
 	size_t space_left;
@@ -537,13 +537,14 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 	/*
 	 * Align size to 16 bytes
 	 */
-	chunk_size = TC_ALIGN16(size);
+	chunk_size = TC_ALIGN16(size + prefix_len);
 
 	if (space_left < chunk_size) {
 		return NULL;
 	}
 
-	result = (struct talloc_chunk *)pool_ctx->hdr.next;
+	result = (struct talloc_chunk *)
+		((char *)pool_ctx->hdr.next + prefix_len);
 
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
 	VALGRIND_MAKE_MEM_UNDEFINED(result, size);
@@ -562,10 +563,12 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 /*
    Allocate a bit of memory as a child of an existing pointer
 */
-static inline void *__talloc(const void *context, size_t size)
+static inline void *__talloc_with_prefix(const void *context, size_t size,
+					size_t prefix_len)
 {
 	struct talloc_chunk *tc = NULL;
 	struct talloc_memlimit *limit = NULL;
+	size_t total_len = TC_HDR_SIZE + size + prefix_len;
 
 	if (unlikely(context == NULL)) {
 		context = null_context;
@@ -575,6 +578,10 @@ static inline void *__talloc(const void *context, size_t size)
 		return NULL;
 	}
 
+	if (unlikely(total_len < TC_HDR_SIZE)) {
+		return NULL;
+	}
+
 	if (context != NULL) {
 		struct talloc_chunk *ptc = talloc_chunk_from_ptr(context);
 
@@ -582,24 +589,24 @@ static inline void *__talloc(const void *context, size_t size)
 			limit = ptc->limit;
 		}
 
-		tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size);
+		tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size, prefix_len);
 	}
 
 	if (tc == NULL) {
 		/*
 		 * Only do the memlimit check/update on actual allocation.
 		 */
-		if (!talloc_memlimit_check(limit, TC_HDR_SIZE + size)) {
+		if (!talloc_memlimit_check(limit, total_len)) {
 			errno = ENOMEM;
 			return NULL;
 		}
 
-		tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
+		tc = (struct talloc_chunk *)malloc(total_len);
 		if (unlikely(tc == NULL)) return NULL;
 		tc->flags = TALLOC_MAGIC;
 		tc->pool  = NULL;
 
-		talloc_memlimit_grow(limit, TC_HDR_SIZE + size);
+		talloc_memlimit_grow(limit, total_len);
 	}
 
 	tc->limit = limit;
@@ -629,6 +636,11 @@ static inline void *__talloc(const void *context, size_t size)
 	return TC_PTR_FROM_CHUNK(tc);
 }
 
+static inline void *__talloc(const void *context, size_t size)
+{
+	return __talloc_with_prefix(context, size, 0);
+}
+
 /*
  * Create a talloc pool
  */
@@ -1558,7 +1570,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 
 #if ALWAYS_REALLOC
 	if (pool_tc) {
-		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
+		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0);
 		pool_tc->hdr.object_count--;
 
 		if (new_ptr == NULL) {
@@ -1673,7 +1685,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			}
 		}
 
-		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
+		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0);
 
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
-- 
1.8.4


From 55270d8dcf3f03f1b06dd0329a0e66b9df61c5c1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 14:08:43 -0700
Subject: [PATCH 3/9] talloc: Put pool-specific data before the chunk

This is a preparation to make talloc pool real objects themselves.

Signed-off-by: Volker Lendecke <vl at samba.org>
Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c | 204 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 125 insertions(+), 79 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 21d675d..a553050 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -244,7 +244,7 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc);
 
 typedef int (*talloc_destructor_t)(void *);
 
-union talloc_pool_chunk;
+struct talloc_pool_hdr;
 
 struct talloc_chunk {
 	struct talloc_chunk *next, *prev;
@@ -270,7 +270,7 @@ struct talloc_chunk {
 	 * allocated from. This way children can quickly find the pool to chew
 	 * from.
 	 */
-	union talloc_pool_chunk *pool;
+	struct talloc_pool_hdr *pool;
 };
 
 /* 16 byte alignment seems to keep everyone happy */
@@ -458,31 +458,37 @@ _PUBLIC_ const char *talloc_parent_name(const void *ptr)
   memory footprint of each talloc chunk by those 16 bytes.
 */
 
-union talloc_pool_chunk {
-	/* This lets object_count nestle into 16-byte padding of talloc_chunk,
-	 * on 32-bit platforms. */
-	struct tc_pool_hdr {
-		struct talloc_chunk c;
-		void *next;
-		unsigned int object_count;
-	} hdr;
-	/* This makes it always 16 byte aligned. */
-	char pad[TC_ALIGN16(sizeof(struct tc_pool_hdr))];
+struct talloc_pool_hdr {
+	void *end;
+	unsigned int object_count;
 };
 
-static void *tc_pool_end(union talloc_pool_chunk *pool_tc)
+#define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr))
+
+static struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c)
+{
+	return (struct talloc_pool_hdr *)((char *)c - TP_HDR_SIZE);
+}
+
+static struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h)
 {
-	return (char *)pool_tc + TC_HDR_SIZE + pool_tc->hdr.c.size;
+	return (struct talloc_chunk *)((char *)h + TP_HDR_SIZE);
 }
 
-static size_t tc_pool_space_left(union talloc_pool_chunk *pool_tc)
+static void *tc_pool_end(struct talloc_pool_hdr *pool_hdr)
 {
-	return (char *)tc_pool_end(pool_tc) - (char *)pool_tc->hdr.next;
+	struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr);
+	return (char *)tc + TC_HDR_SIZE + tc->size;
 }
 
-static void *tc_pool_first_chunk(union talloc_pool_chunk *pool_tc)
+static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr)
 {
-	return pool_tc + 1;
+	return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end;
+}
+
+static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr)
+{
+	return TC_PTR_FROM_CHUNK(talloc_chunk_from_pool(pool_hdr));
 }
 
 /* If tc is inside a pool, this gives the next neighbour. */
@@ -492,16 +498,16 @@ static void *tc_next_chunk(struct talloc_chunk *tc)
 }
 
 /* Mark the whole remaining pool as not accessable */
-static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc)
+static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr)
 {
-	size_t flen = tc_pool_space_left(pool_tc);
+	size_t flen = tc_pool_space_left(pool_hdr);
 
 	if (unlikely(talloc_fill.enabled)) {
-		memset(pool_tc->hdr.next, talloc_fill.fill_value, flen);
+		memset(pool_hdr->end, talloc_fill.fill_value, flen);
 	}
 
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
-	VALGRIND_MAKE_MEM_NOACCESS(pool_tc->hdr.next, flen);
+	VALGRIND_MAKE_MEM_NOACCESS(pool_hdr->end, flen);
 #endif
 }
 
@@ -512,7 +518,7 @@ static void tc_invalidate_pool(union talloc_pool_chunk *pool_tc)
 static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 					      size_t size, size_t prefix_len)
 {
-	union talloc_pool_chunk *pool_ctx = NULL;
+	struct talloc_pool_hdr *pool_hdr = NULL;
 	size_t space_left;
 	struct talloc_chunk *result;
 	size_t chunk_size;
@@ -522,17 +528,17 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 	}
 
 	if (parent->flags & TALLOC_FLAG_POOL) {
-		pool_ctx = (union talloc_pool_chunk *)parent;
+		pool_hdr = talloc_pool_from_chunk(parent);
 	}
 	else if (parent->flags & TALLOC_FLAG_POOLMEM) {
-		pool_ctx = parent->pool;
+		pool_hdr = parent->pool;
 	}
 
-	if (pool_ctx == NULL) {
+	if (pool_hdr == NULL) {
 		return NULL;
 	}
 
-	space_left = tc_pool_space_left(pool_ctx);
+	space_left = tc_pool_space_left(pool_hdr);
 
 	/*
 	 * Align size to 16 bytes
@@ -543,19 +549,18 @@ static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
 		return NULL;
 	}
 
-	result = (struct talloc_chunk *)
-		((char *)pool_ctx->hdr.next + prefix_len);
+	result = (struct talloc_chunk *)((char *)pool_hdr->end + prefix_len);
 
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
-	VALGRIND_MAKE_MEM_UNDEFINED(result, size);
+	VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, chunk_size);
 #endif
 
-	pool_ctx->hdr.next = (void *)((char *)result + chunk_size);
+	pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size);
 
 	result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
-	result->pool = pool_ctx;
+	result->pool = pool_hdr;
 
-	pool_ctx->hdr.object_count++;
+	pool_hdr->object_count++;
 
 	return result;
 }
@@ -593,6 +598,8 @@ static inline void *__talloc_with_prefix(const void *context, size_t size,
 	}
 
 	if (tc == NULL) {
+		char *ptr;
+
 		/*
 		 * Only do the memlimit check/update on actual allocation.
 		 */
@@ -601,8 +608,11 @@ static inline void *__talloc_with_prefix(const void *context, size_t size,
 			return NULL;
 		}
 
-		tc = (struct talloc_chunk *)malloc(total_len);
-		if (unlikely(tc == NULL)) return NULL;
+		ptr = malloc(total_len);
+		if (unlikely(ptr == NULL)) {
+			return NULL;
+		}
+		tc = (struct talloc_chunk *)(ptr + prefix_len);
 		tc->flags = TALLOC_MAGIC;
 		tc->pool  = NULL;
 
@@ -647,27 +657,32 @@ static inline void *__talloc(const void *context, size_t size)
 
 _PUBLIC_ void *talloc_pool(const void *context, size_t size)
 {
-	union talloc_pool_chunk *pool_tc;
-	void *result = __talloc(context, sizeof(*pool_tc) - TC_HDR_SIZE + size);
+	struct talloc_chunk *tc;
+	struct talloc_pool_hdr *pool_hdr;
+	void *result;
+
+	result = __talloc_with_prefix(context, size, TP_HDR_SIZE);
 
 	if (unlikely(result == NULL)) {
 		return NULL;
 	}
 
-	pool_tc = (union talloc_pool_chunk *)talloc_chunk_from_ptr(result);
-	if (unlikely(pool_tc->hdr.c.flags & TALLOC_FLAG_POOLMEM)) {
+	tc = talloc_chunk_from_ptr(result);
+	pool_hdr = talloc_pool_from_chunk(tc);
+
+	if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) {
 		/* We don't handle this correctly, so fail. */
 		talloc_log("talloc: cannot allocate pool off another pool %s\n",
 			   talloc_get_name(context));
 		talloc_free(result);
 		return NULL;
 	}
-	pool_tc->hdr.c.flags |= TALLOC_FLAG_POOL;
-	pool_tc->hdr.next = tc_pool_first_chunk(pool_tc);
+	tc->flags |= TALLOC_FLAG_POOL;
 
-	pool_tc->hdr.object_count = 1;
+	pool_hdr->object_count = 1;
+	pool_hdr->end = result;
 
-	tc_invalidate_pool(pool_tc);
+	tc_invalidate_pool(pool_hdr);
 
 	return result;
 }
@@ -770,10 +785,12 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr);
 static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 					const char *location)
 {
-	union talloc_pool_chunk *pool;
+	struct talloc_pool_hdr *pool;
+	struct talloc_chunk *pool_tc;
 	void *next_tc;
 
 	pool = tc->pool;
+	pool_tc = talloc_chunk_from_pool(pool);
 	next_tc = tc_next_chunk(tc);
 
 	tc->flags |= TALLOC_FLAG_FREE;
@@ -786,15 +803,15 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 
 	TC_INVALIDATE_FULL_CHUNK(tc);
 
-	if (unlikely(pool->hdr.object_count == 0)) {
+	if (unlikely(pool->object_count == 0)) {
 		talloc_abort("Pool object count zero!");
 		return;
 	}
 
-	pool->hdr.object_count--;
+	pool->object_count--;
 
-	if (unlikely(pool->hdr.object_count == 1
-		     && !(pool->hdr.c.flags & TALLOC_FLAG_FREE))) {
+	if (unlikely(pool->object_count == 1
+		     && !(pool_tc->flags & TALLOC_FLAG_FREE))) {
 		/*
 		 * if there is just one object left in the pool
 		 * and pool->flags does not have TALLOC_FLAG_FREE,
@@ -802,33 +819,33 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		 * the rest is available for new objects
 		 * again.
 		 */
-		pool->hdr.next = tc_pool_first_chunk(pool);
+		pool->end = tc_pool_first_chunk(pool);
 		tc_invalidate_pool(pool);
 		return;
 	}
 
-	if (unlikely(pool->hdr.object_count == 0)) {
+	if (unlikely(pool->object_count == 0)) {
 		/*
 		 * we mark the freed memory with where we called the free
 		 * from. This means on a double free error we can report where
 		 * the first free came from
 		 */
-		pool->hdr.c.name = location;
+		pool_tc->name = location;
 
-		talloc_memlimit_update_on_free(&pool->hdr.c);
+		talloc_memlimit_update_on_free(pool_tc);
 
-		TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c);
+		TC_INVALIDATE_FULL_CHUNK(pool_tc);
 		free(pool);
 		return;
 	}
 
-	if (pool->hdr.next == next_tc) {
+	if (pool->end == next_tc) {
 		/*
 		 * if pool->pool still points to end of
 		 * 'tc' (which is stored in the 'next_tc' variable),
 		 * we can reclaim the memory of 'tc'.
 		 */
-		pool->hdr.next = tc;
+		pool->end = tc;
 		return;
 	}
 
@@ -924,23 +941,30 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 	tc->name = location;
 
 	if (tc->flags & TALLOC_FLAG_POOL) {
-		union talloc_pool_chunk *pool = (union talloc_pool_chunk *)tc;
+		struct talloc_pool_hdr *pool;
+
+		pool = talloc_pool_from_chunk(tc);
 
-		if (unlikely(pool->hdr.object_count == 0)) {
+		if (unlikely(pool->object_count == 0)) {
 			talloc_abort("Pool object count zero!");
 			return 0;
 		}
 
-		pool->hdr.object_count--;
+		pool->object_count--;
 
-		if (likely(pool->hdr.object_count != 0)) {
+		if (likely(pool->object_count != 0)) {
 			return 0;
 		}
 
+		/*
+		 * This call takes into account the
+		 * prefix TP_HDR_SIZE allocated before
+		 * the pool talloc_chunk.
+		 */
 		talloc_memlimit_update_on_free(tc);
 
 		TC_INVALIDATE_FULL_CHUNK(tc);
-		free(tc);
+		free(pool);
 		return 0;
 	}
 
@@ -1486,7 +1510,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 	struct talloc_chunk *tc;
 	void *new_ptr;
 	bool malloced = false;
-	union talloc_pool_chunk *pool_tc = NULL;
+	struct talloc_pool_hdr *pool_hdr = NULL;
 	size_t old_size = 0;
 	size_t new_size = 0;
 
@@ -1526,19 +1550,19 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 
 	/* handle realloc inside a talloc_pool */
 	if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) {
-		pool_tc = tc->pool;
+		pool_hdr = tc->pool;
 	}
 
 #if (ALWAYS_REALLOC == 0)
 	/* don't shrink if we have less than 1k to gain */
 	if (size < tc->size && tc->limit == NULL) {
-		if (pool_tc) {
+		if (pool_hdr) {
 			void *next_tc = tc_next_chunk(tc);
 			TC_INVALIDATE_SHRINK_CHUNK(tc, size);
 			tc->size = size;
-			if (next_tc == pool_tc->hdr.next) {
+			if (next_tc == pool_hdr->end) {
 				/* note: tc->size has changed, so this works */
-				pool_tc->hdr.next = tc_next_chunk(tc);
+				pool_hdr->end = tc_next_chunk(tc);
 			}
 			return ptr;
 		} else if ((tc->size - size) < 1024) {
@@ -1569,9 +1593,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 	tc->flags |= TALLOC_FLAG_FREE;
 
 #if ALWAYS_REALLOC
-	if (pool_tc) {
+	if (pool_hdr) {
 		new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0);
-		pool_tc->hdr.object_count--;
+		pool_hdr->object_count--;
 
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
@@ -1594,15 +1618,17 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		}
 	}
 #else
-	if (pool_tc) {
+	if (pool_hdr) {
+		struct talloc_chunk *pool_tc;
 		void *next_tc = tc_next_chunk(tc);
 		size_t old_chunk_size = TC_ALIGN16(TC_HDR_SIZE + tc->size);
 		size_t new_chunk_size = TC_ALIGN16(TC_HDR_SIZE + size);
 		size_t space_needed;
 		size_t space_left;
-		unsigned int chunk_count = pool_tc->hdr.object_count;
+		unsigned int chunk_count = pool_hdr->object_count;
 
-		if (!(pool_tc->hdr.c.flags & TALLOC_FLAG_FREE)) {
+		pool_tc = talloc_chunk_from_pool(pool_hdr);
+		if (!(pool_tc->flags & TALLOC_FLAG_FREE)) {
 			chunk_count -= 1;
 		}
 
@@ -1611,9 +1637,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			 * optimize for the case where 'tc' is the only
 			 * chunk in the pool.
 			 */
-			char *start = tc_pool_first_chunk(pool_tc);
+			char *start = tc_pool_first_chunk(pool_hdr);
 			space_needed = new_chunk_size;
-			space_left = (char *)tc_pool_end(pool_tc) - start;
+			space_left = (char *)tc_pool_end(pool_hdr) - start;
 
 			if (space_left >= space_needed) {
 				size_t old_used = TC_HDR_SIZE + tc->size;
@@ -1650,11 +1676,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 				 * because we want to invalidate the padding
 				 * too.
 				 */
-				pool_tc->hdr.next = new_used + (char *)new_ptr;
-				tc_invalidate_pool(pool_tc);
+				pool_hdr->end = new_used + (char *)new_ptr;
+				tc_invalidate_pool(pool_hdr);
 
 				/* now the aligned pointer */
-				pool_tc->hdr.next = new_chunk_size + (char *)new_ptr;
+				pool_hdr->end = new_chunk_size + (char *)new_ptr;
 				goto got_new_ptr;
 			}
 
@@ -1668,19 +1694,19 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 			return ptr;
 		}
 
-		if (next_tc == pool_tc->hdr.next) {
+		if (next_tc == pool_hdr->end) {
 			/*
 			 * optimize for the case where 'tc' is the last
 			 * chunk in the pool.
 			 */
 			space_needed = new_chunk_size - old_chunk_size;
-			space_left = tc_pool_space_left(pool_tc);
+			space_left = tc_pool_space_left(pool_hdr);
 
 			if (space_left >= space_needed) {
 				TC_UNDEFINE_GROW_CHUNK(tc, size);
 				tc->flags &= ~TALLOC_FLAG_FREE;
 				tc->size = size;
-				pool_tc->hdr.next = tc_next_chunk(tc);
+				pool_hdr->end = tc_next_chunk(tc);
 				return ptr;
 			}
 		}
@@ -1822,6 +1848,13 @@ static size_t _talloc_total_mem_internal(const void *ptr,
 			 */
 			if (!(tc->flags & TALLOC_FLAG_POOLMEM)) {
 				total = tc->size + TC_HDR_SIZE;
+				/*
+				 * If this is a pool, remember to
+				 * add the prefix length.
+				 */
+				if (tc->flags & TALLOC_FLAG_POOL) {
+					total += TP_HDR_SIZE;
+				}
 			}
 		}
 		break;
@@ -2579,6 +2612,8 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
 */
 static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
 {
+	size_t limit_shrink_size;
+
 	if (!tc->limit) {
 		return;
 	}
@@ -2597,7 +2632,18 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
 	 * we need to subtract the memory used from the counters
 	 */
 
-	talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE);
+	limit_shrink_size = tc->size+TC_HDR_SIZE;
+
+	/*
+	 * If we're deallocating a pool, take into
+	 * account the prefix size added for the pool.
+	 */
+
+	if (tc->flags & TALLOC_FLAG_POOL) {
+		limit_shrink_size += TP_HDR_SIZE;
+	}
+
+	talloc_memlimit_shrink(tc->limit, limit_shrink_size);
 
 	if (tc->limit->parent == tc) {
 		free(tc->limit);
-- 
1.8.4


From ce9e14fc8a8b121db3a66e69c8c20238573a5136 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 14:20:20 -0700
Subject: [PATCH 4/9] talloc: Add a separate pool size

This is necessary to allow talloc pools to be objects on their own. It
is an incompatible change in the sense that talloc_get_size(pool) now
returns 0 instead of the pool size. When the talloc_pooled_object()
call is added, this will start to make sense again.

Maybe we should add a talloc_pool_size call? Or is that overkill?

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/talloc/talloc.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index a553050..5d13567 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -461,6 +461,7 @@ _PUBLIC_ const char *talloc_parent_name(const void *ptr)
 struct talloc_pool_hdr {
 	void *end;
 	unsigned int object_count;
+	size_t poolsize;
 };
 
 #define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr))
@@ -478,7 +479,7 @@ static struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h)
 static void *tc_pool_end(struct talloc_pool_hdr *pool_hdr)
 {
 	struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr);
-	return (char *)tc + TC_HDR_SIZE + tc->size;
+	return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize;
 }
 
 static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr)
@@ -486,17 +487,18 @@ static size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr)
 	return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end;
 }
 
-static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr)
-{
-	return TC_PTR_FROM_CHUNK(talloc_chunk_from_pool(pool_hdr));
-}
-
 /* If tc is inside a pool, this gives the next neighbour. */
 static void *tc_next_chunk(struct talloc_chunk *tc)
 {
 	return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size);
 }
 
+static void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr)
+{
+	struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr);
+	return tc_next_chunk(tc);
+}
+
 /* Mark the whole remaining pool as not accessable */
 static void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr)
 {
@@ -678,9 +680,11 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size)
 		return NULL;
 	}
 	tc->flags |= TALLOC_FLAG_POOL;
+	tc->size = 0;
 
 	pool_hdr->object_count = 1;
 	pool_hdr->end = result;
+	pool_hdr->poolsize = size;
 
 	tc_invalidate_pool(pool_hdr);
 
@@ -1847,13 +1851,20 @@ static size_t _talloc_total_mem_internal(const void *ptr,
 			 * pool itself.
 			 */
 			if (!(tc->flags & TALLOC_FLAG_POOLMEM)) {
-				total = tc->size + TC_HDR_SIZE;
-				/*
-				 * If this is a pool, remember to
-				 * add the prefix length.
-				 */
 				if (tc->flags & TALLOC_FLAG_POOL) {
-					total += TP_HDR_SIZE;
+					/*
+					 * If this is a pool, the allocated
+					 * size is in the pool header, and
+					 * remember to add in the prefix
+					 * length.
+					 */
+					struct talloc_pool_hdr *pool_hdr
+							= talloc_pool_from_chunk(tc);
+					total = pool_hdr->poolsize +
+							TC_HDR_SIZE +
+							TP_HDR_SIZE;
+				} else {
+					total = tc->size + TC_HDR_SIZE;
 				}
 			}
 		}
-- 
1.8.4


From 1e09b440559044eba24fe91c6f9aa060e606fbaf Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 14:52:28 -0700
Subject: [PATCH 5/9] talloc: Allow nested pools.

Signed-off-by: Volker Lendecke <vl at samba.org>
Signed-off-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/talloc.c    | 47 +++++++++++++++++++++++++----------------------
 lib/talloc/talloc.h    |  3 +--
 lib/talloc/testsuite.c | 26 ++++++++++++++++++++++++++
 3 files changed, 52 insertions(+), 24 deletions(-)

diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 5d13567..198bab9 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -672,13 +672,6 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size)
 	tc = talloc_chunk_from_ptr(result);
 	pool_hdr = talloc_pool_from_chunk(tc);
 
-	if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) {
-		/* We don't handle this correctly, so fail. */
-		talloc_log("talloc: cannot allocate pool off another pool %s\n",
-			   talloc_get_name(context));
-		talloc_free(result);
-		return NULL;
-	}
 	tc->flags |= TALLOC_FLAG_POOL;
 	tc->size = 0;
 
@@ -836,10 +829,19 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		 */
 		pool_tc->name = location;
 
-		talloc_memlimit_update_on_free(pool_tc);
-
-		TC_INVALIDATE_FULL_CHUNK(pool_tc);
-		free(pool);
+		if (pool_tc->flags & TALLOC_FLAG_POOLMEM) {
+			_talloc_free_poolmem(pool_tc, location);
+		} else {
+			/*
+			 * The talloc_memlimit_update_on_free()
+			 * call takes into account the
+			 * prefix TP_HDR_SIZE allocated before
+			 * the pool talloc_chunk.
+			 */
+			talloc_memlimit_update_on_free(pool_tc);
+			TC_INVALIDATE_FULL_CHUNK(pool_tc);
+			free(pool);
+		}
 		return;
 	}
 
@@ -869,6 +871,7 @@ static inline void _talloc_free_children_internal(struct talloc_chunk *tc,
 static inline int _talloc_free_internal(void *ptr, const char *location)
 {
 	struct talloc_chunk *tc;
+	void *ptr_to_free;
 
 	if (unlikely(ptr == NULL)) {
 		return -1;
@@ -961,15 +964,13 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 		}
 
 		/*
-		 * This call takes into account the
-		 * prefix TP_HDR_SIZE allocated before
-		 * the pool talloc_chunk.
-		 */
-		talloc_memlimit_update_on_free(tc);
-
-		TC_INVALIDATE_FULL_CHUNK(tc);
-		free(pool);
-		return 0;
+		 * With object_count==0, a pool becomes a normal piece of
+		 * memory to free. If it's allocated inside a pool, it needs
+		 * to be freed as poolmem, else it needs to be just freed.
+		*/
+		ptr_to_free = pool;
+	} else {
+		ptr_to_free = tc;
 	}
 
 	if (tc->flags & TALLOC_FLAG_POOLMEM) {
@@ -980,7 +981,7 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
 	talloc_memlimit_update_on_free(tc);
 
 	TC_INVALIDATE_FULL_CHUNK(tc);
-	free(tc);
+	free(ptr_to_free);
 	return 0;
 }
 
@@ -2632,7 +2633,9 @@ static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
 	/*
 	 * Pool entries don't count. Only the pools
 	 * themselves are counted as part of the memory
-	 * limits.
+	 * limits. Note that this also takes care of
+	 * nested pools which have both flags
+	 * TALLOC_FLAG_POOLMEM|TALLOC_FLAG_POOL set.
 	 */
 	if (tc->flags & TALLOC_FLAG_POOLMEM) {
 		return;
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index f3cbcd0..aa9864b 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -839,8 +839,7 @@ void *talloc_find_parent_bytype(const void *ptr, #type);
  * talloc pool to a talloc parent outside the pool, the whole pool memory is
  * not free(3)'ed until that moved chunk is also talloc_free()ed.
  *
- * @param[in]  context  The talloc context to hang the result off (must not
- *			be another pool).
+ * @param[in]  context  The talloc context to hang the result off.
  *
  * @param[in]  size     Size of the talloc pool.
  *
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index 426c31a..f04f4f1 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -1267,6 +1267,30 @@ static bool test_pool_steal(void)
 	return true;
 }
 
+static bool test_pool_nest(void)
+{
+	void *p1, *p2, *p3;
+	void *e = talloc_new(NULL);
+
+	p1 = talloc_pool(NULL, 1024);
+	torture_assert("talloc_pool", p1 != NULL, "failed");
+
+	p2 = talloc_pool(p1, 500);
+	torture_assert("talloc_pool", p2 != NULL, "failed");
+
+	p3 = talloc_size(p2, 10);
+
+	talloc_steal(e, p3);
+
+	talloc_free(p2);
+
+	talloc_free(p3);
+
+	talloc_free(p1);
+
+	return true;
+}
+
 static bool test_free_ref_null_context(void)
 {
 	void *p1, *p2, *p3;
@@ -1567,6 +1591,8 @@ bool torture_local_talloc(struct torture_context *tctx)
 	setlinebuf(stdout);
 
 	test_reset();
+	ret &= test_pool_nest();
+	test_reset();
 	ret &= test_ref1();
 	test_reset();
 	ret &= test_ref2();
-- 
1.8.4


From 22a2c6b869f25b540dc348cf471782608db77d29 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 15:15:32 -0700
Subject: [PATCH 6/9] talloc: Add talloc_pooled_object

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 lib/talloc/ABI/pytalloc-util-2.1.0.sigs |  6 +++
 lib/talloc/ABI/talloc-2.1.0.sigs        | 64 ++++++++++++++++++++++++++++++++
 lib/talloc/talloc.c                     | 66 +++++++++++++++++++++++++++++++++
 lib/talloc/talloc.h                     | 37 ++++++++++++++++++
 lib/talloc/wscript                      |  2 +-
 5 files changed, 174 insertions(+), 1 deletion(-)
 create mode 100644 lib/talloc/ABI/pytalloc-util-2.1.0.sigs
 create mode 100644 lib/talloc/ABI/talloc-2.1.0.sigs

diff --git a/lib/talloc/ABI/pytalloc-util-2.1.0.sigs b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs
new file mode 100644
index 0000000..961c1a8
--- /dev/null
+++ b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs
@@ -0,0 +1,6 @@
+pytalloc_CObject_FromTallocPtr: PyObject *(void *)
+pytalloc_Check: int (PyObject *)
+pytalloc_GetObjectType: PyTypeObject *(void)
+pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
+pytalloc_steal: PyObject *(PyTypeObject *, void *)
+pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *)
diff --git a/lib/talloc/ABI/talloc-2.1.0.sigs b/lib/talloc/ABI/talloc-2.1.0.sigs
new file mode 100644
index 0000000..eae12cc
--- /dev/null
+++ b/lib/talloc/ABI/talloc-2.1.0.sigs
@@ -0,0 +1,64 @@
+_talloc: void *(const void *, size_t)
+_talloc_array: void *(const void *, size_t, unsigned int, const char *)
+_talloc_free: int (void *, const char *)
+_talloc_get_type_abort: void *(const void *, const char *, const char *)
+_talloc_memdup: void *(const void *, const void *, size_t, const char *)
+_talloc_move: void *(const void *, const void *)
+_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t)
+_talloc_realloc: void *(const void *, void *, size_t, const char *)
+_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *)
+_talloc_reference_loc: void *(const void *, const void *, const char *)
+_talloc_set_destructor: void (const void *, int (*)(void *))
+_talloc_steal_loc: void *(const void *, const void *, const char *)
+_talloc_zero: void *(const void *, size_t, const char *)
+_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *)
+talloc_asprintf: char *(const void *, const char *, ...)
+talloc_asprintf_append: char *(char *, const char *, ...)
+talloc_asprintf_append_buffer: char *(char *, const char *, ...)
+talloc_autofree_context: void *(void)
+talloc_check_name: void *(const void *, const char *)
+talloc_disable_null_tracking: void (void)
+talloc_enable_leak_report: void (void)
+talloc_enable_leak_report_full: void (void)
+talloc_enable_null_tracking: void (void)
+talloc_enable_null_tracking_no_autofree: void (void)
+talloc_find_parent_byname: void *(const void *, const char *)
+talloc_free_children: void (void *)
+talloc_get_name: const char *(const void *)
+talloc_get_size: size_t (const void *)
+talloc_increase_ref_count: int (const void *)
+talloc_init: void *(const char *, ...)
+talloc_is_parent: int (const void *, const void *)
+talloc_named: void *(const void *, size_t, const char *, ...)
+talloc_named_const: void *(const void *, size_t, const char *)
+talloc_parent: void *(const void *)
+talloc_parent_name: const char *(const void *)
+talloc_pool: void *(const void *, size_t)
+talloc_realloc_fn: void *(const void *, void *, size_t)
+talloc_reference_count: size_t (const void *)
+talloc_reparent: void *(const void *, const void *, const void *)
+talloc_report: void (const void *, FILE *)
+talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *)
+talloc_report_depth_file: void (const void *, int, int, FILE *)
+talloc_report_full: void (const void *, FILE *)
+talloc_set_abort_fn: void (void (*)(const char *))
+talloc_set_log_fn: void (void (*)(const char *))
+talloc_set_log_stderr: void (void)
+talloc_set_memlimit: int (const void *, size_t)
+talloc_set_name: const char *(const void *, const char *, ...)
+talloc_set_name_const: void (const void *, const char *)
+talloc_show_parents: void (const void *, FILE *)
+talloc_strdup: char *(const void *, const char *)
+talloc_strdup_append: char *(char *, const char *)
+talloc_strdup_append_buffer: char *(char *, const char *)
+talloc_strndup: char *(const void *, const char *, size_t)
+talloc_strndup_append: char *(char *, const char *, size_t)
+talloc_strndup_append_buffer: char *(char *, const char *, size_t)
+talloc_total_blocks: size_t (const void *)
+talloc_total_size: size_t (const void *)
+talloc_unlink: int (const void *, void *)
+talloc_vasprintf: char *(const void *, const char *, va_list)
+talloc_vasprintf_append: char *(char *, const char *, va_list)
+talloc_vasprintf_append_buffer: char *(char *, const char *, va_list)
+talloc_version_major: int (void)
+talloc_version_minor: int (void)
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 198bab9..1cb4d7d 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -685,6 +685,72 @@ _PUBLIC_ void *talloc_pool(const void *context, size_t size)
 }
 
 /*
+ * Create a talloc pool correctly sized for a basic size plus
+ * a number of subobjects whose total size is given. Essentially
+ * a custom allocator for talloc to reduce fragmentation.
+ */
+
+_PUBLIC_ void *_talloc_pooled_object(const void *ctx,
+				     size_t type_size,
+				     const char *type_name,
+				     unsigned num_subobjects,
+				     size_t total_subobjects_size)
+{
+	size_t poolsize, subobjects_slack, tmp;
+	struct talloc_chunk *tc;
+	struct talloc_pool_hdr *pool_hdr;
+	void *ret;
+
+	poolsize = type_size + total_subobjects_size;
+
+	if ((poolsize < type_size) || (poolsize < total_subobjects_size)) {
+		goto overflow;
+	}
+
+	if (num_subobjects == UINT_MAX) {
+		goto overflow;
+	}
+	num_subobjects += 1;       /* the object body itself */
+
+	/*
+	 * Alignment can increase the pool size by at most 15 bytes per object
+	 * plus alignment for the object itself
+	 */
+	subobjects_slack = (TC_HDR_SIZE + TP_HDR_SIZE + 15) * num_subobjects;
+	if (subobjects_slack < num_subobjects) {
+		goto overflow;
+	}
+
+	tmp = poolsize + subobjects_slack;
+	if ((tmp < poolsize) || (tmp < subobjects_slack)) {
+		goto overflow;
+	}
+	poolsize = tmp;
+
+	ret = talloc_pool(ctx, poolsize);
+	if (ret == NULL) {
+		return NULL;
+	}
+
+	tc = talloc_chunk_from_ptr(ret);
+	tc->size = type_size;
+
+	pool_hdr = talloc_pool_from_chunk(tc);
+
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+	VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, type_size);
+#endif
+
+	pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size));
+
+	talloc_set_name_const(ret, type_name);
+	return ret;
+
+overflow:
+	return NULL;
+}
+
+/*
   setup a destructor to be called on free of a pointer
   the destructor should return 0 on success, or -1 on failure.
   if the destructor fails then the free is failed, and the memory can
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index aa9864b..1b59390 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -847,6 +847,43 @@ void *talloc_find_parent_bytype(const void *ptr, #type);
  */
 void *talloc_pool(const void *context, size_t size);
 
+#ifdef DOXYGEN
+/**
+ * @brief Allocate a talloc object as/with an additional pool.
+ *
+ * This is like talloc_pool(), but's it's more flexible
+ * and allows an object to be a pool for its children.
+ *
+ * @param[in] ctx                   The talloc context to hang the result off.
+ *
+ * @param[in] type                  The type that we want to allocate.
+ *
+ * @param[in] num_subobjects        The expected number of subobjects, which will
+ *                                  be allocated within the pool. This allocates
+ *                                  space for talloc_chunk headers.
+ *
+ * @param[in] total_subobjects_size The size that all subobjects can use in total.
+ *
+ *
+ * @return              The allocated talloc object, NULL on error.
+ */
+void *talloc_pooled_object(const void *ctx, #type,
+			   unsigned num_subobjects,
+			   size_t total_subobjects_size);
+#else
+#define talloc_pooled_object(_ctx, _type, \
+			     _num_subobjects, \
+			     _total_subobjects_size) \
+	(_type *)_talloc_pooled_object((_ctx), sizeof(_type), #_type, \
+					(_num_subobjects), \
+					(_total_subobjects_size))
+void *_talloc_pooled_object(const void *ctx,
+			    size_t type_size,
+			    const char *type_name,
+			    unsigned num_subobjects,
+			    size_t total_subobjects_size);
+#endif
+
 /**
  * @brief Free a talloc chunk and NULL out the pointer.
  *
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index ecc5e24..1ca41f6 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'talloc'
-VERSION = '2.0.8'
+VERSION = '2.1.0'
 
 
 blddir = 'bin'
-- 
1.8.4


From f6d0f0245ab8e6b8830d48d131dbf45fd6ccb8be Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 15:30:38 -0700
Subject: [PATCH 7/9] talloc: Test the pooled object

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 lib/talloc/testsuite.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index f04f4f1..888d260 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -1291,6 +1291,40 @@ static bool test_pool_nest(void)
 	return true;
 }
 
+struct pooled {
+	char *s1;
+	char *s2;
+	char *s3;
+};
+
+static bool test_pooled_object(void)
+{
+	struct pooled *p;
+	const char *s1 = "hello";
+	const char *s2 = "world";
+	const char *s3 = "";
+
+	p = talloc_pooled_object(NULL, struct pooled, 3,
+			strlen(s1)+strlen(s2)+strlen(s3)+3);
+
+	if (talloc_get_size(p) != sizeof(struct pooled)) {
+		return false;
+	}
+
+	p->s1 = talloc_strdup(p, s1);
+
+	TALLOC_FREE(p->s1);
+	p->s1 = talloc_strdup(p, s2);
+	TALLOC_FREE(p->s1);
+
+	p->s1 = talloc_strdup(p, s1);
+	p->s2 = talloc_strdup(p, s2);
+	p->s3 = talloc_strdup(p, s3);
+
+	TALLOC_FREE(p);
+	return true;
+}
+
 static bool test_free_ref_null_context(void)
 {
 	void *p1, *p2, *p3;
@@ -1591,6 +1625,8 @@ bool torture_local_talloc(struct torture_context *tctx)
 	setlinebuf(stdout);
 
 	test_reset();
+	ret &= test_pooled_object();
+	test_reset();
 	ret &= test_pool_nest();
 	test_reset();
 	ret &= test_ref1();
-- 
1.8.4


From 6682f5e20e74be5b3b013746afe77cb41100f04e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 15:34:44 -0700
Subject: [PATCH 8/9] smbd: Use talloc_pooled_object in cp_smb_filename

Requires new talloc

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 source3/lib/filename_util.c | 48 ++++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c
index 19ffcc3..3ebf311 100644
--- a/source3/lib/filename_util.c
+++ b/source3/lib/filename_util.c
@@ -161,39 +161,55 @@ struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx,
 				     const struct smb_filename *in)
 {
 	struct smb_filename *out;
+	size_t base_len = 0;
+	size_t stream_len = 0;
+	size_t lcomp_len = 0;
+	int num = 0;
 
 	/* stream_name must always be NULL if there is no stream. */
 	if (in->stream_name) {
 		SMB_ASSERT(in->stream_name[0] != '\0');
 	}
 
-	out = talloc_zero(mem_ctx, struct smb_filename);
+	if (in->base_name != NULL) {
+		base_len = strlen(in->base_name) + 1;
+		num += 1;
+	}
+	if (in->stream_name != NULL) {
+		stream_len = strlen(in->stream_name) + 1;
+		num += 1;
+	}
+	if (in->original_lcomp != NULL) {
+		lcomp_len = strlen(in->original_lcomp) + 1;
+		num += 1;
+	}
+
+	out = talloc_pooled_object(mem_ctx, struct smb_filename,
+				num, stream_len + base_len + lcomp_len);
 	if (out == NULL) {
 		return NULL;
 	}
+	ZERO_STRUCTP(out);
+
+	/*
+	 * The following allocations cannot fails as we
+	 * pre-allocated space for them in the out pooled
+	 * object.
+	 */
 	if (in->base_name != NULL) {
-		out->base_name = talloc_strdup(out, in->base_name);
-		if (out->base_name == NULL) {
-			goto fail;
-		}
+		out->base_name = talloc_memdup(
+				out, in->base_name, base_len);
 	}
 	if (in->stream_name != NULL) {
-		out->stream_name = talloc_strdup(out, in->stream_name);
-		if (out->stream_name == NULL) {
-			goto fail;
-		}
+		out->stream_name = talloc_memdup(
+				out, in->stream_name, stream_len);
 	}
 	if (in->original_lcomp != NULL) {
-		out->original_lcomp = talloc_strdup(out, in->original_lcomp);
-		if (out->original_lcomp == NULL) {
-			goto fail;
-		}
+		out->original_lcomp = talloc_memdup(
+				out, in->original_lcomp, lcomp_len);
 	}
 	out->st = in->st;
 	return out;
-fail:
-	TALLOC_FREE(out);
-	return NULL;
 }
 
 /****************************************************************************
-- 
1.8.4


From fba2a9afa81a1b86de60a670352254d5fd573df5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 6 Sep 2013 15:37:56 -0700
Subject: [PATCH 9/9] tevent: Use talloc_pooled_object for tevent_req_create

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 lib/tevent/tevent_req.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index d8d0c5f..556d984 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -61,10 +61,13 @@ struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
 	void **ppdata = (void **)pdata;
 	void *data;
 
-	req = talloc_zero(mem_ctx, struct tevent_req);
+	req = talloc_pooled_object(
+		mem_ctx, struct tevent_req, 2,
+		sizeof(struct tevent_immediate) + data_size);
 	if (req == NULL) {
 		return NULL;
 	}
+	ZERO_STRUCTP(req);
 	req->internal.private_type	= type;
 	req->internal.create_location	= location;
 	req->internal.finish_location	= NULL;
-- 
1.8.4



More information about the samba-technical mailing list