Skip to content

Commit 092d00e

Browse files
committed
cleanup: Provide retain_and_null_ptr()
In cases where an allocation is consumed by another function, the allocation needs to be retained on success or freed on failure. The code pattern is usually: struct foo *f = kzalloc(sizeof(*f), GFP_KERNEL); struct bar *b; ,,, // Initialize f ... if (ret) goto free; ... bar = bar_create(f); if (!bar) { ret = -ENOMEM; goto free; } ... return 0; free: kfree(f); return ret; This prevents using __free(kfree) on @f because there is no canonical way to tell the cleanup code that the allocation should not be freed. Abusing no_free_ptr() by force ignoring the return value is not really a sensible option either. Provide an explicit macro retain_and_null_ptr(), which NULLs the cleanup pointer. That makes it easy to analyze and reason about. Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: James Bottomley <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 0af2f6b commit 092d00e

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

include/linux/cleanup.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,25 @@ const volatile void * __must_check_fn(const volatile void *val)
216216

217217
#define return_ptr(p) return no_free_ptr(p)
218218

219+
/*
220+
* Only for situations where an allocation is handed in to another function
221+
* and consumed by that function on success.
222+
*
223+
* struct foo *f __free(kfree) = kzalloc(sizeof(*f), GFP_KERNEL);
224+
*
225+
* setup(f);
226+
* if (some_condition)
227+
* return -EINVAL;
228+
* ....
229+
* ret = bar(f);
230+
* if (!ret)
231+
* retain_and_null_ptr(f);
232+
* return ret;
233+
*
234+
* After retain_and_null_ptr(f) the variable f is NULL and cannot be
235+
* dereferenced anymore.
236+
*/
237+
#define retain_and_null_ptr(p) ((void)__get_and_null(p, NULL))
219238

220239
/*
221240
* DEFINE_CLASS(name, type, exit, init, init_args...):

0 commit comments

Comments
 (0)