[SCM] Samba Shared Repository - branch master updated
Jeremy Allison
jra at samba.org
Tue Aug 27 18:45:03 MDT 2013
The branch, master has been updated
via 617c647 Fix valgrind errors with memmove and talloc pools.
via cbfc3ef Add simple limited pool tests to test_memlimit().
via 3d0f717 Remove talloc_memlimit_update(). No longer used.
via 8e2a543 Inside _talloc_realloc(), keep track of size changes over malloc/realloc/free.
via 314508d Don't call talloc_memlimit_update() inside _talloc_realloc() when we're just manipulating pool members.
via 0fbcfcc Fix a conditional check. (size - tc->size > 0) is always true if size and tc->size are unsigned.
via 4386029 In _talloc_steal_internal(), correctly decrement the memory limit in the source, and increment in the destination.
via 6bc190d Inside _talloc_free_internal(), always call talloc_memlimit_update_on_free() before we free the real memory.
via 4dfde7d Update memory limits when we call free() on a pool.
via a4ebbe7 Change __talloc() to only call talloc_memlimit_check()/talloc_memlimit_grow() on actual malloc allocation.
via 4159a78 Change _talloc_total_mem_internal() to ignore memory allocated from a pool when calculating limit size.
via 7a6beae Remove magic TC_HDR_SIZE handling inside talloc_memlimit_check().
via fe790f6 Start to fix talloc memlimits with talloc pools.
from 323cccd smbd: Use #defines in smb2_getinfo_send
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 617c647b8ef562ace589a11a15eb460e6db71f2a
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 13:20:43 2013 -0700
Fix valgrind errors with memmove and talloc pools.
bin/smbtorture //127.0.0.1 local.talloc now runs with no valgrind errors.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: "Stefan (metze) Metzmacher" <metze at samba.org>
Autobuild-User(master): Jeremy Allison <jra at samba.org>
Autobuild-Date(master): Wed Aug 28 02:44:17 CEST 2013 on sn-devel-104
commit cbfc3efbfd4a3a6f3b031ce8ef375d37f2c545f3
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 13:09:03 2013 -0700
Add simple limited pool tests to test_memlimit().
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 3d0f717d437bb24f430fad788b9eb35e8fe8e0e8
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 13:08:33 2013 -0700
Remove talloc_memlimit_update(). No longer used.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 8e2a543e088cac36a5b6bbab1a6be961fa00cc4d
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 13:07:04 2013 -0700
Inside _talloc_realloc(), keep track of size changes over malloc/realloc/free.
Replace the last use of talloc_memlimit_update() with talloc_memlimit_grow()/
talloc_memlimit_shrink().
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 314508dd73105138d756f4ca3dfb65f1d368a9f7
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 13:03:27 2013 -0700
Don't call talloc_memlimit_update() inside _talloc_realloc() when we're just manipulating pool members.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 0fbcfcc824e474874c15d7c0b2ea0df408448906
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:59:04 2013 -0700
Fix a conditional check. (size - tc->size > 0) is always true if size and tc->size are unsigned.
Replace with (size > tc->size).
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 43860293225d14ca2c339277b42f8705322463ab
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:57:43 2013 -0700
In _talloc_steal_internal(), correctly decrement the memory limit in the source, and increment in the destination.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 6bc190d6dd7fd0ab028c39c1463477a863f6943a
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:54:38 2013 -0700
Inside _talloc_free_internal(), always call talloc_memlimit_update_on_free() before we free the real memory.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 4dfde7d33e7ac6c94833ecc758baff487ab67e4e
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:51:20 2013 -0700
Update memory limits when we call free() on a pool.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit a4ebbe73b4b8dcab4d344e693ad9796ec8997f87
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:49:00 2013 -0700
Change __talloc() to only call talloc_memlimit_check()/talloc_memlimit_grow() on actual malloc allocation.
Don't check the memlimit if the allocation was successful from a pool. We already
checked the memory limit when we created the pool.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 4159a78ed7eda340758e22286f16186987a20f2f
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:46:09 2013 -0700
Change _talloc_total_mem_internal() to ignore memory allocated from a pool when calculating limit size.
We must only count normal tallocs, or a talloc pool itself.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit 7a6beae68ee3f9a97e9e56f4e24a437839fb3e19
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:43:50 2013 -0700
Remove magic TC_HDR_SIZE handling inside talloc_memlimit_check().
Callers already account for TC_HDR_SIZE, do not add it twice.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
commit fe790f6cbc9b888a8d613cfb515f0d0c76daad47
Author: Jeremy Allison <jra at samba.org>
Date: Tue Aug 27 12:36:23 2013 -0700
Start to fix talloc memlimits with talloc pools.
Add the functions:
talloc_memlimit_grow(), talloc_memlimit_shrink(),
talloc_memlimit_update_on_free().
as replacements for talloc_memlimit_update().
The interface to talloc_memlimit_update() is very
hard to understand and use. The above functions
are (to me) much clearer.
The goal of these changes is to only update
the memlimits on malloc/free/realloc, not
on every pool allocation. That way we only
count pool creation as allocation from any
imposed limits, not allocation from an already
created pool.
Signed-off-by: Jeremy Allison <jra at samba.org>
Reviewed-by: Simo Sorce <idra at samba.org>
-----------------------------------------------------------------------
Summary of changes:
lib/talloc/talloc.c | 211 +++++++++++++++++++++++++++++-------------------
lib/talloc/testsuite.c | 27 ++++++
2 files changed, 155 insertions(+), 83 deletions(-)
Changeset truncated at 500 lines:
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 76f0aee..69d5a16 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -236,8 +236,11 @@ struct talloc_memlimit {
};
static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size);
-static bool talloc_memlimit_update(struct talloc_memlimit *limit,
- size_t old_size, size_t new_size);
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+ size_t size);
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+ size_t size);
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc);
typedef int (*talloc_destructor_t)(void *);
@@ -581,27 +584,24 @@ static inline void *__talloc(const void *context, size_t size)
limit = ptc->limit;
}
- if (!talloc_memlimit_check(limit, (TC_HDR_SIZE+size))) {
- errno = ENOMEM;
- return NULL;
- }
-
tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size);
}
if (tc == NULL) {
+ /*
+ * Only do the memlimit check/update on actual allocation.
+ */
+ if (!talloc_memlimit_check(limit, TC_HDR_SIZE + size)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
if (unlikely(tc == NULL)) return NULL;
tc->flags = TALLOC_MAGIC;
tc->pool = NULL;
- }
- if (limit != NULL) {
- struct talloc_memlimit *l;
-
- for (l = limit; l != NULL; l = l->upper) {
- l->cur_size += TC_HDR_SIZE+size;
- }
+ talloc_memlimit_grow(limit, TC_HDR_SIZE + size);
}
tc->limit = limit;
@@ -805,6 +805,8 @@ static inline void _talloc_free_poolmem(struct talloc_chunk *tc,
*/
pool->hdr.c.name = location;
+ talloc_memlimit_update_on_free(&pool->hdr.c);
+
TC_INVALIDATE_FULL_CHUNK(&pool->hdr.c);
free(pool);
return;
@@ -905,29 +907,6 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
tc->flags |= TALLOC_FLAG_FREE;
- /*
- * If we are part of a memory limited context hierarchy
- * we need to subtract the memory used from the counters
- */
- if (tc->limit) {
- struct talloc_memlimit *l;
-
- for (l = tc->limit; l != NULL; l = l->upper) {
- if (l->cur_size >= tc->size+TC_HDR_SIZE) {
- l->cur_size -= tc->size+TC_HDR_SIZE;
- } else {
- talloc_abort("cur_size memlimit counter not correct!");
- return 0;
- }
- }
-
- if (tc->limit->parent == tc) {
- free(tc->limit);
- }
-
- tc->limit = NULL;
- }
-
/* 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
@@ -948,6 +927,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
return 0;
}
+ talloc_memlimit_update_on_free(tc);
+
TC_INVALIDATE_FULL_CHUNK(tc);
free(tc);
return 0;
@@ -958,6 +939,8 @@ static inline int _talloc_free_internal(void *ptr, const char *location)
return 0;
}
+ talloc_memlimit_update_on_free(tc);
+
TC_INVALIDATE_FULL_CHUNK(tc);
free(tc);
return 0;
@@ -991,11 +974,8 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
ctx_size = _talloc_total_limit_size(ptr, NULL, NULL);
- if (!talloc_memlimit_update(tc->limit->upper, ctx_size, 0)) {
- talloc_abort("cur_size memlimit counter not correct!");
- errno = EINVAL;
- return NULL;
- }
+ /* Decrement the memory limit from the source .. */
+ talloc_memlimit_shrink(tc->limit->upper, ctx_size);
if (tc->limit->parent == tc) {
tc->limit->upper = NULL;
@@ -1043,13 +1023,9 @@ static void *_talloc_steal_internal(const void *new_ctx, const void *ptr)
if (tc->limit || new_tc->limit) {
ctx_size = _talloc_total_limit_size(ptr, tc->limit,
new_tc->limit);
- }
-
- if (new_tc->limit) {
- struct talloc_memlimit *l;
-
- for (l = new_tc->limit; l != NULL; l = l->upper) {
- l->cur_size += ctx_size;
+ /* .. and increment it in the destination. */
+ if (new_tc->limit) {
+ talloc_memlimit_grow(new_tc->limit, ctx_size);
}
}
@@ -1501,6 +1477,8 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
void *new_ptr;
bool malloced = false;
union talloc_pool_chunk *pool_tc = NULL;
+ size_t old_size = 0;
+ size_t new_size = 0;
/* size zero is equivalent to free() */
if (unlikely(size == 0)) {
@@ -1529,7 +1507,7 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
return NULL;
}
- if (tc->limit && (size - tc->size > 0)) {
+ if (tc->limit && (size > tc->size)) {
if (!talloc_memlimit_check(tc->limit, (size - tc->size))) {
errno = ENOMEM;
return NULL;
@@ -1588,6 +1566,7 @@ _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;
+ new_size = size;
}
if (new_ptr) {
@@ -1595,6 +1574,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
TC_INVALIDATE_FULL_CHUNK(tc);
}
} else {
+ /* We're doing malloc then free here, so record the difference. */
+ old_size = tc->size;
+ new_size = size;
new_ptr = malloc(size + TC_HDR_SIZE);
if (new_ptr) {
memcpy(new_ptr, tc, MIN(tc->size, size) + TC_HDR_SIZE);
@@ -1627,6 +1609,27 @@ _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;
@@ -1651,14 +1654,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
if (new_chunk_size == old_chunk_size) {
TC_UNDEFINE_GROW_CHUNK(tc, size);
tc->flags &= ~TALLOC_FLAG_FREE;
- if (!talloc_memlimit_update(tc->limit,
- tc->size, size)) {
- talloc_abort("cur_size memlimit counter not"
- " correct!");
- errno = EINVAL;
- return NULL;
- }
-
tc->size = size;
return ptr;
}
@@ -1674,13 +1669,6 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
if (space_left >= space_needed) {
TC_UNDEFINE_GROW_CHUNK(tc, size);
tc->flags &= ~TALLOC_FLAG_FREE;
- if (!talloc_memlimit_update(tc->limit,
- tc->size, size)) {
- talloc_abort("cur_size memlimit "
- "counter not correct!");
- errno = EINVAL;
- return NULL;
- }
tc->size = size;
pool_tc->hdr.c.pool = tc_next_chunk(tc);
return ptr;
@@ -1692,6 +1680,7 @@ _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;
+ new_size = size;
}
if (new_ptr) {
@@ -1701,6 +1690,9 @@ _PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, cons
}
}
else {
+ /* We're doing realloc here, so record the difference. */
+ old_size = tc->size;
+ new_size = size;
new_ptr = realloc(tc, size + TC_HDR_SIZE);
}
got_new_ptr:
@@ -1729,11 +1721,12 @@ got_new_ptr:
tc->next->prev = tc;
}
- if (!talloc_memlimit_update(tc->limit, tc->size, size)) {
- talloc_abort("cur_size memlimit counter not correct!");
- errno = EINVAL;
- return NULL;
+ if (new_size > old_size) {
+ talloc_memlimit_grow(tc->limit, new_size - old_size);
+ } else if (new_size < old_size) {
+ talloc_memlimit_shrink(tc->limit, old_size - new_size);
}
+
tc->size = size;
_talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
@@ -1812,7 +1805,14 @@ static size_t _talloc_total_mem_internal(const void *ptr,
break;
case TOTAL_MEM_LIMIT:
if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) {
- total = tc->size + TC_HDR_SIZE;
+ /*
+ * Don't count memory allocated from a pool
+ * when calculating limits. Only count the
+ * pool itself.
+ */
+ if (!(tc->flags & TALLOC_FLAG_POOLMEM)) {
+ total = tc->size + TC_HDR_SIZE;
+ }
}
break;
}
@@ -2556,7 +2556,7 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
for (l = limit; l != NULL; l = l->upper) {
if (l->max_size != 0 &&
((l->max_size <= l->cur_size) ||
- (l->max_size - l->cur_size < TC_HDR_SIZE+size))) {
+ (l->max_size - l->cur_size < size))) {
return false;
}
}
@@ -2564,26 +2564,71 @@ static bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size)
return true;
}
-static bool talloc_memlimit_update(struct talloc_memlimit *limit,
- size_t old_size, size_t new_size)
+/*
+ Update memory limits when freeing a talloc_chunk.
+*/
+static void talloc_memlimit_update_on_free(struct talloc_chunk *tc)
{
- struct talloc_memlimit *l;
- ssize_t d;
+ if (!tc->limit) {
+ return;
+ }
- if (old_size == 0) {
- d = new_size + TC_HDR_SIZE;
- } else {
- d = new_size - old_size;
+ /*
+ * Pool entries don't count. Only the pools
+ * themselves are counted as part of the memory
+ * limits.
+ */
+ if (tc->flags & TALLOC_FLAG_POOLMEM) {
+ return;
}
+
+ /*
+ * If we are part of a memory limited context hierarchy
+ * we need to subtract the memory used from the counters
+ */
+
+ talloc_memlimit_shrink(tc->limit, tc->size+TC_HDR_SIZE);
+
+ if (tc->limit->parent == tc) {
+ free(tc->limit);
+ }
+
+ tc->limit = NULL;
+}
+
+/*
+ Increase memory limit accounting after a malloc/realloc.
+*/
+static void talloc_memlimit_grow(struct talloc_memlimit *limit,
+ size_t size)
+{
+ struct talloc_memlimit *l;
+
for (l = limit; l != NULL; l = l->upper) {
- ssize_t new_cur_size = l->cur_size + d;
- if (new_cur_size < 0) {
- return false;
+ size_t new_cur_size = l->cur_size + size;
+ if (new_cur_size < l->cur_size) {
+ talloc_abort("logic error in talloc_memlimit_grow\n");
+ return;
}
l->cur_size = new_cur_size;
}
+}
- return true;
+/*
+ Decrease memory limit accounting after a free/realloc.
+*/
+static void talloc_memlimit_shrink(struct talloc_memlimit *limit,
+ size_t size)
+{
+ struct talloc_memlimit *l;
+
+ for (l = limit; l != NULL; l = l->upper) {
+ if (l->cur_size < size) {
+ talloc_abort("logic error in talloc_memlimit_shrink\n");
+ return;
+ }
+ l->cur_size = l->cur_size - size;
+ }
}
_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size)
diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c
index d456cbb..426c31a 100644
--- a/lib/talloc/testsuite.c
+++ b/lib/talloc/testsuite.c
@@ -1359,6 +1359,8 @@ static bool test_memlimit(void)
{
void *root;
char *l1, *l2, *l3, *l4, *l5, *t;
+ char *pool;
+ int i;
printf("test: memlimit\n# MEMORY LIMITS\n");
@@ -1520,6 +1522,31 @@ static bool test_memlimit(void)
talloc_report_full(root, stdout);
talloc_free(root);
+ /* Test memlimits with pools. */
+ pool = talloc_pool(NULL, 10*1024);
+ torture_assert("memlimit", pool != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+ talloc_set_memlimit(pool, 10*1024);
+ for (i = 0; i < 9; i++) {
+ l1 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l1 != NULL,
+ "failed: alloc should not fail due to memory limit\n");
+ }
+ /* The next alloc should fail. */
+ l2 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ /* Moving one of the children shouldn't change the limit,
+ as it's still inside the pool. */
+ root = talloc_new(NULL);
+ talloc_steal(root, l1);
+ l2 = talloc_size(pool, 1024);
+ torture_assert("memlimit", l2 == NULL,
+ "failed: alloc should fail due to memory limit\n");
+
+ talloc_free(pool);
+ talloc_free(root);
printf("success: memlimit\n");
return true;
--
Samba Shared Repository
More information about the samba-cvs
mailing list