devilhorns pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=cb23fd2af2d07c17ae2d6c08a7c87cf8abf45814

commit cb23fd2af2d07c17ae2d6c08a7c87cf8abf45814
Author: Duna Oh <duna...@samsung.com>
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

-- 


Reply via email to