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
This commit is contained in:
Duna Oh 2015-12-15 10:02:49 -05:00 committed by Chris Michael
parent 7fd907a132
commit cb23fd2af2
4 changed files with 31 additions and 15 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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