Skip to content
Permalink
Browse files
HID: bpf: add support for new workqueue triggering BPF call
Add new bpf_hid_schedule_work() API to trigger execution of a BPF program
in a workqueue. A new BPF identifier is also added for the workqueue
program called hid/work.

Signed-off-by: Tero Kristo <tero.kristo@linux.intel.com>
  • Loading branch information
Tero Kristo committed Dec 15, 2021
1 parent 8f11b49 commit 8ffc42bfd37f05ffa2c284b71a6c3bb5021fac8f
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 0 deletions.
@@ -89,6 +89,8 @@ static int hid_bpf_prog_attach(struct hid_device *hdev, const union bpf_attr *at
return ret;

return hid_reconnect(hdev);
case BPF_HID_WORK:
return __hid_bpf_prog_attach(hdev, &hdev->bpf.work_prog, prog);
}

return -EINVAL;
@@ -163,6 +165,11 @@ int hid_bpf_prog_detach(struct hid_device *hdev, struct bpf_prog *prog)
return ret;

return hid_reconnect(hdev);
case BPF_HID_WORK:
if (prog != hdev->bpf.work_prog)
return -EINVAL;

return __hid_bpf_prog_detach(hdev, &hdev->bpf.work_prog);
default:
return -EINVAL;
}
@@ -577,6 +584,24 @@ static const struct bpf_func_proto bpf_hid_set_data_proto = {
.arg4_type = ARG_ANYTHING,
};

BPF_CALL_2(bpf_hid_schedule_work, void*, ctx, u64, timeout)
{
struct hid_bpf_ctx *bpf_ctx = ctx;

if (!delayed_work_pending(&bpf_ctx->work))
schedule_delayed_work(&bpf_ctx->work, timeout);

return 0;
}

static const struct bpf_func_proto bpf_hid_schedule_work_proto = {
.func = bpf_hid_schedule_work,
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_PTR_TO_CTX,
.arg2_type = ARG_ANYTHING,
};

static const struct bpf_func_proto *
hid_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
{
@@ -593,6 +618,8 @@ hid_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_hid_raw_request_proto;
case BPF_FUNC_hid_set_data:
return &bpf_hid_set_data_proto;
case BPF_FUNC_hid_schedule_work:
return &bpf_hid_schedule_work_proto;
default:
return bpf_base_func_proto(func_id);
}
@@ -659,6 +686,18 @@ static struct hid_device *__hid_bpf_fd_to_hdev(int fd)
return hdev;
}

static void hid_bpf_work(struct work_struct *work)
{
struct hid_bpf_ctx *ctx =
container_of(work, struct hid_bpf_ctx, work.work);

migrate_disable();

bpf_prog_run(ctx->hdev->bpf.work_prog, ctx);

migrate_enable();
}

static struct hid_bpf_ctx *hid_bpf_allocate(struct hid_device *hdev)
{
struct hid_bpf_ctx *ctx;
@@ -669,6 +708,8 @@ static struct hid_bpf_ctx *hid_bpf_allocate(struct hid_device *hdev)

ctx->hdev = hdev;

INIT_DELAYED_WORK(&ctx->work, hid_bpf_work);

return ctx;
}

@@ -371,6 +371,7 @@ struct hid_device { /* device report descriptor */
struct {
struct mutex lock;
struct bpf_prog __rcu *rdesc_fixup_prog;
struct bpf_prog __rcu *work_prog;
struct bpf_prog_array __rcu *event_progs;
struct bpf_prog_array __rcu *kevent_progs;
struct hid_bpf_ctx *ctx;
@@ -999,6 +999,7 @@ enum bpf_attach_type {
BPF_HID_RAW_EVENT,
BPF_HID_RDESC_FIXUP,
BPF_HID_KERNEL_EVENT,
BPF_HID_WORK,
__MAX_BPF_ATTACH_TYPE
};

@@ -4981,6 +4982,12 @@ union bpf_attr {
* Return
* The number of traversed items for success, **-EINVAL** for
* invalid **flags**.
*
* u32 bpf_hid_schedule_work(void *ctx, u64 timeout)
* Description
* Schedules a delayed work after the specified timeout.
* Return
* 0 on success, a negative error on failure.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5169,6 +5176,7 @@ union bpf_attr {
FN(hid_set_data), \
FN(hid_get_data), \
FN(hid_foreach_rdesc_item), \
FN(hid_schedule_work), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -10,6 +10,7 @@
#define _UAPI__LINUX_BPF_HID_H__

#include <linux/types.h>
#include <linux/workqueue.h>

#define HID_BPF_MAX_BUFFER_SIZE 16384 /* 16kb */

@@ -36,6 +37,7 @@ struct hid_bpf_ctx {
unsigned char request;
int retval;
} event;
struct delayed_work work;
};

/* in sync with struct hid_item */
@@ -3184,6 +3184,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
case BPF_HID_KERNEL_EVENT:
case BPF_HID_RAW_EVENT:
case BPF_HID_RDESC_FIXUP:
case BPF_HID_WORK:
return BPF_PROG_TYPE_HID;
default:
return BPF_PROG_TYPE_UNSPEC;
@@ -999,6 +999,7 @@ enum bpf_attach_type {
BPF_HID_RAW_EVENT,
BPF_HID_RDESC_FIXUP,
BPF_HID_KERNEL_EVENT,
BPF_HID_WORK,
__MAX_BPF_ATTACH_TYPE
};

@@ -4981,6 +4982,12 @@ union bpf_attr {
* Return
* The number of traversed items for success, **-EINVAL** for
* invalid **flags**.
*
* u32 bpf_hid_schedule_work(void *ctx, u64 timeout)
* Description
* Schedules a delayed work after the specified timeout.
* Return
* 0 on success, a negative error on failure.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5169,6 +5176,7 @@ union bpf_attr {
FN(hid_set_data), \
FN(hid_get_data), \
FN(hid_foreach_rdesc_item), \
FN(hid_schedule_work), \
/* */

/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -8370,6 +8370,7 @@ static const struct bpf_sec_def section_defs[] = {
SEC_DEF("hid/event", HID, BPF_HID_KERNEL_EVENT, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
SEC_DEF("hid/raw_event", HID, BPF_HID_RAW_EVENT, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
SEC_DEF("hid/rdesc_fixup", HID, BPF_HID_RDESC_FIXUP, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
SEC_DEF("hid/work", HID, BPF_HID_WORK, SEC_ATTACHABLE_OPT | SEC_SLOPPY_PFX),
};

#define MAX_TYPE_NAME_SIZE 32

0 comments on commit 8ffc42b

Please sign in to comment.