Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

HID: bpf: make hid_bpf_input_report() sleep until the device is ready

hid_bpf_input_report() is already marked to be used in sleepable context
only. So instead of hammering with timers the device to hopefully get
an available slot where the device is not sending events, we can make
that kfunc wait for the current event to be terminated before it goes in.

This allows to work with the following pseudo code:

in struct_ops/hid_device_event:
- schedule a bpf_wq, which calls hid_bpf_input_report()
- once this struct_ops function terminates, hid_bpf_input_report()
immediately starts before the next event

Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-9-cfd60fb6c79f@kernel.org
Acked-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

+26 -9
+12 -4
drivers/hid/bpf/hid_bpf_dispatch.c
··· 496 496 * @buf: a %PTR_TO_MEM buffer 497 497 * @buf__sz: the size of the data to transfer 498 498 * 499 - * Returns %0 on success, a negative error code otherwise. 499 + * Returns %0 on success, a negative error code otherwise. This function will wait for the 500 + * device to be available before injecting the event, thus needs to be called in sleepable 501 + * context. 500 502 */ 501 503 __bpf_kfunc int 502 504 hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf, 503 505 const size_t buf__sz) 504 506 { 505 - struct hid_device *hdev; 506 507 size_t size = buf__sz; 507 508 int ret; 509 + 510 + ret = down_interruptible(&ctx->hid->driver_input_lock); 511 + if (ret) 512 + return ret; 508 513 509 514 /* check arguments */ 510 515 ret = __hid_bpf_hw_check_params(ctx, buf, &size, type); 511 516 if (ret) 512 517 return ret; 513 518 514 - hdev = (struct hid_device *)ctx->hid; /* discard const */ 519 + ret = hid_ops->hid_input_report(ctx->hid, type, buf, size, 0, (__u64)ctx, 520 + true /* lock_already_taken */); 515 521 516 - return hid_ops->hid_input_report(hdev, type, buf, size, 0, (__u64)ctx); 522 + up(&ctx->hid->driver_input_lock); 523 + 524 + return ret; 517 525 } 518 526 __bpf_kfunc_end_defs(); 519 527
+12 -4
drivers/hid/hid-core.c
··· 2027 2027 2028 2028 2029 2029 static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, 2030 - u8 *data, u32 size, int interrupt, u64 source) 2030 + u8 *data, u32 size, int interrupt, u64 source, 2031 + bool lock_already_taken) 2031 2032 { 2032 2033 struct hid_report_enum *report_enum; 2033 2034 struct hid_driver *hdrv; ··· 2038 2037 if (!hid) 2039 2038 return -ENODEV; 2040 2039 2041 - if (down_trylock(&hid->driver_input_lock)) 2040 + ret = down_trylock(&hid->driver_input_lock); 2041 + if (lock_already_taken && !ret) { 2042 + up(&hid->driver_input_lock); 2043 + return -EINVAL; 2044 + } else if (!lock_already_taken && ret) { 2042 2045 return -EBUSY; 2046 + } 2043 2047 2044 2048 if (!hid->driver) { 2045 2049 ret = -ENODEV; ··· 2085 2079 ret = hid_report_raw_event(hid, type, data, size, interrupt); 2086 2080 2087 2081 unlock: 2088 - up(&hid->driver_input_lock); 2082 + if (!lock_already_taken) 2083 + up(&hid->driver_input_lock); 2089 2084 return ret; 2090 2085 } 2091 2086 ··· 2104 2097 int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, 2105 2098 int interrupt) 2106 2099 { 2107 - return __hid_input_report(hid, type, data, size, interrupt, 0); 2100 + return __hid_input_report(hid, type, data, size, interrupt, 0, 2101 + false /* lock_already_taken */); 2108 2102 } 2109 2103 EXPORT_SYMBOL_GPL(hid_input_report); 2110 2104
+2 -1
include/linux/hid_bpf.h
··· 72 72 int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len, 73 73 __u64 source, bool from_bpf); 74 74 int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, 75 - u8 *data, u32 size, int interrupt, u64 source); 75 + u8 *data, u32 size, int interrupt, u64 source, 76 + bool lock_already_taken); 76 77 struct module *owner; 77 78 const struct bus_type *bus_type; 78 79 };