lib: talloc: Allow destructors to reparent the object they're called on.
authorJeremy Allison <jra@samba.org>
Wed, 4 Mar 2015 01:02:47 +0000 (17:02 -0800)
committerJeremy Allison <jra@samba.org>
Sun, 8 Mar 2015 17:24:07 +0000 (18:24 +0100)
If a destructor returns failure (-1) when freeing a child, talloc
must then reparent the child.

Firstly it tries the owner of any reference, next the parent of the
current object calling _talloc_free_children_internal(), and finally
the null context in the last resort.

If a destructor reparented its own object, which can be a very
desirable thing to do (a destructor can make a decision it isn't
time to die yet, and as the parent may be going away it might
want to move itself to longer-term storage) then this new parent
gets overwritten by the existing reparenting logic.

This patch checks when freeing a child if it already reparented
itself, and if it did doesn't then overwrite the new parent.

Makes destructors more flexible.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Ira Cooper <ira@samba.org>
lib/talloc/talloc.c

index 1ccb039ff7448f56f67d7b69620fae3d46e420d7..46f10f4697cfce55393a687c2eb7a4c3c973ed4e 100644 (file)
@@ -1470,6 +1470,13 @@ static inline void _talloc_free_children_internal(struct talloc_chunk *tc,
                        if (p) new_parent = TC_PTR_FROM_CHUNK(p);
                }
                if (unlikely(_talloc_free_internal(child, location) == -1)) {
+                       if (talloc_parent_chunk(child) != tc) {
+                               /*
+                                * Destructor already reparented this child.
+                                * No further reparenting needed.
+                                */
+                               return;
+                       }
                        if (new_parent == null_context) {
                                struct talloc_chunk *p = talloc_parent_chunk(ptr);
                                if (p) new_parent = TC_PTR_FROM_CHUNK(p);