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: 2022-12-09 01:23:36 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_helper.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_DEBUG_LEASE("lessor %d\n", lessor->lessee_id);
     217             : 
     218           0 :         lessee = drm_master_create(lessor->dev);
     219           0 :         if (!lessee) {
     220           0 :                 DRM_DEBUG_LEASE("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_DEBUG_LEASE("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_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor);
     253             : 
     254           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     255           0 :         return lessee;
     256             : 
     257             : out_lessee:
     258           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     259             : 
     260           0 :         drm_master_put(&lessee);
     261             : 
     262           0 :         return ERR_PTR(error);
     263             : }
     264             : 
     265           0 : void drm_lease_destroy(struct drm_master *master)
     266             : {
     267           0 :         struct drm_device *dev = master->dev;
     268             : 
     269           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     270             : 
     271           0 :         DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master->lessee_id);
     272             : 
     273             :         /* This master is referenced by all lessees, hence it cannot be destroyed
     274             :          * until all of them have been
     275             :          */
     276           0 :         WARN_ON(!list_empty(&master->lessees));
     277             : 
     278             :         /* Remove this master from the lessee idr in the owner */
     279           0 :         if (master->lessee_id != 0) {
     280           0 :                 DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master->lessee_id);
     281           0 :                 idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
     282             :         }
     283             : 
     284             :         /* Remove this master from any lessee list it may be on */
     285           0 :         list_del(&master->lessee_list);
     286             : 
     287           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     288             : 
     289           0 :         if (master->lessor) {
     290             :                 /* Tell the master to check the lessee list */
     291           0 :                 drm_sysfs_lease_event(dev);
     292           0 :                 drm_master_put(&master->lessor);
     293             :         }
     294             : 
     295           0 :         DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id);
     296           0 : }
     297             : 
     298           0 : static void _drm_lease_revoke(struct drm_master *top)
     299             : {
     300             :         int object;
     301             :         void *entry;
     302           0 :         struct drm_master *master = top;
     303             : 
     304             :         lockdep_assert_held(&top->dev->mode_config.idr_mutex);
     305             : 
     306             :         /*
     307             :          * Walk the tree starting at 'top' emptying all leases. Because
     308             :          * the tree is fully connected, we can do this without recursing
     309             :          */
     310             :         for (;;) {
     311           0 :                 DRM_DEBUG_LEASE("revoke leases for %p %d\n", master, master->lessee_id);
     312             : 
     313             :                 /* Evacuate the lease */
     314           0 :                 idr_for_each_entry(&master->leases, entry, object)
     315           0 :                         idr_remove(&master->leases, object);
     316             : 
     317             :                 /* Depth-first list walk */
     318             : 
     319             :                 /* Down */
     320           0 :                 if (!list_empty(&master->lessees)) {
     321           0 :                         master = list_first_entry(&master->lessees, struct drm_master, lessee_list);
     322             :                 } else {
     323             :                         /* Up */
     324           0 :                         while (master != top && master == list_last_entry(&master->lessor->lessees, struct drm_master, lessee_list))
     325             :                                 master = master->lessor;
     326             : 
     327           0 :                         if (master == top)
     328             :                                 break;
     329             : 
     330             :                         /* Over */
     331           0 :                         master = list_next_entry(master, lessee_list);
     332             :                 }
     333             :         }
     334           0 : }
     335             : 
     336           0 : void drm_lease_revoke(struct drm_master *top)
     337             : {
     338           0 :         mutex_lock(&top->dev->mode_config.idr_mutex);
     339           0 :         _drm_lease_revoke(top);
     340           0 :         mutex_unlock(&top->dev->mode_config.idr_mutex);
     341           0 : }
     342             : 
     343           0 : static int validate_lease(struct drm_device *dev,
     344             :                           int object_count,
     345             :                           struct drm_mode_object **objects,
     346             :                           bool universal_planes)
     347             : {
     348             :         int o;
     349           0 :         int has_crtc = -1;
     350           0 :         int has_connector = -1;
     351           0 :         int has_plane = -1;
     352             : 
     353             :         /* we want to confirm that there is at least one crtc, plane
     354             :            connector object. */
     355             : 
     356           0 :         for (o = 0; o < object_count; o++) {
     357           0 :                 if (objects[o]->type == DRM_MODE_OBJECT_CRTC && has_crtc == -1) {
     358           0 :                         has_crtc = o;
     359             :                 }
     360           0 :                 if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
     361           0 :                         has_connector = o;
     362             : 
     363           0 :                 if (universal_planes) {
     364           0 :                         if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
     365           0 :                                 has_plane = o;
     366             :                 }
     367             :         }
     368           0 :         if (has_crtc == -1 || has_connector == -1)
     369             :                 return -EINVAL;
     370           0 :         if (universal_planes && has_plane == -1)
     371             :                 return -EINVAL;
     372           0 :         return 0;
     373             : }
     374             : 
     375           0 : static int fill_object_idr(struct drm_device *dev,
     376             :                            struct drm_file *lessor_priv,
     377             :                            struct idr *leases,
     378             :                            int object_count,
     379             :                            u32 *object_ids)
     380             : {
     381             :         struct drm_mode_object **objects;
     382             :         u32 o;
     383             :         int ret;
     384           0 :         bool universal_planes = READ_ONCE(lessor_priv->universal_planes);
     385             : 
     386           0 :         objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
     387             :                           GFP_KERNEL);
     388           0 :         if (!objects)
     389             :                 return -ENOMEM;
     390             : 
     391             :         /* step one - get references to all the mode objects
     392             :            and check for validity. */
     393           0 :         for (o = 0; o < object_count; o++) {
     394           0 :                 objects[o] = drm_mode_object_find(dev, lessor_priv,
     395           0 :                                                   object_ids[o],
     396             :                                                   DRM_MODE_OBJECT_ANY);
     397           0 :                 if (!objects[o]) {
     398             :                         ret = -ENOENT;
     399             :                         goto out_free_objects;
     400             :                 }
     401             : 
     402           0 :                 if (!drm_mode_object_lease_required(objects[o]->type)) {
     403           0 :                         DRM_DEBUG_KMS("invalid object for lease\n");
     404           0 :                         ret = -EINVAL;
     405           0 :                         goto out_free_objects;
     406             :                 }
     407             :         }
     408             : 
     409           0 :         ret = validate_lease(dev, object_count, objects, universal_planes);
     410           0 :         if (ret) {
     411           0 :                 DRM_DEBUG_LEASE("lease validation failed\n");
     412           0 :                 goto out_free_objects;
     413             :         }
     414             : 
     415             :         /* add their IDs to the lease request - taking into account
     416             :            universal planes */
     417           0 :         for (o = 0; o < object_count; o++) {
     418           0 :                 struct drm_mode_object *obj = objects[o];
     419           0 :                 u32 object_id = objects[o]->id;
     420             : 
     421           0 :                 DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id);
     422             : 
     423             :                 /*
     424             :                  * We're using an IDR to hold the set of leased
     425             :                  * objects, but we don't need to point at the object's
     426             :                  * data structure from the lease as the main object_idr
     427             :                  * will be used to actually find that. Instead, all we
     428             :                  * really want is a 'leased/not-leased' result, for
     429             :                  * which any non-NULL pointer will work fine.
     430             :                  */
     431           0 :                 ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
     432           0 :                 if (ret < 0) {
     433           0 :                         DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
     434             :                                         object_id, ret);
     435           0 :                         goto out_free_objects;
     436             :                 }
     437           0 :                 if (obj->type == DRM_MODE_OBJECT_CRTC && !universal_planes) {
     438           0 :                         struct drm_crtc *crtc = obj_to_crtc(obj);
     439             : 
     440           0 :                         ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
     441           0 :                         if (ret < 0) {
     442           0 :                                 DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
     443             :                                                 object_id, ret);
     444           0 :                                 goto out_free_objects;
     445             :                         }
     446           0 :                         if (crtc->cursor) {
     447           0 :                                 ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
     448           0 :                                 if (ret < 0) {
     449           0 :                                         DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
     450             :                                                         object_id, ret);
     451           0 :                                         goto out_free_objects;
     452             :                                 }
     453             :                         }
     454             :                 }
     455             :         }
     456             : 
     457             :         ret = 0;
     458             : out_free_objects:
     459           0 :         for (o = 0; o < object_count; o++) {
     460           0 :                 if (objects[o])
     461           0 :                         drm_mode_object_put(objects[o]);
     462             :         }
     463           0 :         kfree(objects);
     464           0 :         return ret;
     465             : }
     466             : 
     467             : /*
     468             :  * The master associated with the specified file will have a lease
     469             :  * created containing the objects specified in the ioctl structure.
     470             :  * A file descriptor will be allocated for that and returned to the
     471             :  * application.
     472             :  */
     473           0 : int drm_mode_create_lease_ioctl(struct drm_device *dev,
     474             :                                 void *data, struct drm_file *lessor_priv)
     475             : {
     476           0 :         struct drm_mode_create_lease *cl = data;
     477             :         size_t object_count;
     478           0 :         int ret = 0;
     479             :         struct idr leases;
     480             :         struct drm_master *lessor;
     481           0 :         struct drm_master *lessee = NULL;
     482           0 :         struct file *lessee_file = NULL;
     483           0 :         struct file *lessor_file = lessor_priv->filp;
     484             :         struct drm_file *lessee_priv;
     485           0 :         int fd = -1;
     486             :         uint32_t *object_ids;
     487             : 
     488             :         /* Can't lease without MODESET */
     489           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     490             :                 return -EOPNOTSUPP;
     491             : 
     492           0 :         if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK))) {
     493           0 :                 DRM_DEBUG_LEASE("invalid flags\n");
     494           0 :                 return -EINVAL;
     495             :         }
     496             : 
     497           0 :         lessor = drm_file_get_master(lessor_priv);
     498             :         /* Do not allow sub-leases */
     499           0 :         if (lessor->lessor) {
     500           0 :                 DRM_DEBUG_LEASE("recursive leasing not allowed\n");
     501           0 :                 ret = -EINVAL;
     502           0 :                 goto out_lessor;
     503             :         }
     504             : 
     505           0 :         object_count = cl->object_count;
     506             : 
     507             :         /* Handle leased objects, if any */
     508           0 :         idr_init(&leases);
     509           0 :         if (object_count != 0) {
     510           0 :                 object_ids = memdup_user(u64_to_user_ptr(cl->object_ids),
     511             :                                          array_size(object_count, sizeof(__u32)));
     512           0 :                 if (IS_ERR(object_ids)) {
     513           0 :                         ret = PTR_ERR(object_ids);
     514           0 :                         idr_destroy(&leases);
     515           0 :                         goto out_lessor;
     516             :                 }
     517             : 
     518             :                 /* fill and validate the object idr */
     519           0 :                 ret = fill_object_idr(dev, lessor_priv, &leases,
     520             :                                       object_count, object_ids);
     521           0 :                 kfree(object_ids);
     522           0 :                 if (ret) {
     523           0 :                         DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
     524           0 :                         idr_destroy(&leases);
     525           0 :                         goto out_lessor;
     526             :                 }
     527             :         }
     528             : 
     529             :         /* Allocate a file descriptor for the lease */
     530           0 :         fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
     531           0 :         if (fd < 0) {
     532           0 :                 idr_destroy(&leases);
     533           0 :                 ret = fd;
     534           0 :                 goto out_lessor;
     535             :         }
     536             : 
     537           0 :         DRM_DEBUG_LEASE("Creating lease\n");
     538             :         /* lessee will take the ownership of leases */
     539           0 :         lessee = drm_lease_create(lessor, &leases);
     540             : 
     541           0 :         if (IS_ERR(lessee)) {
     542           0 :                 ret = PTR_ERR(lessee);
     543           0 :                 idr_destroy(&leases);
     544           0 :                 goto out_leases;
     545             :         }
     546             : 
     547             :         /* Clone the lessor file to create a new file for us */
     548           0 :         DRM_DEBUG_LEASE("Allocating lease file\n");
     549           0 :         lessee_file = file_clone_open(lessor_file);
     550           0 :         if (IS_ERR(lessee_file)) {
     551           0 :                 ret = PTR_ERR(lessee_file);
     552             :                 goto out_lessee;
     553             :         }
     554             : 
     555           0 :         lessee_priv = lessee_file->private_data;
     556             :         /* Change the file to a master one */
     557           0 :         drm_master_put(&lessee_priv->master);
     558           0 :         lessee_priv->master = lessee;
     559           0 :         lessee_priv->is_master = 1;
     560           0 :         lessee_priv->authenticated = 1;
     561             : 
     562             :         /* Pass fd back to userspace */
     563           0 :         DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
     564           0 :         cl->fd = fd;
     565           0 :         cl->lessee_id = lessee->lessee_id;
     566             : 
     567             :         /* Hook up the fd */
     568           0 :         fd_install(fd, lessee_file);
     569             : 
     570           0 :         drm_master_put(&lessor);
     571           0 :         DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
     572           0 :         return 0;
     573             : 
     574             : out_lessee:
     575           0 :         drm_master_put(&lessee);
     576             : 
     577             : out_leases:
     578           0 :         put_unused_fd(fd);
     579             : 
     580             : out_lessor:
     581           0 :         drm_master_put(&lessor);
     582           0 :         DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
     583           0 :         return ret;
     584             : }
     585             : 
     586           0 : int drm_mode_list_lessees_ioctl(struct drm_device *dev,
     587             :                                void *data, struct drm_file *lessor_priv)
     588             : {
     589           0 :         struct drm_mode_list_lessees *arg = data;
     590           0 :         __u32 __user *lessee_ids = (__u32 __user *) (uintptr_t) (arg->lessees_ptr);
     591           0 :         __u32 count_lessees = arg->count_lessees;
     592             :         struct drm_master *lessor, *lessee;
     593             :         int count;
     594           0 :         int ret = 0;
     595             : 
     596           0 :         if (arg->pad)
     597             :                 return -EINVAL;
     598             : 
     599             :         /* Can't lease without MODESET */
     600           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     601             :                 return -EOPNOTSUPP;
     602             : 
     603           0 :         lessor = drm_file_get_master(lessor_priv);
     604           0 :         DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id);
     605             : 
     606           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     607             : 
     608           0 :         count = 0;
     609           0 :         drm_for_each_lessee(lessee, lessor) {
     610             :                 /* Only list un-revoked leases */
     611           0 :                 if (!idr_is_empty(&lessee->leases)) {
     612           0 :                         if (count_lessees > count) {
     613           0 :                                 DRM_DEBUG_LEASE("Add lessee %d\n", lessee->lessee_id);
     614           0 :                                 ret = put_user(lessee->lessee_id, lessee_ids + count);
     615           0 :                                 if (ret)
     616             :                                         break;
     617             :                         }
     618           0 :                         count++;
     619             :                 }
     620             :         }
     621             : 
     622           0 :         DRM_DEBUG_LEASE("Lessor leases to %d\n", count);
     623           0 :         if (ret == 0)
     624           0 :                 arg->count_lessees = count;
     625             : 
     626           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     627           0 :         drm_master_put(&lessor);
     628             : 
     629           0 :         return ret;
     630             : }
     631             : 
     632             : /* Return the list of leased objects for the specified lessee */
     633           0 : int drm_mode_get_lease_ioctl(struct drm_device *dev,
     634             :                              void *data, struct drm_file *lessee_priv)
     635             : {
     636           0 :         struct drm_mode_get_lease *arg = data;
     637           0 :         __u32 __user *object_ids = (__u32 __user *) (uintptr_t) (arg->objects_ptr);
     638           0 :         __u32 count_objects = arg->count_objects;
     639             :         struct drm_master *lessee;
     640             :         struct idr *object_idr;
     641             :         int count;
     642             :         void *entry;
     643             :         int object;
     644           0 :         int ret = 0;
     645             : 
     646           0 :         if (arg->pad)
     647             :                 return -EINVAL;
     648             : 
     649             :         /* Can't lease without MODESET */
     650           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     651             :                 return -EOPNOTSUPP;
     652             : 
     653           0 :         lessee = drm_file_get_master(lessee_priv);
     654           0 :         DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id);
     655             : 
     656           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     657             : 
     658           0 :         if (lessee->lessor == NULL)
     659             :                 /* owner can use all objects */
     660           0 :                 object_idr = &lessee->dev->mode_config.object_idr;
     661             :         else
     662             :                 /* lessee can only use allowed object */
     663           0 :                 object_idr = &lessee->leases;
     664             : 
     665           0 :         count = 0;
     666           0 :         idr_for_each_entry(object_idr, entry, object) {
     667           0 :                 if (count_objects > count) {
     668           0 :                         DRM_DEBUG_LEASE("adding object %d\n", object);
     669           0 :                         ret = put_user(object, object_ids + count);
     670           0 :                         if (ret)
     671             :                                 break;
     672             :                 }
     673           0 :                 count++;
     674             :         }
     675             : 
     676           0 :         DRM_DEBUG("lease holds %d objects\n", count);
     677           0 :         if (ret == 0)
     678           0 :                 arg->count_objects = count;
     679             : 
     680           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     681           0 :         drm_master_put(&lessee);
     682             : 
     683           0 :         return ret;
     684             : }
     685             : 
     686             : /*
     687             :  * This removes all of the objects from the lease without
     688             :  * actually getting rid of the lease itself; that way all
     689             :  * references to it still work correctly
     690             :  */
     691           0 : int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
     692             :                                 void *data, struct drm_file *lessor_priv)
     693             : {
     694           0 :         struct drm_mode_revoke_lease *arg = data;
     695             :         struct drm_master *lessor;
     696             :         struct drm_master *lessee;
     697           0 :         int ret = 0;
     698             : 
     699           0 :         DRM_DEBUG_LEASE("revoke lease for %d\n", arg->lessee_id);
     700             : 
     701             :         /* Can't lease without MODESET */
     702           0 :         if (!drm_core_check_feature(dev, DRIVER_MODESET))
     703             :                 return -EOPNOTSUPP;
     704             : 
     705           0 :         lessor = drm_file_get_master(lessor_priv);
     706           0 :         mutex_lock(&dev->mode_config.idr_mutex);
     707             : 
     708           0 :         lessee = _drm_find_lessee(lessor, arg->lessee_id);
     709             : 
     710             :         /* No such lessee */
     711           0 :         if (!lessee) {
     712             :                 ret = -ENOENT;
     713             :                 goto fail;
     714             :         }
     715             : 
     716             :         /* Lease is not held by lessor */
     717           0 :         if (lessee->lessor != lessor) {
     718             :                 ret = -EACCES;
     719             :                 goto fail;
     720             :         }
     721             : 
     722           0 :         _drm_lease_revoke(lessee);
     723             : 
     724             : fail:
     725           0 :         mutex_unlock(&dev->mode_config.idr_mutex);
     726           0 :         drm_master_put(&lessor);
     727             : 
     728           0 :         return ret;
     729             : }

Generated by: LCOV version 1.14