HID: bpf: protect HID-BPF prog_list access by a SRCU
We want to add sleepable callbacks for hid_hw_raw_request() and hid_hw_output_report(), but we can not use a plain RCU for those. Prepare for a SRCU so we can extend HID-BPF. This changes a little bit how hid_bpf_device_init() behaves, as it may now fail, so there is a tiny hid-core.c change to accommodate for this. Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-3-cfd60fb6c79f@kernel.org Acked-by: Jiri Kosina <jkosina@suse.com> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
This commit is contained in:
parent
67eccf151d
commit
6cd735f0e5
@ -506,13 +506,17 @@ void hid_bpf_destroy_device(struct hid_device *hdev)
|
||||
hdev->bpf.destroyed = true;
|
||||
|
||||
__hid_bpf_ops_destroy_device(hdev);
|
||||
|
||||
synchronize_srcu(&hdev->bpf.srcu);
|
||||
cleanup_srcu_struct(&hdev->bpf.srcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
|
||||
|
||||
void hid_bpf_device_init(struct hid_device *hdev)
|
||||
int hid_bpf_device_init(struct hid_device *hdev)
|
||||
{
|
||||
INIT_LIST_HEAD(&hdev->bpf.prog_list);
|
||||
mutex_init(&hdev->bpf.prog_list_lock);
|
||||
return init_srcu_struct(&hdev->bpf.srcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_bpf_device_init);
|
||||
|
||||
|
@ -214,6 +214,7 @@ static int hid_bpf_reg(void *kdata)
|
||||
list_add_rcu(&ops->list, &hdev->bpf.prog_list);
|
||||
else
|
||||
list_add_tail_rcu(&ops->list, &hdev->bpf.prog_list);
|
||||
synchronize_srcu(&hdev->bpf.srcu);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&hdev->bpf.prog_list_lock);
|
||||
@ -244,6 +245,7 @@ static void hid_bpf_unreg(void *kdata)
|
||||
mutex_lock(&hdev->bpf.prog_list_lock);
|
||||
|
||||
list_del_rcu(&ops->list);
|
||||
synchronize_srcu(&hdev->bpf.srcu);
|
||||
|
||||
reconnect = hdev->bpf.rdesc_ops == ops;
|
||||
if (reconnect)
|
||||
|
@ -2875,9 +2875,15 @@ struct hid_device *hid_allocate_device(void)
|
||||
mutex_init(&hdev->ll_open_lock);
|
||||
kref_init(&hdev->ref);
|
||||
|
||||
hid_bpf_device_init(hdev);
|
||||
ret = hid_bpf_device_init(hdev);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
return hdev;
|
||||
|
||||
out_err:
|
||||
hid_destroy_device(hdev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_allocate_device);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <uapi/linux/hid.h>
|
||||
|
||||
struct hid_device;
|
||||
@ -145,6 +146,7 @@ struct hid_bpf {
|
||||
struct hid_bpf_ops *rdesc_ops;
|
||||
struct list_head prog_list;
|
||||
struct mutex prog_list_lock; /* protects prog_list update */
|
||||
struct srcu_struct srcu; /* protects prog_list read-only access */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_HID_BPF
|
||||
@ -153,7 +155,7 @@ u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type t
|
||||
int hid_bpf_connect_device(struct hid_device *hdev);
|
||||
void hid_bpf_disconnect_device(struct hid_device *hdev);
|
||||
void hid_bpf_destroy_device(struct hid_device *hid);
|
||||
void hid_bpf_device_init(struct hid_device *hid);
|
||||
int hid_bpf_device_init(struct hid_device *hid);
|
||||
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
|
||||
#else /* CONFIG_HID_BPF */
|
||||
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
|
||||
@ -162,7 +164,7 @@ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid
|
||||
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
|
||||
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
|
||||
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
|
||||
static inline void hid_bpf_device_init(struct hid_device *hid) {}
|
||||
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
|
||||
#define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \
|
||||
((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user