]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
HID: bpf: hid_bpf_helpers: provide a cleanup functions
authorBenjamin Tissoires <bentiss@kernel.org>
Fri, 3 Apr 2026 16:12:20 +0000 (18:12 +0200)
committerJiri Kosina <jkosina@suse.com>
Wed, 8 Apr 2026 19:46:00 +0000 (21:46 +0200)
Combination of 2 udev-hid-bpf commits:
bpf: hid_bpf_helpers: provide a cleanup function for hid_bpf_release_context
bpf: helpers: add guard(bpf_spin) macro

Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/221
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/bpf/progs/hid_bpf_async.h
drivers/hid/bpf/progs/hid_bpf_helpers.h

index 9ab5854342393f38f849cb39b83ae86c8b1d73a4..877bb7e81f034b617a535eeffea2d1553406771c 100644 (file)
@@ -116,15 +116,14 @@ static int hid_bpf_async_find_empty_key(void)
                if (!elem)
                        return -ENOMEM; /* should never happen */
 
-               bpf_spin_lock(&elem->lock);
+               {
+                       guard(bpf_spin)(&elem->lock);
 
-               if (elem->state == HID_BPF_ASYNC_STATE_UNSET) {
-                       elem->state = HID_BPF_ASYNC_STATE_INITIALIZING;
-                       bpf_spin_unlock(&elem->lock);
-                       return i;
+                       if (elem->state == HID_BPF_ASYNC_STATE_UNSET) {
+                               elem->state = HID_BPF_ASYNC_STATE_INITIALIZING;
+                               return i;
+                       }
                }
-
-               bpf_spin_unlock(&elem->lock);
        }
 
        return -EINVAL;
@@ -175,18 +174,19 @@ static int hid_bpf_async_delayed_call(struct hid_bpf_ctx *hctx, u64 milliseconds
        if (!elem)
                return -EINVAL;
 
-       bpf_spin_lock(&elem->lock);
-       /* The wq must be:
-        * - HID_BPF_ASYNC_STATE_INITIALIZED -> it's been initialized and ready to be called
-        * - HID_BPF_ASYNC_STATE_RUNNING -> possible re-entry from the wq itself
-        */
-       if (elem->state != HID_BPF_ASYNC_STATE_INITIALIZED &&
-           elem->state != HID_BPF_ASYNC_STATE_RUNNING) {
-               bpf_spin_unlock(&elem->lock);
-               return -EINVAL;
+       {
+               guard(bpf_spin)(&elem->lock);
+
+               /* The wq must be:
+                * - HID_BPF_ASYNC_STATE_INITIALIZED -> it's been initialized and ready to be called
+                * - HID_BPF_ASYNC_STATE_RUNNING -> possible re-entry from the wq itself
+                */
+               if (elem->state != HID_BPF_ASYNC_STATE_INITIALIZED &&
+                   elem->state != HID_BPF_ASYNC_STATE_RUNNING)
+                       return -EINVAL;
+
+               elem->state = HID_BPF_ASYNC_STATE_STARTING;
        }
-       elem->state = HID_BPF_ASYNC_STATE_STARTING;
-       bpf_spin_unlock(&elem->lock);
 
        elem->hid = hctx->hid->id;
 
index 228f8d7875673a5b26cbc8e54063686d9ca9e7bf..5e3ffca1ed7b7ff7d1ec484e3359895d437c40ea 100644 (file)
@@ -40,6 +40,86 @@ extern int bpf_wq_set_callback(struct bpf_wq *wq,
 #define HID_MAX_DESCRIPTOR_SIZE        4096
 #define HID_IGNORE_EVENT       -1
 
+/**
+ * Use: _cleanup_(somefunction) struct foo *bar;
+ */
+#define _cleanup_(_x) __attribute__((cleanup(_x)))
+
+/**
+ * Use: _release_(foo) *bar;
+ *
+ * This requires foo_releasep() to be present, use DEFINE_RELEASE_CLEANUP_FUNC.
+ */
+#define _release_(_type) struct _type __attribute__((cleanup(_type##_releasep)))
+
+/**
+ * Define a cleanup function for the struct type foo with a matching
+ * foo_release(). Use:
+ * DEFINE_RELEASE_CLEANUP_FUNC(foo)
+ * _unref_(foo) struct foo *bar;
+ */
+#define DEFINE_RELEASE_CLEANUP_FUNC(_type)                             \
+       static inline void _type##_releasep(struct _type **_p) {        \
+               if (*_p)                                                \
+                       _type##_release(*_p);                           \
+       }                                                               \
+       struct __useless_struct_to_allow_trailing_semicolon__
+
+/* for being able to have a cleanup function */
+#define hid_bpf_ctx_release hid_bpf_release_context
+DEFINE_RELEASE_CLEANUP_FUNC(hid_bpf_ctx);
+
+/*
+ * Kernel-style guard macros adapted for BPF
+ * Based on include/linux/cleanup.h from the Linux kernel
+ *
+ * These provide automatic lock/unlock using __attribute__((cleanup))
+ * similar to how _release_() works for contexts.
+ */
+
+/**
+ * DEFINE_GUARD(name, type, lock, unlock):
+ *     Define a guard for automatic lock/unlock using the same pattern as _release_()
+ *     @name: identifier for the guard (e.g., bpf_spin)
+ *     @type: lock variable type (e.g., struct bpf_spin_lock)
+ *     @lock: lock function name (e.g., bpf_spin_lock)
+ *     @unlock: unlock function name (e.g., bpf_spin_unlock)
+ *
+ * guard(name):
+ *     Declare and lock in one statement - lock held until end of scope
+ *
+ * Example:
+ *     DEFINE_GUARD(bpf_spin, struct bpf_spin_lock, bpf_spin_lock, bpf_spin_unlock)
+ *
+ *     void foo(struct bpf_spin_lock *lock) {
+ *             guard(bpf_spin)(lock);
+ *             // lock held until end of scope
+ *     }
+ */
+
+/* Guard helper struct - stores lock pointer for cleanup */
+#define DEFINE_GUARD(_name, _type, _lock, _unlock)                     \
+struct _name##_guard {                                                 \
+       _type *lock;                                                    \
+};                                                                     \
+static inline void _name##_guard_cleanup(struct _name##_guard *g) {    \
+       if (g && g->lock)                                               \
+               _unlock(g->lock);                                       \
+}                                                                      \
+static inline struct _name##_guard _name##_guard_init(_type *l) {      \
+       if (l)                                                          \
+               _lock(l);                                               \
+       return (struct _name##_guard){.lock = l};                       \
+}                                                                      \
+struct __useless_struct_to_allow_trailing_semicolon__
+
+#define guard(_name) \
+       struct _name##_guard COMBINE(guard, __LINE__) __attribute__((cleanup(_name##_guard_cleanup))) = \
+               _name##_guard_init
+
+/* Define BPF spinlock guard */
+DEFINE_GUARD(bpf_spin, struct bpf_spin_lock, bpf_spin_lock, bpf_spin_unlock);
+
 /* extracted from <linux/input.h> */
 #define BUS_ANY                        0x00
 #define BUS_PCI                        0x01