* [PATCH 1/2] HID: core: factor out hid_parse_collections()
@ 2026-03-26 6:25 Dmitry Torokhov
2026-03-26 6:25 ` [PATCH 2/2] HID: core: use __free(kfree) and __free(kvfree) to clean up temporary buffers Dmitry Torokhov
2026-03-27 11:09 ` [PATCH 1/2] HID: core: factor out hid_parse_collections() Jiri Kosina
0 siblings, 2 replies; 3+ messages in thread
From: Dmitry Torokhov @ 2026-03-26 6:25 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
In preparation to making use of __free(...) cleanup facilities to
clean up temporary buffers, factor out code parsing collections into
a separate function to make the code simpler.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 169 ++++++++++++++++++++++-------------------
1 file changed, 89 insertions(+), 80 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 833df14ef68f..bb13dcb116a9 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1244,6 +1244,88 @@ void hid_setup_resolution_multiplier(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
+static int hid_parse_collections(struct hid_device *device)
+{
+ struct hid_parser *parser;
+ struct hid_item item;
+ const u8 *start = device->rdesc;
+ const u8 *end = start + device->rsize;
+ const u8 *next;
+ int ret;
+ static typeof(hid_parser_main) (* const dispatch_type[]) = {
+ hid_parser_main,
+ hid_parser_global,
+ hid_parser_local,
+ hid_parser_reserved
+ };
+
+ parser = vzalloc(sizeof(*parser));
+ if (!parser)
+ return -ENOMEM;
+
+ parser->device = device;
+
+ device->collection = kzalloc_objs(*device->collection,
+ HID_DEFAULT_NUM_COLLECTIONS);
+ if (!device->collection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+ for (unsigned int i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++)
+ device->collection[i].parent_idx = -1;
+
+ ret = -EINVAL;
+ while ((next = fetch_item(start, end, &item)) != NULL) {
+ start = next;
+
+ if (item.format != HID_ITEM_FORMAT_SHORT) {
+ hid_err(device, "unexpected long global item\n");
+ goto out;
+ }
+
+ if (dispatch_type[item.type](parser, &item)) {
+ hid_err(device, "item %u %u %u %u parsing failed\n",
+ item.format,
+ (unsigned int)item.size,
+ (unsigned int)item.type,
+ (unsigned int)item.tag);
+ goto out;
+ }
+ }
+
+ if (start != end) {
+ hid_err(device, "item fetching failed at offset %u/%u\n",
+ device->rsize - (unsigned int)(end - start),
+ device->rsize);
+ goto out;
+ }
+
+ if (parser->collection_stack_ptr) {
+ hid_err(device, "unbalanced collection at end of report description\n");
+ goto out;
+ }
+
+ if (parser->local.delimiter_depth) {
+ hid_err(device, "unbalanced delimiter at end of report description\n");
+ goto out;
+ }
+
+ /*
+ * fetch initial values in case the device's
+ * default multiplier isn't the recommended 1
+ */
+ hid_setup_resolution_multiplier(device);
+
+ device->status |= HID_STAT_PARSED;
+ ret = 0;
+
+out:
+ kfree(parser->collection_stack);
+ vfree(parser);
+ return ret;
+}
+
/**
* hid_open_report - open a driver-specific device report
*
@@ -1258,21 +1340,9 @@ EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
*/
int hid_open_report(struct hid_device *device)
{
- struct hid_parser *parser;
- struct hid_item item;
unsigned int size;
- const __u8 *start;
- const __u8 *end;
- const __u8 *next;
- int ret;
- int i;
- static int (*dispatch_type[])(struct hid_parser *parser,
- struct hid_item *item) = {
- hid_parser_main,
- hid_parser_global,
- hid_parser_local,
- hid_parser_reserved
- };
+ const u8 *start;
+ int error;
if (WARN_ON(device->status & HID_STAT_PARSED))
return -EBUSY;
@@ -1309,74 +1379,13 @@ int hid_open_report(struct hid_device *device)
device->rdesc = start;
device->rsize = size;
- parser = vzalloc(sizeof(struct hid_parser));
- if (!parser) {
- ret = -ENOMEM;
- goto alloc_err;
- }
-
- parser->device = device;
-
- end = start + size;
-
- device->collection = kzalloc_objs(struct hid_collection,
- HID_DEFAULT_NUM_COLLECTIONS);
- if (!device->collection) {
- ret = -ENOMEM;
- goto err;
- }
- device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
- for (i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++)
- device->collection[i].parent_idx = -1;
-
- ret = -EINVAL;
- while ((next = fetch_item(start, end, &item)) != NULL) {
- start = next;
-
- if (item.format != HID_ITEM_FORMAT_SHORT) {
- hid_err(device, "unexpected long global item\n");
- goto err;
- }
-
- if (dispatch_type[item.type](parser, &item)) {
- hid_err(device, "item %u %u %u %u parsing failed\n",
- item.format, (unsigned)item.size,
- (unsigned)item.type, (unsigned)item.tag);
- goto err;
- }
-
- if (start == end) {
- if (parser->collection_stack_ptr) {
- hid_err(device, "unbalanced collection at end of report description\n");
- goto err;
- }
- if (parser->local.delimiter_depth) {
- hid_err(device, "unbalanced delimiter at end of report description\n");
- goto err;
- }
-
- /*
- * fetch initial values in case the device's
- * default multiplier isn't the recommended 1
- */
- hid_setup_resolution_multiplier(device);
-
- kfree(parser->collection_stack);
- vfree(parser);
- device->status |= HID_STAT_PARSED;
-
- return 0;
- }
+ error = hid_parse_collections(device);
+ if (error) {
+ hid_close_report(device);
+ return error;
}
- hid_err(device, "item fetching failed at offset %u/%u\n",
- size - (unsigned int)(end - start), size);
-err:
- kfree(parser->collection_stack);
-alloc_err:
- vfree(parser);
- hid_close_report(device);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(hid_open_report);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 2/2] HID: core: use __free(kfree) and __free(kvfree) to clean up temporary buffers
2026-03-26 6:25 [PATCH 1/2] HID: core: factor out hid_parse_collections() Dmitry Torokhov
@ 2026-03-26 6:25 ` Dmitry Torokhov
2026-03-27 11:09 ` [PATCH 1/2] HID: core: factor out hid_parse_collections() Jiri Kosina
1 sibling, 0 replies; 3+ messages in thread
From: Dmitry Torokhov @ 2026-03-26 6:25 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, linux-kernel
This simplifies error handling and protects against memory leaks.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/hid/hid-core.c | 34 ++++++++++++----------------------
1 file changed, 12 insertions(+), 22 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bb13dcb116a9..b40953e0f52e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -924,7 +924,6 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
*/
static int hid_scan_report(struct hid_device *hid)
{
- struct hid_parser *parser;
struct hid_item item;
const __u8 *start = hid->dev_rdesc;
const __u8 *end = start + hid->dev_rsize;
@@ -936,7 +935,7 @@ static int hid_scan_report(struct hid_device *hid)
hid_parser_reserved
};
- parser = vzalloc(sizeof(struct hid_parser));
+ struct hid_parser *parser __free(kvfree) = vzalloc(sizeof(*parser));
if (!parser)
return -ENOMEM;
@@ -987,7 +986,6 @@ static int hid_scan_report(struct hid_device *hid)
}
kfree(parser->collection_stack);
- vfree(parser);
return 0;
}
@@ -1246,7 +1244,6 @@ EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier);
static int hid_parse_collections(struct hid_device *device)
{
- struct hid_parser *parser;
struct hid_item item;
const u8 *start = device->rdesc;
const u8 *end = start + device->rsize;
@@ -1259,7 +1256,7 @@ static int hid_parse_collections(struct hid_device *device)
hid_parser_reserved
};
- parser = vzalloc(sizeof(*parser));
+ struct hid_parser *parser __free(kvfree) = vzalloc(sizeof(*parser));
if (!parser)
return -ENOMEM;
@@ -1267,10 +1264,9 @@ static int hid_parse_collections(struct hid_device *device)
device->collection = kzalloc_objs(*device->collection,
HID_DEFAULT_NUM_COLLECTIONS);
- if (!device->collection) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!device->collection)
+ return -ENOMEM;
+
device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
for (unsigned int i = 0; i < HID_DEFAULT_NUM_COLLECTIONS; i++)
device->collection[i].parent_idx = -1;
@@ -1322,7 +1318,6 @@ static int hid_parse_collections(struct hid_device *device)
out:
kfree(parser->collection_stack);
- vfree(parser);
return ret;
}
@@ -1358,9 +1353,9 @@ int hid_open_report(struct hid_device *device)
* on a copy of our report descriptor so it can
* change it.
*/
- __u8 *buf = kmemdup(start, size, GFP_KERNEL);
+ u8 *buf __free(kfree) = kmemdup(start, size, GFP_KERNEL);
- if (buf == NULL)
+ if (!buf)
return -ENOMEM;
start = device->driver->report_fixup(device, buf, &size);
@@ -1371,8 +1366,7 @@ int hid_open_report(struct hid_device *device)
* needs to be cleaned up or not at the end.
*/
start = kmemdup(start, size, GFP_KERNEL);
- kfree(buf);
- if (start == NULL)
+ if (!start)
return -ENOMEM;
}
@@ -1998,11 +1992,11 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
int __hid_request(struct hid_device *hid, struct hid_report *report,
enum hid_class_request reqtype)
{
- char *buf, *data_buf;
+ u8 *data_buf;
int ret;
u32 len;
- buf = hid_alloc_report_buf(report, GFP_KERNEL);
+ u8 *buf __free(kfree) = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -2021,17 +2015,13 @@ int __hid_request(struct hid_device *hid, struct hid_report *report,
ret = hid_hw_raw_request(hid, report->id, buf, len, report->type, reqtype);
if (ret < 0) {
dbg_hid("unable to complete request: %d\n", ret);
- goto out;
+ return ret;
}
if (reqtype == HID_REQ_GET_REPORT)
hid_input_report(hid, report->type, buf, ret, 0);
- ret = 0;
-
-out:
- kfree(buf);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(__hid_request);
--
2.53.0.1018.g2bb0e51243-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH 1/2] HID: core: factor out hid_parse_collections()
2026-03-26 6:25 [PATCH 1/2] HID: core: factor out hid_parse_collections() Dmitry Torokhov
2026-03-26 6:25 ` [PATCH 2/2] HID: core: use __free(kfree) and __free(kvfree) to clean up temporary buffers Dmitry Torokhov
@ 2026-03-27 11:09 ` Jiri Kosina
1 sibling, 0 replies; 3+ messages in thread
From: Jiri Kosina @ 2026-03-27 11:09 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Benjamin Tissoires, linux-input, linux-kernel
On Wed, 25 Mar 2026, Dmitry Torokhov wrote:
> In preparation to making use of __free(...) cleanup facilities to
> clean up temporary buffers, factor out code parsing collections into
> a separate function to make the code simpler.
Both applied to hid.git#for-7.1/core-v2, thanks Dmitry!
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-27 11:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26 6:25 [PATCH 1/2] HID: core: factor out hid_parse_collections() Dmitry Torokhov
2026-03-26 6:25 ` [PATCH 2/2] HID: core: use __free(kfree) and __free(kvfree) to clean up temporary buffers Dmitry Torokhov
2026-03-27 11:09 ` [PATCH 1/2] HID: core: factor out hid_parse_collections() Jiri Kosina
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox