Loading Documentation/core-api/cleanup.rst 0 → 100644 +8 −0 Original line number Diff line number Diff line .. SPDX-License-Identifier: GPL-2.0 =========================== Scope-based Cleanup Helpers =========================== .. kernel-doc:: include/linux/cleanup.h :doc: scope-based cleanup helpers Documentation/core-api/index.rst +1 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ Library functionality that is used throughout the kernel. kobject kref cleanup assoc_array xarray maple_tree Loading arch/x86/include/asm/atomic64_32.h +2 −4 Original line number Diff line number Diff line Loading @@ -163,20 +163,18 @@ static __always_inline s64 arch_atomic64_dec_return(atomic64_t *v) } #define arch_atomic64_dec_return arch_atomic64_dec_return static __always_inline s64 arch_atomic64_add(s64 i, atomic64_t *v) static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v) { __alternative_atomic64(add, add_return, ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_NO_INPUT_CLOBBER("memory")); return i; } static __always_inline s64 arch_atomic64_sub(s64 i, atomic64_t *v) static __always_inline void arch_atomic64_sub(s64 i, atomic64_t *v) { __alternative_atomic64(sub, sub_return, ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_NO_INPUT_CLOBBER("memory")); return i; } static __always_inline void arch_atomic64_inc(atomic64_t *v) Loading arch/x86/lib/atomic64_cx8_32.S +7 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ cmpxchg8b (\reg) .endm .macro read64_nonatomic reg movl (\reg), %eax movl 4(\reg), %edx .endm SYM_FUNC_START(atomic64_read_cx8) read64 %ecx RET Loading Loading @@ -51,7 +56,7 @@ SYM_FUNC_START(atomic64_\func\()_return_cx8) movl %edx, %edi movl %ecx, %ebp read64 %ecx read64_nonatomic %ecx 1: movl %eax, %ebx movl %edx, %ecx Loading Loading @@ -79,7 +84,7 @@ addsub_return sub sub sbb SYM_FUNC_START(atomic64_\func\()_return_cx8) pushl %ebx read64 %esi read64_nonatomic %esi 1: movl %eax, %ebx movl %edx, %ecx Loading include/linux/cleanup.h +136 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,142 @@ #include <linux/compiler.h> /** * DOC: scope-based cleanup helpers * * The "goto error" pattern is notorious for introducing subtle resource * leaks. It is tedious and error prone to add new resource acquisition * constraints into code paths that already have several unwind * conditions. The "cleanup" helpers enable the compiler to help with * this tedium and can aid in maintaining LIFO (last in first out) * unwind ordering to avoid unintentional leaks. * * As drivers make up the majority of the kernel code base, here is an * example of using these helpers to clean up PCI drivers. The target of * the cleanups are occasions where a goto is used to unwind a device * reference (pci_dev_put()), or unlock the device (pci_dev_unlock()) * before returning. * * The DEFINE_FREE() macro can arrange for PCI device references to be * dropped when the associated variable goes out of scope:: * * DEFINE_FREE(pci_dev_put, struct pci_dev *, if (_T) pci_dev_put(_T)) * ... * struct pci_dev *dev __free(pci_dev_put) = * pci_get_slot(parent, PCI_DEVFN(0, 0)); * * The above will automatically call pci_dev_put() if @dev is non-NULL * when @dev goes out of scope (automatic variable scope). If a function * wants to invoke pci_dev_put() on error, but return @dev (i.e. without * freeing it) on success, it can do:: * * return no_free_ptr(dev); * * ...or:: * * return_ptr(dev); * * The DEFINE_GUARD() macro can arrange for the PCI device lock to be * dropped when the scope where guard() is invoked ends:: * * DEFINE_GUARD(pci_dev, struct pci_dev *, pci_dev_lock(_T), pci_dev_unlock(_T)) * ... * guard(pci_dev)(dev); * * The lifetime of the lock obtained by the guard() helper follows the * scope of automatic variable declaration. Take the following example:: * * func(...) * { * if (...) { * ... * guard(pci_dev)(dev); // pci_dev_lock() invoked here * ... * } // <- implied pci_dev_unlock() triggered here * } * * Observe the lock is held for the remainder of the "if ()" block not * the remainder of "func()". * * Now, when a function uses both __free() and guard(), or multiple * instances of __free(), the LIFO order of variable definition order * matters. GCC documentation says: * * "When multiple variables in the same scope have cleanup attributes, * at exit from the scope their associated cleanup functions are run in * reverse order of definition (last defined, first cleanup)." * * When the unwind order matters it requires that variables be defined * mid-function scope rather than at the top of the file. Take the * following example and notice the bug highlighted by "!!":: * * LIST_HEAD(list); * DEFINE_MUTEX(lock); * * struct object { * struct list_head node; * }; * * static struct object *alloc_add(void) * { * struct object *obj; * * lockdep_assert_held(&lock); * obj = kzalloc(sizeof(*obj), GFP_KERNEL); * if (obj) { * LIST_HEAD_INIT(&obj->node); * list_add(obj->node, &list): * } * return obj; * } * * static void remove_free(struct object *obj) * { * lockdep_assert_held(&lock); * list_del(&obj->node); * kfree(obj); * } * * DEFINE_FREE(remove_free, struct object *, if (_T) remove_free(_T)) * static int init(void) * { * struct object *obj __free(remove_free) = NULL; * int err; * * guard(mutex)(&lock); * obj = alloc_add(); * * if (!obj) * return -ENOMEM; * * err = other_init(obj); * if (err) * return err; // remove_free() called without the lock!! * * no_free_ptr(obj); * return 0; * } * * That bug is fixed by changing init() to call guard() and define + * initialize @obj in this order:: * * guard(mutex)(&lock); * struct object *obj __free(remove_free) = alloc_add(); * * Given that the "__free(...) = NULL" pattern for variables defined at * the top of the function poses this potential interdependency problem * the recommendation is to always define and assign variables in one * statement and not group variable definitions at the top of the * function when __free() is used. * * Lastly, given that the benefit of cleanup helpers is removal of * "goto", and that the "goto" statement can jump between scopes, the * expectation is that usage of "goto" and cleanup helpers is never * mixed in the same function. I.e. for a given routine, convert all * resources that need a "goto" cleanup to scope-based cleanup, or * convert none of them. */ /* * DEFINE_FREE(name, type, free): * simple helper macro that defines the required wrapper for a __free() Loading Loading
Documentation/core-api/cleanup.rst 0 → 100644 +8 −0 Original line number Diff line number Diff line .. SPDX-License-Identifier: GPL-2.0 =========================== Scope-based Cleanup Helpers =========================== .. kernel-doc:: include/linux/cleanup.h :doc: scope-based cleanup helpers
Documentation/core-api/index.rst +1 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ Library functionality that is used throughout the kernel. kobject kref cleanup assoc_array xarray maple_tree Loading
arch/x86/include/asm/atomic64_32.h +2 −4 Original line number Diff line number Diff line Loading @@ -163,20 +163,18 @@ static __always_inline s64 arch_atomic64_dec_return(atomic64_t *v) } #define arch_atomic64_dec_return arch_atomic64_dec_return static __always_inline s64 arch_atomic64_add(s64 i, atomic64_t *v) static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v) { __alternative_atomic64(add, add_return, ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_NO_INPUT_CLOBBER("memory")); return i; } static __always_inline s64 arch_atomic64_sub(s64 i, atomic64_t *v) static __always_inline void arch_atomic64_sub(s64 i, atomic64_t *v) { __alternative_atomic64(sub, sub_return, ASM_OUTPUT2("+A" (i), "+c" (v)), ASM_NO_INPUT_CLOBBER("memory")); return i; } static __always_inline void arch_atomic64_inc(atomic64_t *v) Loading
arch/x86/lib/atomic64_cx8_32.S +7 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ cmpxchg8b (\reg) .endm .macro read64_nonatomic reg movl (\reg), %eax movl 4(\reg), %edx .endm SYM_FUNC_START(atomic64_read_cx8) read64 %ecx RET Loading Loading @@ -51,7 +56,7 @@ SYM_FUNC_START(atomic64_\func\()_return_cx8) movl %edx, %edi movl %ecx, %ebp read64 %ecx read64_nonatomic %ecx 1: movl %eax, %ebx movl %edx, %ecx Loading Loading @@ -79,7 +84,7 @@ addsub_return sub sub sbb SYM_FUNC_START(atomic64_\func\()_return_cx8) pushl %ebx read64 %esi read64_nonatomic %esi 1: movl %eax, %ebx movl %edx, %ecx Loading
include/linux/cleanup.h +136 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,142 @@ #include <linux/compiler.h> /** * DOC: scope-based cleanup helpers * * The "goto error" pattern is notorious for introducing subtle resource * leaks. It is tedious and error prone to add new resource acquisition * constraints into code paths that already have several unwind * conditions. The "cleanup" helpers enable the compiler to help with * this tedium and can aid in maintaining LIFO (last in first out) * unwind ordering to avoid unintentional leaks. * * As drivers make up the majority of the kernel code base, here is an * example of using these helpers to clean up PCI drivers. The target of * the cleanups are occasions where a goto is used to unwind a device * reference (pci_dev_put()), or unlock the device (pci_dev_unlock()) * before returning. * * The DEFINE_FREE() macro can arrange for PCI device references to be * dropped when the associated variable goes out of scope:: * * DEFINE_FREE(pci_dev_put, struct pci_dev *, if (_T) pci_dev_put(_T)) * ... * struct pci_dev *dev __free(pci_dev_put) = * pci_get_slot(parent, PCI_DEVFN(0, 0)); * * The above will automatically call pci_dev_put() if @dev is non-NULL * when @dev goes out of scope (automatic variable scope). If a function * wants to invoke pci_dev_put() on error, but return @dev (i.e. without * freeing it) on success, it can do:: * * return no_free_ptr(dev); * * ...or:: * * return_ptr(dev); * * The DEFINE_GUARD() macro can arrange for the PCI device lock to be * dropped when the scope where guard() is invoked ends:: * * DEFINE_GUARD(pci_dev, struct pci_dev *, pci_dev_lock(_T), pci_dev_unlock(_T)) * ... * guard(pci_dev)(dev); * * The lifetime of the lock obtained by the guard() helper follows the * scope of automatic variable declaration. Take the following example:: * * func(...) * { * if (...) { * ... * guard(pci_dev)(dev); // pci_dev_lock() invoked here * ... * } // <- implied pci_dev_unlock() triggered here * } * * Observe the lock is held for the remainder of the "if ()" block not * the remainder of "func()". * * Now, when a function uses both __free() and guard(), or multiple * instances of __free(), the LIFO order of variable definition order * matters. GCC documentation says: * * "When multiple variables in the same scope have cleanup attributes, * at exit from the scope their associated cleanup functions are run in * reverse order of definition (last defined, first cleanup)." * * When the unwind order matters it requires that variables be defined * mid-function scope rather than at the top of the file. Take the * following example and notice the bug highlighted by "!!":: * * LIST_HEAD(list); * DEFINE_MUTEX(lock); * * struct object { * struct list_head node; * }; * * static struct object *alloc_add(void) * { * struct object *obj; * * lockdep_assert_held(&lock); * obj = kzalloc(sizeof(*obj), GFP_KERNEL); * if (obj) { * LIST_HEAD_INIT(&obj->node); * list_add(obj->node, &list): * } * return obj; * } * * static void remove_free(struct object *obj) * { * lockdep_assert_held(&lock); * list_del(&obj->node); * kfree(obj); * } * * DEFINE_FREE(remove_free, struct object *, if (_T) remove_free(_T)) * static int init(void) * { * struct object *obj __free(remove_free) = NULL; * int err; * * guard(mutex)(&lock); * obj = alloc_add(); * * if (!obj) * return -ENOMEM; * * err = other_init(obj); * if (err) * return err; // remove_free() called without the lock!! * * no_free_ptr(obj); * return 0; * } * * That bug is fixed by changing init() to call guard() and define + * initialize @obj in this order:: * * guard(mutex)(&lock); * struct object *obj __free(remove_free) = alloc_add(); * * Given that the "__free(...) = NULL" pattern for variables defined at * the top of the function poses this potential interdependency problem * the recommendation is to always define and assign variables in one * statement and not group variable definitions at the top of the * function when __free() is used. * * Lastly, given that the benefit of cleanup helpers is removal of * "goto", and that the "goto" statement can jump between scopes, the * expectation is that usage of "goto" and cleanup helpers is never * mixed in the same function. I.e. for a given routine, convert all * resources that need a "goto" cleanup to scope-based cleanup, or * convert none of them. */ /* * DEFINE_FREE(name, type, free): * simple helper macro that defines the required wrapper for a __free() Loading