[Mesa-dev] [PATCH v3 3/3] egl/android: Add DRM node probing and filtering

Rob Herring robh at kernel.org
Wed Jun 13 15:15:26 UTC 2018


+Amit and John

On Sat, Jun 9, 2018 at 11:27 AM, Robert Foss <robert.foss at collabora.com> wrote:
> This patch both adds support for probing & filtering DRM nodes
> and switches away from using the GRALLOC_MODULE_PERFORM_GET_DRM_FD
> gralloc call.
>
> Currently the filtering is based just on the driver name,
> and the desired name is supplied using the "drm.gpu.vendor_name"
> Android property.

There's a potential issue with this whole approach and that is
SELinux. With the way SELinux locks down accesses, getting probing
thru device files to work can be a pain. It may be better now than the
prior version because sysfs is not probed. I'll leave it to Amit or
John to comment.

Rob

>
> Signed-off-by: Robert Foss <robert.foss at collabora.com>
> ---
>
> Changes since v2:
>  - Switch from drmGetDevices2 to manual renderD node iteration
>  - Add probe_res enum to communicate probing results better
>  - Avoid using _eglError() in internal static functions
>  - Avoid actually loading the driver while probing, just verify
>    that it exists.
>  - Replace strlen call with the assumed length PROPERTY_VALUE_MAX
>
> Changes since v1:
>  - Do not rely on libdrm for probing
>  - Distinguish between errors and when no drm devices are found
>
> Changes since RFC:
>  - Rebased on newer libdrm drmHandleMatch patch
>  - Added support for driver probing
>
>
>  src/egl/drivers/dri2/platform_android.c | 222 ++++++++++++++++++------
>  1 file changed, 169 insertions(+), 53 deletions(-)
>
> diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
> index 4ba96aad90..a2cbe92d93 100644
> --- a/src/egl/drivers/dri2/platform_android.c
> +++ b/src/egl/drivers/dri2/platform_android.c
> @@ -27,12 +27,16 @@
>   * DEALINGS IN THE SOFTWARE.
>   */
>
> +#include <cutils/properties.h>
>  #include <errno.h>
> +#include <dirent.h>
>  #include <dlfcn.h>
>  #include <fcntl.h>
>  #include <xf86drm.h>
>  #include <stdbool.h>
> +#include <stdio.h>
>  #include <sync/sync.h>
> +#include <sys/types.h>
>
>  #include "loader.h"
>  #include "egl_dri2.h"
> @@ -1130,31 +1134,6 @@ droid_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *dpy)
>     return (config_count != 0);
>  }
>
> -enum {
> -        /* perform(const struct gralloc_module_t *mod,
> -         *         int op,
> -         *         int *fd);
> -         */
> -        GRALLOC_MODULE_PERFORM_GET_DRM_FD = 0x40000002,
> -};
> -
> -static int
> -droid_open_device(struct dri2_egl_display *dri2_dpy)
> -{
> -   int fd = -1, err = -EINVAL;
> -
> -   if (dri2_dpy->gralloc->perform)
> -         err = dri2_dpy->gralloc->perform(dri2_dpy->gralloc,
> -                                          GRALLOC_MODULE_PERFORM_GET_DRM_FD,
> -                                          &fd);
> -   if (err || fd < 0) {
> -      _eglLog(_EGL_WARNING, "fail to get drm fd");
> -      fd = -1;
> -   }
> -
> -   return (fd >= 0) ? fcntl(fd, F_DUPFD_CLOEXEC, 3) : -1;
> -}
> -
>  static const struct dri2_egl_display_vtbl droid_display_vtbl = {
>     .authenticate = NULL,
>     .create_window_surface = droid_create_window_surface,
> @@ -1215,6 +1194,168 @@ static const __DRIextension *droid_image_loader_extensions[] = {
>     NULL,
>  };
>
> +EGLBoolean
> +droid_load_driver(_EGLDisplay *disp)
> +{
> +   struct dri2_egl_display *dri2_dpy = disp->DriverData;
> +   const char *err;
> +
> +   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
> +   if (dri2_dpy->driver_name == NULL)
> +      return false;
> +
> +   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
> +
> +   if (!dri2_dpy->is_render_node) {
> +   #ifdef HAVE_DRM_GRALLOC
> +       /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names
> +        * for backwards compatibility with drm_gralloc. (Do not use on new
> +        * systems.) */
> +       dri2_dpy->loader_extensions = droid_dri2_loader_extensions;
> +       if (!dri2_load_driver(disp)) {
> +          err = "DRI2: failed to load driver";
> +          goto error;
> +       }
> +   #else
> +       err = "DRI2: handle is not for a render node";
> +       goto error;
> +   #endif
> +   } else {
> +       dri2_dpy->loader_extensions = droid_image_loader_extensions;
> +       if (!dri2_load_driver_dri3(disp)) {
> +          err = "DRI3: failed to load driver";
> +          goto error;
> +       }
> +    }
> +
> +   return true;
> +
> +error:
> +   free(dri2_dpy->driver_name);
> +   dri2_dpy->driver_name = NULL;
> +   return false;
> +}
> +
> +static bool
> +droid_probe_driver(int fd)
> +{
> +   char *driver_name;
> +
> +   driver_name = loader_get_driver_for_fd(fd);
> +   if (driver_name == NULL)
> +      return false;
> +
> +   free(driver_name);
> +   return true;
> +}
> +
> +typedef enum {
> +   probe_error = -1,
> +   probe_success = 0,
> +   probe_filtered_out = 1,
> +   probe_no_driver = 2
> +} probe_ret_t;
> +
> +static probe_ret_t
> +droid_probe_device(_EGLDisplay *disp, int fd, char *vendor)
> +{
> +   int ret;
> +
> +   drmVersionPtr ver = drmGetVersion(fd);
> +   if (!ver)
> +      return probe_error;
> +
> +   if (vendor != NULL && ver->name != NULL &&
> +       strncmp(vendor, ver->name, PROPERTY_VALUE_MAX) != 0) {
> +          ret = probe_filtered_out;
> +          goto cleanup;
> +       }
> +
> +
> +   if (!droid_probe_driver(fd)) {
> +      ret = probe_no_driver;
> +      goto cleanup;
> +   }
> +
> +   ret = probe_success;
> +
> +cleanup:
> +   drmFreeVersion(ver);
> +   return ret;
> +}
> +
> +static int
> +droid_open_device(_EGLDisplay *disp)
> +{
> +   const int MAX_DRM_DEVICES = 32;
> +   int prop_set, num_devices;
> +   int fd = -1, fallback_fd = -1;
> +
> +   char *vendor_name = NULL;
> +   char vendor_buf[PROPERTY_VALUE_MAX];
> +   if (property_get("drm.gpu.vendor_name", vendor_buf, NULL) > 0);
> +      vendor_name = vendor_buf;
> +
> +   const char *drm_dir_name = "/dev/dri";
> +   DIR *sysdir = opendir(drm_dir_name);
> +   if (!sysdir)
> +       return -errno;
> +
> +   struct dirent *dent;
> +   while ((dent = readdir(sysdir))) {
> +      char dev_path[128];
> +      char *render_dev_prefix = "renderD";
> +      size_t prefix_len = strlen(render_dev_prefix);
> +
> +      if (strncmp(render_dev_prefix, dent->d_name, prefix_len) != 0)
> +         continue;
> +
> +      sprintf(dev_path, "%s/%s", drm_dir_name, dent->d_name);
> +      fd = loader_open_device(dev_path);
> +      if (fd == -1) {
> +         _eglLog(_EGL_WARNING, "%s() Failed to open DRM device %s",
> +                 __func__, dev_path);
> +         continue;
> +      }
> +
> +      int ret = droid_probe_device(disp, fd, vendor_name);
> +      switch (ret) {
> +      case probe_success:
> +         goto success;
> +      case probe_filtered_out:
> +         goto allow_fallback;
> +      case probe_error:
> +      case probe_no_driver:
> +         goto next;
> +      }
> +
> +allow_fallback:
> +      if (fallback_fd == -1)
> +         fallback_fd = fd;
> +next:
> +      if (fallback_fd != fd)
> +         close(fd);
> +      fd = -1;
> +      continue;
> +   }
> +
> +success:
> +   closedir(sysdir);
> +
> +   if (fallback_fd < 0 && fd < 0) {
> +      _eglLog(_EGL_WARNING, "Failed to open any DRM device");
> +      return -1;
> +   }
> +
> +   if (fd < 0) {
> +      _eglLog(_EGL_WARNING, "Failed to open desired DRM device, using fallback");
> +      return fallback_fd;
> +   }
> +
> +   close(fallback_fd);
> +   return fd;
> +}
> +
>  EGLBoolean
>  dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
>  {
> @@ -1242,42 +1383,17 @@ dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *disp)
>
>     disp->DriverData = (void *) dri2_dpy;
>
> -   dri2_dpy->fd = droid_open_device(dri2_dpy);
> +   dri2_dpy->fd = droid_open_device(disp);
>     if (dri2_dpy->fd < 0) {
>        err = "DRI2: failed to open device";
>        goto cleanup;
>     }
>
> -   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
> -   if (dri2_dpy->driver_name == NULL) {
> -      err = "DRI2: failed to get driver name";
> +   if (!droid_load_driver(disp)) {
> +      err = "DRI2: failed to load driver";
>        goto cleanup;
>     }
>
> -   dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
> -
> -   if (!dri2_dpy->is_render_node) {
> -   #ifdef HAVE_DRM_GRALLOC
> -       /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names
> -        * for backwards compatibility with drm_gralloc. (Do not use on new
> -        * systems.) */
> -       dri2_dpy->loader_extensions = droid_dri2_loader_extensions;
> -       if (!dri2_load_driver(disp)) {
> -          err = "DRI2: failed to load driver";
> -          goto cleanup;
> -       }
> -   #else
> -       err = "DRI2: handle is not for a render node";
> -       goto cleanup;
> -   #endif
> -   } else {
> -       dri2_dpy->loader_extensions = droid_image_loader_extensions;
> -       if (!dri2_load_driver_dri3(disp)) {
> -          err = "DRI3: failed to load driver";
> -          goto cleanup;
> -       }
> -   }
> -
>     if (!dri2_create_screen(disp)) {
>        err = "DRI2: failed to create screen";
>        goto cleanup;
> --
> 2.17.1
>


More information about the mesa-dev mailing list