aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichał Kępień <kernel@kempniu.pl>2017-03-08 09:20:10 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-03-08 14:28:53 -0800
commitfabeb165afd52a3fb05b9b68e5a3550609b8e157 (patch)
treea5851d7d6d6a45dd1e571b05de4bc07be9670514 /drivers
parentLinux 4.10 (diff)
downloadlinux-dev-fabeb165afd52a3fb05b9b68e5a3550609b8e157.tar.xz
linux-dev-fabeb165afd52a3fb05b9b68e5a3550609b8e157.zip
Input: sparse-keymap - use a managed allocation for keymap copy
Some platform drivers use devm_input_allocate_device() together with sparse_keymap_setup() in their .probe callbacks. While using the former simplifies error handling, using the latter necessitates calling sparse_keymap_free() in the error path and upon module unloading to avoid leaking the copy of the keymap allocated by sparse_keymap_setup(). To help prevent such leaks and enable simpler error handling, make sparse_keymap_setup() use devm_kmemdup() to create the keymap copy so that it gets automatically freed. This works for both managed and non-managed input devices as the keymap is freed after the last reference to the input device is dropped. Note that actions previously taken by sparse_keymap_free(), i.e. taking the input device's mutex and zeroing its keycode and keycodemax fields, are now redundant because the managed keymap will always be freed after the input device is unregistered. Signed-off-by: Michał Kępień <kernel@kempniu.pl> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/sparse-keymap.c39
1 files changed, 9 insertions, 30 deletions
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index e7409c45bdd0..12a3ad83296d 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -160,12 +160,12 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
* @keymap: Keymap in form of array of &key_entry structures ending
* with %KE_END type entry
* @setup: Function that can be used to adjust keymap entries
- * depending on device's deeds, may be %NULL
+ * depending on device's needs, may be %NULL
*
* The function calculates size and allocates copy of the original
* keymap after which sets up input device event bits appropriately.
- * Before destroying input device allocated keymap should be freed
- * with a call to sparse_keymap_free().
+ * The allocated copy of the keymap is automatically freed when it
+ * is no longer needed.
*/
int sparse_keymap_setup(struct input_dev *dev,
const struct key_entry *keymap,
@@ -180,19 +180,18 @@ int sparse_keymap_setup(struct input_dev *dev,
for (e = keymap; e->type != KE_END; e++)
map_size++;
- map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL);
+ map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
+ GFP_KERNEL);
if (!map)
return -ENOMEM;
- memcpy(map, keymap, map_size * sizeof(struct key_entry));
-
for (i = 0; i < map_size; i++) {
entry = &map[i];
if (setup) {
error = setup(dev, entry);
if (error)
- goto err_out;
+ return error;
}
switch (entry->type) {
@@ -221,10 +220,6 @@ int sparse_keymap_setup(struct input_dev *dev,
dev->setkeycode = sparse_keymap_setkeycode;
return 0;
-
- err_out:
- kfree(map);
- return error;
}
EXPORT_SYMBOL(sparse_keymap_setup);
@@ -232,29 +227,13 @@ EXPORT_SYMBOL(sparse_keymap_setup);
* sparse_keymap_free - free memory allocated for sparse keymap
* @dev: Input device using sparse keymap
*
- * This function is used to free memory allocated by sparse keymap
+ * This function used to free memory allocated by sparse keymap
* in an input device that was set up by sparse_keymap_setup().
- * NOTE: It is safe to cal this function while input device is
- * still registered (however the drivers should care not to try to
- * use freed keymap and thus have to shut off interrupts/polling
- * before freeing the keymap).
+ * Since sparse_keymap_setup() now uses a managed allocation for the
+ * keymap copy, use of this function is deprecated.
*/
void sparse_keymap_free(struct input_dev *dev)
{
- unsigned long flags;
-
- /*
- * Take event lock to prevent racing with input_get_keycode()
- * and input_set_keycode() if we are called while input device
- * is still registered.
- */
- spin_lock_irqsave(&dev->event_lock, flags);
-
- kfree(dev->keycode);
- dev->keycode = NULL;
- dev->keycodemax = 0;
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
EXPORT_SYMBOL(sparse_keymap_free);