talloc_pooled_object patchset

Jeremy Allison jra at samba.org
Thu Aug 22 15:54:48 MDT 2013


On Tue, Aug 06, 2013 at 07:47:22AM +0200, Volker Lendecke wrote:
> Hi!
> 
> Attached find a patchset that implements
> talloc_pooled_object. The idea is basically that
> tevent_req_create only does one malloc instead of three, and
> for example cp_smb_filename also does just one:
> 
> talloc_pooled_object allocates a basic object as a pool
> similar to talloc(). Additionally, this object itself is a
> pool that will host num_members of user-visible size
> member_size.
> 
> A very simple test fetching a 1G file with aio read size = 1
> with smbclient according to valgrind's callgrind gives a
> reduction of user-space instructions of roughly 7%. In more
> complex tests, I think this has also the potential to reduce
> malloc fragmentation.
> 
> This is not yet ready for pushing, with valgrind I still see
> invalid writes. But I suspect this is due to invalid
> valgrind instrumentation, this patchset does survive
> autobuild.

Here are the fixes on top of your patchset that
fix the valgrind issues.

Note the actual code you wrote is 100% good, it's
merely the valgrind marking of regions as NOACCESS/
UNDEFINED that needed fixing :-).

I'm going to break this up into small patches
and then submit on top of your patchset for
review so we can get this code in !

Cheers & thanks for the *excellent* work here !

Are there more areas we can use talloc_pooled_object
as a custom allocator to reduce our allocations
and fragmentations ? Anywhere we're allocating
talloc'ed structures would seem to be good for
this.

Cheers,

	Jeremy.
-------------- next part --------------
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 8d8e621..9090610 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -609,6 +609,10 @@ static inline void *__talloc_with_prefix(const void *context, size_t size,
 			return NULL;
 		}
 
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+		VALGRIND_MAKE_MEM_UNDEFINED(ptr, total_len);
+#endif
+
 		tc = (struct talloc_chunk *)(ptr + prefix_len);
 		tc->flags = TALLOC_MAGIC;
 		tc->pool  = NULL;
@@ -729,7 +733,6 @@ _PUBLIC_ void *_talloc_pooled_object(const void *ctx, size_t size,
 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
 	VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, size);
 #endif
-	memset(pool_hdr->end, 0, size);
 
 	pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(size));
 
@@ -885,11 +888,10 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
 		 */
 		pool_tc->name = location;
 
-		TC_INVALIDATE_FULL_CHUNK(pool_tc);
-
 		if (pool_tc->flags & TALLOC_FLAG_POOLMEM) {
 			_talloc_free_poolmem(pool_tc, location);
 		} else {
+			TC_INVALIDATE_FULL_CHUNK(pool_tc);
 			free(pool);
 		}
 		return;
@@ -1680,6 +1682,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+			if (new_ptr) {
+				VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, TC_HDR_SIZE+size);
+			}
+#endif
 			malloced = true;
 		}
 
@@ -1690,6 +1697,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 	} else {
 		new_ptr = malloc(size + TC_HDR_SIZE);
 		if (new_ptr) {
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+			VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, size+TC_HDR_SIZE);
+#endif
 			memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE);
 			free(tc);
 		}
@@ -1722,6 +1732,25 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 				size_t old_used = TC_HDR_SIZE + tc->size;
 				size_t new_used = TC_HDR_SIZE + size;
 				new_ptr = start;
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+				{
+					/*
+					 * The area from
+					 * start -> tc may have
+					 * been freed and thus been marked as
+					 * VALGRIND_MEM_NOACCESS. Set it to
+					 * VALGRIND_MEM_UNDEFINED so we can
+					 * copy into it without valgrind errors.
+					 * We can't just mark
+					 * new_ptr -> new_ptr + old_used
+					 * as this may overlap on top of tc,
+					 * (which is why we use memmove, not
+					 * memcpy below) hence the MIN.
+					 */
+					size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used);
+					VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len);
+				}
+#endif
 				memmove(new_ptr, tc, old_used);
 
 				tc = (struct talloc_chunk *)new_ptr;
@@ -1788,6 +1817,11 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
 		if (new_ptr == NULL) {
 			new_ptr = malloc(TC_HDR_SIZE+size);
 			malloced = true;
+#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
+			if (new_ptr) {
+				VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, TC_HDR_SIZE+size);
+			}
+#endif
 		}
 
 		if (new_ptr) {


More information about the samba-technical mailing list