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