devilhorns pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=cb23fd2af2d07c17ae2d6c08a7c87cf8abf45814
commit cb23fd2af2d07c17ae2d6c08a7c87cf8abf45814 Author: Duna Oh <[email protected]> Date: Tue Dec 15 10:02:49 2015 -0500 ecore-drm: Fix failure of setting/closing evdev->fd which causes fd leak Summary: When a input device is plugged in, _cb_open_restricted() is called before creating evdev. So setting fd value on evdev was failed in _cb_open_restricted() and also closing evdev->fd was invalid. Using a eina_hash which has 'path-fd' pairs, we can find fd value after evdev is created. @fix Test Plan: (1) Multiple input devices are connected. Their evdev->fd remains zero or initial value. (2) When one of those devices are plugged out, fd leak would happen. Reviewers: raster, zmike, gwanglim, stefan_schmidt, devilhorns, ManMower Subscribers: cedric, jpeg, Jeon, input.hacker Differential Revision: https://phab.enlightenment.org/D3428 --- src/lib/ecore_drm/ecore_drm.c | 4 ++++ src/lib/ecore_drm/ecore_drm_inputs.c | 39 +++++++++++++++++++++------------- src/lib/ecore_drm/ecore_drm_launcher.c | 1 + src/lib/ecore_drm/ecore_drm_private.h | 2 ++ 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/lib/ecore_drm/ecore_drm.c b/src/lib/ecore_drm/ecore_drm.c index 6bbbde0..02dd76e 100644 --- a/src/lib/ecore_drm/ecore_drm.c +++ b/src/lib/ecore_drm/ecore_drm.c @@ -87,6 +87,8 @@ ecore_drm_init(void) /* try to init eeze */ if (!eeze_init()) goto eeze_err; + _ecore_drm_inputs_init(); + ECORE_DRM_EVENT_ACTIVATE = ecore_event_type_new(); ECORE_DRM_EVENT_OUTPUT = ecore_event_type_new(); ECORE_DRM_EVENT_SEAT_ADD = ecore_event_type_new(); @@ -141,6 +143,8 @@ ecore_drm_shutdown(void) /* shutdown eina */ eina_shutdown(); + _ecore_drm_inputs_shutdown(); + /* return init count */ return _ecore_drm_init_count; } diff --git a/src/lib/ecore_drm/ecore_drm_inputs.c b/src/lib/ecore_drm/ecore_drm_inputs.c index 75655ec..df46b19 100644 --- a/src/lib/ecore_drm/ecore_drm_inputs.c +++ b/src/lib/ecore_drm/ecore_drm_inputs.c @@ -5,15 +5,13 @@ #include "ecore_drm_private.h" EAPI int ECORE_DRM_EVENT_SEAT_ADD = -1; +static Eina_Hash *_fd_hash = NULL; /* local functions */ static int _cb_open_restricted(const char *path, int flags, void *data) { Ecore_Drm_Input *input; - Ecore_Drm_Seat *seat; - Ecore_Drm_Evdev *edev; - Eina_List *l, *ll; int fd = -1; if (!(input = data)) return -1; @@ -21,18 +19,8 @@ _cb_open_restricted(const char *path, int flags, void *data) /* try to open the device */ fd = _ecore_drm_launcher_device_open_no_pending(path, flags); if (fd < 0) ERR("Could not open device"); - - EINA_LIST_FOREACH(input->dev->seats, l, seat) - { - EINA_LIST_FOREACH(seat->devices, ll, edev) - { - if (strstr(path, edev->path)) - { - edev->fd = fd; - return fd; - } - } - } + if (_fd_hash) + eina_hash_add(_fd_hash, path, (void *)(intptr_t)fd); return fd; } @@ -54,6 +42,9 @@ _cb_close_restricted(int fd, void *data) if (edev->fd == fd) { _ecore_drm_launcher_device_close(edev->path, fd); + + /* re-initialize fd after closing */ + edev->fd = -1; return; } } @@ -118,6 +109,8 @@ _device_added(Ecore_Drm_Input *input, struct libinput_device *device) return; } + edev->fd = (int)(intptr_t)eina_hash_find(_fd_hash, edev->path); + /* append this device to the seat */ seat->devices = eina_list_append(seat->devices, edev); } @@ -134,6 +127,9 @@ _device_removed(Ecore_Drm_Input *input EINA_UNUSED, struct libinput_device *devi /* remove this evdev from the seat's list of devices */ edev->seat->devices = eina_list_remove(edev->seat->devices, edev); + if (_fd_hash) + eina_hash_del_by_key(_fd_hash, edev->path); + /* tell launcher to release device */ _ecore_drm_launcher_device_close(edev->path, edev->fd); @@ -345,3 +341,16 @@ ecore_drm_inputs_disable(Ecore_Drm_Input *input) input->suspended = EINA_TRUE; } + +void +_ecore_drm_inputs_init(void) +{ + _fd_hash = eina_hash_string_superfast_new(NULL); +} + +void +_ecore_drm_inputs_shutdown(void) +{ + eina_hash_free(_fd_hash); + _fd_hash = NULL; +} diff --git a/src/lib/ecore_drm/ecore_drm_launcher.c b/src/lib/ecore_drm/ecore_drm_launcher.c index 2baa550..6ba92ec 100644 --- a/src/lib/ecore_drm/ecore_drm_launcher.c +++ b/src/lib/ecore_drm/ecore_drm_launcher.c @@ -167,5 +167,6 @@ _ecore_drm_launcher_device_close(const char *device, int fd) { if ((logind) && (device)) _ecore_drm_logind_device_close(device); + if (fd < 0) return; close(fd); } diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h index aa97a20..fbc6bda 100644 --- a/src/lib/ecore_drm/ecore_drm_private.h +++ b/src/lib/ecore_drm/ecore_drm_private.h @@ -289,4 +289,6 @@ void _ecore_drm_dbus_device_release(uint32_t major, uint32_t minor); Eina_Bool _ecore_drm_dbus_session_take(void); Eina_Bool _ecore_drm_dbus_session_release(void); +void _ecore_drm_inputs_init(void); +void _ecore_drm_inputs_shutdown(void); #endif --
