]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cleanup: Optimize guards
authorPeter Zijlstra <peterz@infradead.org>
Mon, 9 Mar 2026 16:40:42 +0000 (17:40 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 16 Mar 2026 12:16:49 +0000 (13:16 +0100)
Andrew reported that a guard() conversion of zone_lock increased the
code size unnecessarily.

It turns out the unconditional __GUARD_IS_ERR() is to blame. As
explored earlier [1], __GUARD_IS_ERR(), similar to IS_ERR_OR_NULL(),
generates somewhat sub-optimal code.

However, looking at things again, it is possible to avoid doing the
__GUARD_IS_ERR() unconditionally. Revert the normal destructors to a
simple NULL test and only add the IS_ERR bit to COND guards.

This cures the reported overhead; as compiled by GCC-16:

page_alloc.o:

pre: Total: Before=45299, After=45371, chg +0.16%
post: Total: Before=45299, After=45026, chg -0.60%

[1] https://lkml.kernel.org/r/20250513085001.GC25891@noisy.programming.kicks-ass.net

Reported-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Dan Williams <dan.j.williams@intel.com>
Link: https://patch.msgid.link/20260309164516.GE606826@noisy.programming.kicks-ass.net
include/linux/cleanup.h

index dbc4162921e9b2dac67f1912161abd64c9c5529e..ea95ca4bc11c2fb9fbcf670aa5b5a54011102669 100644 (file)
@@ -286,15 +286,18 @@ static __always_inline _type class_##_name##_constructor(_init_args)      \
        __no_context_analysis                                           \
 { _type t = _init; return t; }
 
-#define EXTEND_CLASS(_name, ext, _init, _init_args...)                 \
-typedef lock_##_name##_t lock_##_name##ext##_t;                        \
+#define EXTEND_CLASS_COND(_name, ext, _cond, _init, _init_args...)     \
+typedef lock_##_name##_t lock_##_name##ext##_t;                                \
 typedef class_##_name##_t class_##_name##ext##_t;                      \
-static __always_inline void class_##_name##ext##_destructor(class_##_name##_t *p) \
-{ class_##_name##_destructor(p); }                                     \
+static __always_inline void class_##_name##ext##_destructor(class_##_name##_t *_T) \
+{ if (_cond) return; class_##_name##_destructor(_T); }                 \
 static __always_inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
        __no_context_analysis \
 { class_##_name##_t t = _init; return t; }
 
+#define EXTEND_CLASS(_name, ext, _init, _init_args...)                 \
+       EXTEND_CLASS_COND(_name, ext, 0, _init, _init_args)
+
 #define CLASS(_name, var)                                              \
        class_##_name##_t var __cleanup(class_##_name##_destructor) =   \
                class_##_name##_constructor
@@ -394,12 +397,12 @@ static __maybe_unused const bool class_##_name##_is_conditional = _is_cond
        __DEFINE_GUARD_LOCK_PTR(_name, _T)
 
 #define DEFINE_GUARD(_name, _type, _lock, _unlock) \
-       DEFINE_CLASS(_name, _type, if (!__GUARD_IS_ERR(_T)) { _unlock; }, ({ _lock; _T; }), _type _T); \
+       DEFINE_CLASS(_name, _type, if (_T) { _unlock; }, ({ _lock; _T; }), _type _T); \
        DEFINE_CLASS_IS_GUARD(_name)
 
 #define DEFINE_GUARD_COND_4(_name, _ext, _lock, _cond) \
        __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
-       EXTEND_CLASS(_name, _ext, \
+       EXTEND_CLASS_COND(_name, _ext, __GUARD_IS_ERR(*_T), \
                     ({ void *_t = _T; int _RET = (_lock); if (_T && !(_cond)) _t = ERR_PTR(_RET); _t; }), \
                     class_##_name##_t _T) \
        static __always_inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \
@@ -488,7 +491,7 @@ typedef struct {                                                    \
 static __always_inline void class_##_name##_destructor(class_##_name##_t *_T) \
        __no_context_analysis                                           \
 {                                                                      \
-       if (!__GUARD_IS_ERR(_T->lock)) { _unlock; }                     \
+       if (_T->lock) { _unlock; }                                      \
 }                                                                      \
                                                                        \
 __DEFINE_GUARD_LOCK_PTR(_name, &_T->lock)
@@ -565,7 +568,7 @@ __DEFINE_LOCK_GUARD_0(_name, _lock)
 
 #define DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _cond)          \
        __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true);               \
-       EXTEND_CLASS(_name, _ext,                                       \
+       EXTEND_CLASS_COND(_name, _ext, __GUARD_IS_ERR(_T->lock),        \
                     ({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\
                        int _RET = (_lock);                             \
                        if (_T->lock && !(_cond)) _T->lock = ERR_PTR(_RET);\