summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2007-03-12 16:55:12 +0300
committerJiri Kosina <jkosina@suse.cz>2007-03-12 16:55:12 +0300
commit47a80edb1d80ae644ea374a016c8e68d43d2671f (patch)
tree374089eed300fbc95b8286805cdb43333af9fc30 /drivers
parentbe521466feb3bb1cd89de82a2b1d080e9ebd3cb6 (diff)
downloadlinux-47a80edb1d80ae644ea374a016c8e68d43d2671f.tar.xz
HID: allocate hid_parser in a proper way
hid_parser is non-trivially large structure, so it should be allocated using vmalloc() to avoid unsuccessful allocations when memory fragmentation is too high. This structue has a very short life, it's destroyed as soon as the report descriptor has been completely parsed. This should be considered a temporary solution, until the hid_parser is rewritten to consume less memory during report descriptor parsing. Acked-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/hid-core.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index f4ee1afe488f..e5894a75a6f3 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -26,6 +26,7 @@
#include <asm/byteorder.h>
#include <linux/input.h>
#include <linux/wait.h>
+#include <linux/vmalloc.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
@@ -654,12 +655,13 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
memcpy(device->rdesc, start, size);
device->rsize = size;
- if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+ if (!(parser = vmalloc(sizeof(struct hid_parser)))) {
kfree(device->rdesc);
kfree(device->collection);
kfree(device);
return NULL;
}
+ memset(parser, 0, sizeof(struct hid_parser));
parser->device = device;
end = start + size;
@@ -668,7 +670,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (item.format != HID_ITEM_FORMAT_SHORT) {
dbg("unexpected long global item");
hid_free_device(device);
- kfree(parser);
+ vfree(parser);
return NULL;
}
@@ -676,7 +678,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
dbg("item %u %u %u %u parsing failed\n",
item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
hid_free_device(device);
- kfree(parser);
+ vfree(parser);
return NULL;
}
@@ -684,23 +686,23 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (parser->collection_stack_ptr) {
dbg("unbalanced collection at end of report description");
hid_free_device(device);
- kfree(parser);
+ vfree(parser);
return NULL;
}
if (parser->local.delimiter_depth) {
dbg("unbalanced delimiter at end of report description");
hid_free_device(device);
- kfree(parser);
+ vfree(parser);
return NULL;
}
- kfree(parser);
+ vfree(parser);
return device;
}
}
dbg("item fetching failed at offset %d\n", (int)(end - start));
hid_free_device(device);
- kfree(parser);
+ vfree(parser);
return NULL;
}
EXPORT_SYMBOL_GPL(hid_parse_report);