LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_lease.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 286 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 15 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright © 2017 Keith Packard <keithp@keithp.com>
       4             :  */
       5             : #include <linux/file.h>
       6             : #include <linux/uaccess.h>
       7             : 
       8             : #include <drm/drm_auth.h>
       9             : #include <drm/drm_crtc.h>
      10             : #include <drm/drm_drv.h>
      11             : #include <drm/drm_file.h>
      12             : #include <drm/drm_lease.h>
      13             : #include <drm/drm_print.h>
      14             : 
      15             : #include "drm_crtc_internal.h"
      16             : #include "drm_internal.h"
      17             : 
      18             : /**
      19             :  * DOC: drm leasing
      20             :  *
      21             :  * DRM leases provide information about whether a DRM master may control a DRM
      22             :  * mode setting object. This enables the creation of multiple DRM masters that
      23             :  * manage subsets of display resources.
      24             :  *
      25             :  * The original DRM master of a device 'owns' the available drm resources. It
      26             :  * may create additional DRM masters and 'lease' resources which it controls
      27             :  * to the new DRM master. This gives the new DRM master control over the
      28             :  * leased resources until the owner revokes the lease, or the new DRM master
      29             :  * is closed. Some helpful terminology:
      30             :  *
      31             :  * - An 'owner' is a &struct drm_master that is not leasing objects from
      32             :  *   another &struct drm_master, and hence 'owns' the objects. The owner can be
      33             :  *   identified as the &struct drm_master for which &drm_master.lessor is NULL.
      34             :  *
      35             :  * - A 'lessor' is a &struct drm_master which is leasing objects to one or more
      36             :  *   other &struct drm_master. Currently, lessees are not allowed to
      37             :  *   create sub-leases, hence the lessor is the same as the owner.
      38             :  *
      39             :  * - A 'lessee' is a &struct drm_master which is leasing objects from some
      40             :  *   other &struct drm_master. Each lessee only leases resources from a single
      41             :  *   lessor recorded in &drm_master.lessor, and holds the set of objects that
      42             :  *   it is leasing in &drm_master.leases.
      43             :  *
      44             :  * - A 'lease' is a contract between the lessor and lessee that identifies
      45             :  *   which resources may be controlled by the lessee. All of the resources
      46             :  *   that are leased must be owned by or leased to the lessor, and lessors are
      47             :  *   not permitted to lease the same object to multiple lessees.
      48             :  *
      49             :  * The set of objects any &struct drm_master 'controls' is limited to the set
      50             :  * of objects it leases (for lessees) or all objects (for owners).
      51             :  *
      52             :  * Objects not controlled by a &struct drm_master cannot be modified through
      53             :  * the various state manipulating ioctls, and any state reported back to user
      54             :  * space will be edited to make them appear idle and/or unusable. For
      55             :  * instance, connectors always report 'disconnected', while encoders
      56             :  * report no possible crtcs or clones.
      57             :  *
      58             :  * Since each lessee may lease objects from a single lessor, display resource
      59             :  * leases form a tree of &struct drm_master. As lessees are currently not
      60             :  * allowed to create sub-leases, the tree depth is limited to 1. All of
      61             :  * these get activated simultaneously when the top level device owner changes
      62             :  * through the SETMASTER or DROPMASTER IOCTL, so &drm_device.master points to
      63             :  * the owner at the top of the lease tree (i.e. the &struct drm_master for which
      64             :  * &drm_master.lessor is NULL). The full list of lessees that are leasing
      65             :  * objects from the owner can be searched via the owner's
      66             :  * &drm_master.lessee_idr.
      67             :  */
      68             : 
      69             : #define drm_for_each_lessee(lessee, lessor) \
      70             :         list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)
      71             : 
      72             : static uint64_t drm_lease_idr_object;
      73             : 
      74           0 : struct drm_master *drm_lease_owner(struct drm_master *master)
      75             : {
      76           0 :         while (master->lessor != NULL)
      77             :                 master = master->lessor;
      78           0 :         return master;
      79             : }
      80             : 
      81             : static struct drm_master*
      82             : _drm_find_lessee(struct drm_master *master, int lessee_id)
      83             : {
      84             :         lockdep_assert_held(&master->dev->mode_config.idr_mutex);
      85           0 :         return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id);
      86             : }
      87             : 
      88             : static int _drm_lease_held_master(struct drm_master *master, int id)
      89             : {
      90             :         lockdep_assert_held(&master->dev->mode_config.idr_mutex);
      91           0 :         if (master->lessor)
      92           0 :                 return idr_find(&master->leases, id) != NULL;
      93             :         return true;
      94             : }
      95             : 
      96             : /* Checks if the given object has been leased to some lessee of drm_master */
      97           0 : static bool _drm_has_leased(struct drm_master *master, int id)
      98             : {
      99             :         struct drm_master *lessee;
     100             : 
     101             :         lockdep_assert_held(&master->dev->mode_config.idr_mutex);
     102           0 :         drm_for_each_lessee(lessee, master)
     103           0 :                 if (_drm_lease_held_master(lessee, id))
     104             :                         return true;
     105             :         return false;
     106             : }
     107             : 
     108             : /* Called with idr_mutex held */
     109           0 : bool _drm_lease_held(struct drm_file *file_priv, int id)
     110             : {
     111             :         bool ret;
     112             :         struct drm_master *master;
     113             : 
     114           0 :         if (!file_priv)
     115             :                 return true;
     116             : 
     117           0 :         master = drm_file_get_master(file_priv);
     118           0 :         if (!master)
     119             :                 return true;
     120           0 :         ret = _drm_lease_held_master(master, id);
     121           0 :         drm_master_put(&master);
     122             : 
     123           0 :         return ret;
     124             : }
     125             : 
     126           0 : bool drm_lease_held(struct drm_file *file_priv, int id)
     127             : {
     128             :         struct drm_master *master;
     129             :         bool ret;
     130             : 
     131           0 :         if (!file_priv)
     132             :                 return true;
     133             : 
     134           0 :         master = drm_file_get_master(file_priv);
     135           0 :         if (!master)
     136             :                 return true;
     137           0 :         if (!master->lessor) {
     138             :                 ret = true;
     139             :                 goto out;
     140             :         }
     141           0 :         mutex_lock(&master->dev->mode_config.idr_mutex);
     142           0 :         ret = _drm_lease_held_master(master, id);
     143           0 :         mutex_unlock(&master->dev->mode_config.idr_mutex);
     144             : 
     145             : out:
     146           0 :         drm_master_put(&master);
     147           0 :         return ret;
     148             : }
     149             : 
     150             : /*
     151             :  * Given a bitmask of crtcs to check, reconstructs a crtc mask based on the
     152             :  * crtcs which are visible through the specified file.
     153             :  */
     154           0 : uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
     155             : {
     156             :         struct drm_master *master;
     157             :         struct drm_device *dev;
     158             :         struct drm_crtc *crtc;
     159             :         int count_in, count_out;
     160           0 :         uint32_t crtcs_out = 0;
     161             : 
     162           0 :         if (!file_priv)
     163             :                 return crtcs_in;
     164             : 
     165           0 :         master = drm_file_get_master(file_priv);
     166           0 :         if (!master)
     167             :                 return crtcs_in;
     168           0 :         if (!master->lessor) {
     169             :                 crtcs_out = crtcs_in;
     170             :                 goto out;
     171             :         }
     172           0 :         dev = master->dev;
     173             : 
     174           0 :         count_in = count_out = 0;
     175           0 :         mutex_lock(&master->dev->mode_config.idr_mutex);
     176           0 :         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
     177           0 :                 if (_drm_lease_held_master(master, crtc->base.id)) {
     178           0 :                         uint32_t mask_in = 1ul << count_in;
     179             : 
     180           0 :                         if ((crtcs_in & mask_in) != 0) {
     181           0 :                                 uint32_t mask_out = 1ul << count_out;
     182             : 
     183           0 :                                 crtcs_out |= mask_out;
     184             :                         }
     185           0 :                         count_out++;
     186             :                 }
     187           0 :                 count_in++;
     188             :         }
     189           0 :         mutex_unlock(&master->dev->mode_config.idr_mutex);
     190             : 
     191             : out:
     192           0 :         drm_master_put(&master);
     193           0 :         return crtcs_out;
     194             : }
     195             : 
     196             : /*
     197             :  * Uses drm_master_create to allocate a new drm_master, then checks to
     198             :  * make sure all of the desired objects can be leased, atomically
     199             :  * leasing them to the new drmmaster.
     200             :  *
     201             :  *      ERR_PTR(-EACCES)        some other master holds the title to any object
     202             :  *      ERR_PTR(-ENOENT)        some object is not a valid DRM object for this device
     203             :  *      ERR_PTR(-EBUSY)         some other lessee holds title to this object
     204             :  *      ERR_PTR(-EEXIST)        same object specified more than once in the provided list
     205             :  *      ERR_PTR(-ENOMEM)        allocation failed
     206             :  */
     207           0 : static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr *leases)
     208             : {
     209           0 :         struct drm_device *dev = lessor->dev;
     210             :         int error;
     211             :         struct drm_master *lessee;
     212             :         int object;
     213             :         int id;
     214             :         void *entry;
     215             : 
     216           0 :         drm_dbg_lease(dev, "lessor %d\n", lessor->lessee_id);
     217             : 
     218           0 :         lessee = drm_master_create(lessor->dev);
     219           0 :         if (!lessee) {
     220           0 :                 drm_dbg_lease(dev, "drm_master_create failed\n");
     221           0 :                 return ERR_PTR(-ENOMEM);
     222             :         }
     223             : 
     224           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     225             : 
     226           0 :         idr_for_each_entry(leases, entry, object) {
     227           0 :                 error = 0;
     228           0 :                 if (!idr_find(&dev->mode_config.object_idr, object))
     229             :                         error = -ENOENT;
     230           0 :                 else if (_drm_has_leased(lessor, object))
     231           0 :                         error = -EBUSY;
     232             : 
     233           0 :                 if (error != 0) {
     234           0 :                         drm_dbg_lease(dev, "object %d failed %d\n", object, error);
     235           0 :                         goto out_lessee;
     236             :                 }
     237             :         }
     238             : 
     239             :         /* Insert the new lessee into the tree */
     240           0 :         id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
     241           0 :         if (id < 0) {
     242             :                 error = id;
     243             :                 goto out_lessee;
     244             :         }
     245             : 
     246           0 :         lessee->lessee_id = id;
     247           0 :         lessee->lessor = drm_master_get(lessor);
     248           0 :         list_add_tail(&lessee->lessee_list, &lessor->lessees);
     249             : 
     250             :         /* Move the leases over */
     251           0 :         lessee->leases = *leases;
     252           0 :         drm_dbg_lease(dev, "new lessee %d %p, lessor %d %p\n",
     253             :                       lessee->lessee_id, lessee, lessor->lessee_id, lessor);
     254             : 
     255           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     256           0 :         return lessee;
     257             : 
     258             : out_lessee:
     259           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     260             : 
     261           0 :         drm_master_put(&lessee);
     262             : 
     263           0 :         return ERR_PTR(error);
     264             : }
     265             : 
     266           0 : void drm_lease_destroy(struct drm_master *master)
     267             : {
     268           0 :         struct drm_device *dev = master->dev;
     269             : 
     270           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     271             : 
     272           0 :         drm_dbg_lease(dev, "drm_lease_destroy %d\n", master->lessee_id);
     273             : 
     274             :         /* This master is referenced by all lessees, hence it cannot be destroyed
     275             :          * until all of them have been
     276             :          */
     277           0 :         WARN_ON(!list_empty(&master->lessees));
     278             : 
     279             :         /* Remove this master from the lessee idr in the owner */
     280           0 :         if (master->lessee_id != 0) {
     281           0 :                 drm_dbg_lease(dev, "remove master %d from device list of lessees\n",
     282             :                               master->lessee_id);
     283           0 :                 idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
     284             :         }
     285             : 
     286             :         /* Remove this master from any lessee list it may be on */
     287           0 :         list_del(&master->lessee_list);
     288             : 
     289           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     290             : 
     291           0 :         if (master->lessor) {
     292             :                 /* Tell the master to check the lessee list */
     293           0 :                 drm_sysfs_lease_event(dev);
     294           0 :                 drm_master_put(&master->lessor);
     295             :         }
     296             : 
     297           0 :         drm_dbg_lease(dev, "drm_lease_destroy done %d\n", master->lessee_id);
     298           0 : }
     299             : 
     300           0 : static void _drm_lease_revoke(struct drm_master *top)
     301             : {
     302             :         int object;
     303             :         void *entry;
     304           0 :         struct drm_master *master = top;
     305             : 
     306             :         lockdep_assert_held(&top->dev->mode_config.idr_mutex);
     307             : 
     308             :         /*
     309             :          * Walk the tree starting at 'top' emptying all leases. Because
     310             :          * the tree is fully connected, we can do this without recursing
     311             :          */
     312             :         for (;;) {
     313           0 :                 drm_dbg_lease(master->dev, "revoke leases for %p %d\n",
     314             :                               master, master->lessee_id);
     315             : 
     316             :                 /* Evacuate the lease */
     317           0 :                 idr_for_each_entry(&master->leases, entry, object)
     318           0 :                         idr_remove(&master->leases, object);
     319             : 
     320             :                 /* Depth-first list walk */
     321             : 
     322             :                 /* Down */
     323           0 :                 if (!list_empty(&master->lessees)) {
     324           0 :                         master = list_first_entry(&master->lessees, struct drm_master, lessee_list);
     325             :                 } else {
     326             :                         /* Up */
     327           0 :                         while (master != top && master == list_last_entry(&master->lessor->lessees, struct drm_master, lessee_list))
     328             :                                 master = master->lessor;
     329             : 
     330           0 :                         if (master == top)
     331             :                                 break;
     332             : 
     333             :                         /* Over */
     334           0 :                         master = list_next_entry(master, lessee_list);
     335             :                 }
     336             :         }
     337           0 : }
     338             : 
     339           0 : void drm_lease_revoke(struct drm_master *top)
     340             : {
     341           0 :         mutex_lock(&top->dev->mode_config.idr_mutex);
     342           0 :         _drm_lease_revoke(top);
     343           0 :         mutex_unlock(&top->dev->mode_config.idr_mutex);
     344           0 : }
     345             : 
     346           0 : static int validate_lease(struct drm_device *dev,
     347             :                           int object_count,
     348             :                           struct drm_mode_object **objects,
     349             :                           bool universal_planes)
     350             : {
     351             :         int o;
     352           0 :         int has_crtc = -1;
     353           0 :         int has_connector = -1;
     354           0 :         int has_plane = -1;
     355             : 
     356             :         /* we want to confirm that there is at least one crtc, plane
     357             :            connector object. */
     358             : 
     359           0 :         for (o = 0; o < object_count; o++) {
     360           0 :                 if (objects[o]->type == DRM_MODE_OBJECT_CRTC && has_crtc == -1) {
     361           0 :                         has_crtc = o;
     362             :                 }
     363           0 :                 if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
     364           0 :                         has_connector = o;
     365             : 
     366           0 :                 if (universal_planes) {
     367           0 :                         if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
     368           0 :                                 has_plane = o;
     369             :                 }
     370             :         }
     371           0 :         if (has_crtc == -1 || has_connector == -1)
     372             :                 return -EINVAL;
     373           0 :         if (universal_planes && has_plane == -1)
     374             :                 return -EINVAL;
     375           0 :         return 0;
     376             : }
     377             : 
     378           0 : static int fill_object_idr(struct drm_device *dev,
     379             :                            struct drm_file *lessor_priv,
     380             :                            struct idr *leases,
     381             :                            int object_count,
     382             :                            u32 *object_ids)
     383             : {
     384             :         struct drm_mode_object **objects;
     385             :         u32 o;
     386             :         int ret;
     387           0 :         bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
     388             : 
     389           0 :         objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
     390             :                           GFP_KERNEL);
     391           0 :         if (!objects)
     392             :                 return -ENOMEM;
     393             : 
     394             :         /* step one - get references to all the mode objects
     395             :            and check for validity. */
     396           0 :         for (o = 0; o < object_count; o++) {
     397           0 :                 objects[o] = drm_mode_object_find(dev, lessor_priv,
     398           0 :                                                   object_ids[o],
     399             :                                                   DRM_MODE_OBJECT_ANY);
     400           0 :                 if (!objects[o]) {
     401             :                         ret = -ENOENT;
     402             :                         goto out_free_objects;
     403             :                 }
     404             : 
     405           0 :                 if (!drm_mode_object_lease_required(objects[o]->type)) {
     406           0 :                         DRM_DEBUG_KMS("invalid object for lease\n");
     407           0 :                         ret = -EINVAL;
     408           0 :                         goto out_free_objects;
     409             :                 }
     410             :         }
     411             : 
     412           0 :         ret = validate_lease(dev, object_count, objects, universal_planes);
     413           0 :         if (ret) {
     414           0 :                 drm_dbg_lease(dev, "lease validation failed\n");
     415           0 :                 goto out_free_objects;
     416             :         }
     417             : 
     418             :         /* add their IDs to the lease request - taking into account
     419             :            universal planes */
     420           0 :         for (o = 0; o < object_count; o++) {
     421           0 :                 struct drm_mode_object *obj = objects[o];
     422           0 :                 u32 object_id = objects[o]->id;
     423             : 
     424           0 :                 drm_dbg_lease(dev, "Adding object %d to lease\n", object_id);
     425             : 
     426             :                 /*
     427             :                  * We're using an IDR to hold the set of leased
     428             :                  * objects, but we don't need to point at the object's
     429             :                  * data structure from the lease as the main object_idr
     430             :                  * will be used to actually find that. Instead, all we
     431             :                  * really want is a 'leased/not-leased' result, for
     432             :                  * which any non-NULL pointer will work fine.
     433             :                  */
     434           0 :                 ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
     435           0 :                 if (ret < 0) {
     436           0 :                         drm_dbg_lease(dev, "Object %d cannot be inserted into leases (%d)\n",
     437             :                                       object_id, ret);
     438           0 :                         goto out_free_objects;
     439             :                 }
     440           0 :                 if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
     441           0 :                         struct drm_crtc *crtc = obj_to_crtc(obj);
     442             : 
     443           0 :                         ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
     444           0 :                         if (ret < 0) {
     445           0 :                                 drm_dbg_lease(dev, "Object primary plane %d cannot be inserted into leases (%d)\n",
     446             :                                               object_id, ret);
     447           0 :                                 goto out_free_objects;
     448             :                         }
     449           0 :                         if (crtc->cursor) {
     450           0 :                                 ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
     451           0 :                                 if (ret < 0) {
     452           0 :                                         drm_dbg_lease(dev, "Object cursor plane %d cannot be inserted into leases (%d)\n",
     453             :                                                       object_id, ret);
     454           0 :                                         goto out_free_objects;
     455             :                                 }
     456             :                         }
     457             :                 }
     458             :         }
     459             : 
     460             :         ret = 0;
     461             : out_free_objects:
     462           0 :         for (o = 0; o < object_count; o++) {
     463           0 :                 if (objects[o])
     464           0 :                         drm_mode_object_put(objects[o]);
     465             :         }
     466           0 :         kfree(objects);
     467           0 :         return ret;
     468             : }
     469             : 
     470             : /*
     471             :  * The master associated with the specified file will have a lease
     472             :  * created containing the objects specified in the ioctl structure.
     473             :  * A file descriptor will be allocated for that and returned to the
     474             :  * application.
     475             :  */
     476           0 : int drm_mode_create_lease_ioctl(struct drm_device *dev,
     477             :                                 void *data, struct drm_file *lessor_priv)
     478             : {
     479           0 :         struct drm_mode_create_lease *cl = data;
     480             :         size_t object_count;
     481           0 :         int ret = 0;
     482             :         struct idr leases;
     483             :         struct drm_master *lessor;
     484           0 :         struct drm_master *lessee = NULL;
     485           0 :         struct file *lessee_file = NULL;
     486           0 :         struct file *lessor_file = lessor_priv->filp;
     487             :         struct drm_file *lessee_priv;
     488           0 :         int fd = -1;
     489             :         uint32_t *object_ids;
     490             : 
     491             :         /* Can't lease without MODESET */
     492           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     493             :                 return -EOPNOTSUPP;
     494             : 
     495           0 :         if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
     496           0 :                 drm_dbg_lease(dev, "invalid flags\n");
     497           0 :                 return -EINVAL;
     498             :         }
     499             : 
     500           0 :         lessor = drm_file_get_master(lessor_priv);
     501             :         /* Do not allow sub-leases */
     502           0 :         if (lessor->lessor) {
     503           0 :                 drm_dbg_lease(dev, "recursive leasing not allowed\n");
     504           0 :                 ret = -EINVAL;
     505           0 :                 goto out_lessor;
     506             :         }
     507             : 
     508           0 :         object_count = cl->object_count;
     509             : 
     510             :         /* Handle leased objects, if any */
     511           0 :         idr_init(&leases);
     512           0 :         if (object_count != 0) {
     513           0 :                 object_ids = memdup_user(u64_to_user_ptr(cl->object_ids),
     514             :                                          array_size(object_count, sizeof(__u32)));
     515           0 :                 if (IS_ERR(object_ids)) {
     516           0 :                         ret = PTR_ERR(object_ids);
     517           0 :                         idr_destroy(&leases);
     518           0 :                         goto out_lessor;
     519             :                 }
     520             : 
     521             :                 /* fill and validate the object idr */
     522           0 :                 ret = fill_object_idr(dev, lessor_priv, &leases,
     523             :                                       object_count, object_ids);
     524           0 :                 kfree(object_ids);
     525           0 :                 if (ret) {
     526           0 :                         drm_dbg_lease(dev, "lease object lookup failed: %i\n", ret);
     527           0 :                         idr_destroy(&leases);
     528           0 :                         goto out_lessor;
     529             :                 }
     530             :         }
     531             : 
     532             :         /* Allocate a file descriptor for the lease */
     533           0 :         fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
     534           0 :         if (fd < 0) {
     535           0 :                 idr_destroy(&leases);
     536           0 :                 ret = fd;
     537           0 :                 goto out_lessor;
     538             :         }
     539             : 
     540           0 :         drm_dbg_lease(dev, "Creating lease\n");
     541             :         /* lessee will take the ownership of leases */
     542           0 :         lessee = drm_lease_create(lessor, &leases);
     543             : 
     544           0 :         if (IS_ERR(lessee)) {
     545           0 :                 ret = PTR_ERR(lessee);
     546           0 :                 idr_destroy(&leases);
     547           0 :                 goto out_leases;
     548             :         }
     549             : 
     550             :         /* Clone the lessor file to create a new file for us */
     551           0 :         drm_dbg_lease(dev, "Allocating lease file\n");
     552           0 :         lessee_file = file_clone_open(lessor_file);
     553           0 :         if (IS_ERR(lessee_file)) {
     554           0 :                 ret = PTR_ERR(lessee_file);
     555             :                 goto out_lessee;
     556             :         }
     557             : 
     558           0 :         lessee_priv = lessee_file->private_data;
     559             :         /* Change the file to a master one */
     560           0 :         drm_master_put(&lessee_priv->master);
     561           0 :         lessee_priv->master = lessee;
     562           0 :         lessee_priv->is_master = 1;
     563           0 :         lessee_priv->authenticated = 1;
     564             : 
     565             :         /* Pass fd back to userspace */
     566           0 :         drm_dbg_lease(dev, "Returning fd %d id %d\n", fd, lessee->lessee_id);
     567           0 :         cl->fd = fd;
     568           0 :         cl->lessee_id = lessee->lessee_id;
     569             : 
     570             :         /* Hook up the fd */
     571           0 :         fd_install(fd, lessee_file);
     572             : 
     573           0 :         drm_master_put(&lessor);
     574           0 :         drm_dbg_lease(dev, "drm_mode_create_lease_ioctl succeeded\n");
     575           0 :         return 0;
     576             : 
     577             : out_lessee:
     578           0 :         drm_master_put(&lessee);
     579             : 
     580             : out_leases:
     581           0 :         put_unused_fd(fd);
     582             : 
     583             : out_lessor:
     584           0 :         drm_master_put(&lessor);
     585           0 :         drm_dbg_lease(dev, "drm_mode_create_lease_ioctl failed: %d\n", ret);
     586           0 :         return ret;
     587             : }
     588             : 
     589           0 : int drm_mode_list_lessees_ioctl(struct drm_device *dev,
     590             :                                void *data, struct drm_file *lessor_priv)
     591             : {
     592           0 :         struct drm_mode_list_lessees *arg = data;
     593           0 :         __u32 __user *lessee_ids = (__u32 __user *) (uintptr_t) (arg->lessees_ptr);
     594           0 :         __u32 count_lessees = arg->count_lessees;
     595             :         struct drm_master *lessor, *lessee;
     596             :         int count;
     597           0 :         int ret = 0;
     598             : 
     599           0 :         if (arg->pad)
     600             :                 return -EINVAL;
     601             : 
     602             :         /* Can't lease without MODESET */
     603           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     604             :                 return -EOPNOTSUPP;
     605             : 
     606           0 :         lessor = drm_file_get_master(lessor_priv);
     607           0 :         drm_dbg_lease(dev, "List lessees for %d\n", lessor->lessee_id);
     608             : 
     609           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     610             : 
     611           0 :         count = 0;
     612           0 :         drm_for_each_lessee(lessee, lessor) {
     613             :                 /* Only list un-revoked leases */
     614           0 :                 if (!idr_is_empty(&lessee->leases)) {
     615           0 :                         if (count_lessees > count) {
     616           0 :                                 drm_dbg_lease(dev, "Add lessee %d\n",
     617             :                                               lessee->lessee_id);
     618           0 :                                 ret = put_user(lessee->lessee_id, lessee_ids + count);
     619           0 :                                 if (ret)
     620             :                                         break;
     621             :                         }
     622           0 :                         count++;
     623             :                 }
     624             :         }
     625             : 
     626           0 :         drm_dbg_lease(dev, "Lessor leases to %d\n", count);
     627           0 :         if (ret == 0)
     628           0 :                 arg->count_lessees = count;
     629             : 
     630           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     631           0 :         drm_master_put(&lessor);
     632             : 
     633           0 :         return ret;
     634             : }
     635             : 
     636             : /* Return the list of leased objects for the specified lessee */
     637           0 : int drm_mode_get_lease_ioctl(struct drm_device *dev,
     638             :                              void *data, struct drm_file *lessee_priv)
     639             : {
     640           0 :         struct drm_mode_get_lease *arg = data;
     641           0 :         __u32 __user *object_ids = (__u32 __user *) (uintptr_t) (arg->objects_ptr);
     642           0 :         __u32 count_objects = arg->count_objects;
     643             :         struct drm_master *lessee;
     644             :         struct idr *object_idr;
     645             :         int count;
     646             :         void *entry;
     647             :         int object;
     648           0 :         int ret = 0;
     649             : 
     650           0 :         if (arg->pad)
     651             :                 return -EINVAL;
     652             : 
     653             :         /* Can't lease without MODESET */
     654           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     655             :                 return -EOPNOTSUPP;
     656             : 
     657           0 :         lessee = drm_file_get_master(lessee_priv);
     658           0 :         drm_dbg_lease(dev, "get lease for %d\n", lessee->lessee_id);
     659             : 
     660           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     661             : 
     662           0 :         if (lessee->lessor == NULL)
     663             :                 /* owner can use all objects */
     664           0 :                 object_idr = &lessee->dev->mode_config.object_idr;
     665             :         else
     666             :                 /* lessee can only use allowed object */
     667           0 :                 object_idr = &lessee->leases;
     668             : 
     669           0 :         count = 0;
     670           0 :         idr_for_each_entry(object_idr, entry, object) {
     671           0 :                 if (count_objects > count) {
     672           0 :                         drm_dbg_lease(dev, "adding object %d\n", object);
     673           0 :                         ret = put_user(object, object_ids + count);
     674           0 :                         if (ret)
     675             :                                 break;
     676             :                 }
     677           0 :                 count++;
     678             :         }
     679             : 
     680           0 :         DRM_DEBUG("lease holds %d objects\n", count);
     681           0 :         if (ret == 0)
     682           0 :                 arg->count_objects = count;
     683             : 
     684           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     685           0 :         drm_master_put(&lessee);
     686             : 
     687           0 :         return ret;
     688             : }
     689             : 
     690             : /*
     691             :  * This removes all of the objects from the lease without
     692             :  * actually getting rid of the lease itself; that way all
     693             :  * references to it still work correctly
     694             :  */
     695           0 : int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
     696             :                                 void *data, struct drm_file *lessor_priv)
     697             : {
     698           0 :         struct drm_mode_revoke_lease *arg = data;
     699             :         struct drm_master *lessor;
     700             :         struct drm_master *lessee;
     701           0 :         int ret = 0;
     702             : 
     703           0 :         drm_dbg_lease(dev, "revoke lease for %d\n", arg->lessee_id);
     704             : 
     705             :         /* Can't lease without MODESET */
     706           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     707             :                 return -EOPNOTSUPP;
     708             : 
     709           0 :         lessor = drm_file_get_master(lessor_priv);
     710           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     711             : 
     712           0 :         lessee = _drm_find_lessee(lessor, arg->lessee_id);
     713             : 
     714             :         /* No such lessee */
     715           0 :         if (!lessee) {
     716             :                 ret = -ENOENT;
     717             :                 goto fail;
     718             :         }
     719             : 
     720             :         /* Lease is not held by lessor */
     721           0 :         if (lessee->lessor != lessor) {
     722             :                 ret = -EACCES;
     723             :                 goto fail;
     724             :         }
     725             : 
     726           0 :         _drm_lease_revoke(lessee);
     727             : 
     728             : fail:
     729           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     730           0 :         drm_master_put(&lessor);
     731             : 
     732           0 :         return ret;
     733             : }

Generated by: LCOV version 1.14