1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright © 2017 Keith Packard <keithp@keithp.com>
5 #include <linux/file.h>
6 #include <linux/uaccess.h>
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>
15 #include "drm_crtc_internal.h"
16 #include "drm_internal.h"
17 #include "drm_legacy.h"
19 #define drm_for_each_lessee(lessee, lessor) \
20 list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)
22 static uint64_t drm_lease_idr_object
;
25 * drm_lease_owner - return ancestor owner drm_master
26 * @master: drm_master somewhere within tree of lessees and lessors
30 * drm_master at the top of the tree (i.e, with lessor NULL
32 struct drm_master
*drm_lease_owner(struct drm_master
*master
)
34 while (master
->lessor
!= NULL
)
35 master
= master
->lessor
;
40 * _drm_find_lessee - find lessee by id (idr_mutex held)
41 * @master: drm_master of lessor
46 * drm_master of the lessee if valid, NULL otherwise
49 static struct drm_master
*
50 _drm_find_lessee(struct drm_master
*master
, int lessee_id
)
52 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
53 return idr_find(&drm_lease_owner(master
)->lessee_idr
, lessee_id
);
57 * _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
58 * @master: the master to check the lease status of
59 * @id: the id to check
61 * Checks if the specified master holds a lease on the object. Return
64 * true 'master' holds a lease on (or owns) the object
65 * false 'master' does not hold a lease.
67 static int _drm_lease_held_master(struct drm_master
*master
, int id
)
69 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
71 return idr_find(&master
->leases
, id
) != NULL
;
76 * _drm_has_leased - check to see if an object has been leased (idr_mutex held)
77 * @master: the master to check the lease status of
78 * @id: the id to check
80 * Checks if any lessee of 'master' holds a lease on 'id'. Return
83 * true Some lessee holds a lease on the object.
84 * false No lessee has a lease on the object.
86 static bool _drm_has_leased(struct drm_master
*master
, int id
)
88 struct drm_master
*lessee
;
90 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
91 drm_for_each_lessee(lessee
, master
)
92 if (_drm_lease_held_master(lessee
, id
))
98 * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
99 * @file_priv: the master drm_file
102 * Checks if the specified master holds a lease on the object. Return
105 * true 'master' holds a lease on (or owns) the object
106 * false 'master' does not hold a lease.
108 bool _drm_lease_held(struct drm_file
*file_priv
, int id
)
110 if (!file_priv
|| !file_priv
->master
)
113 return _drm_lease_held_master(file_priv
->master
, id
);
117 * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
118 * @file_priv: the master drm_file
121 * Checks if the specified master holds a lease on the object. Return
124 * true 'master' holds a lease on (or owns) the object
125 * false 'master' does not hold a lease.
127 bool drm_lease_held(struct drm_file
*file_priv
, int id
)
129 struct drm_master
*master
;
132 if (!file_priv
|| !file_priv
->master
|| !file_priv
->master
->lessor
)
135 master
= file_priv
->master
;
136 mutex_lock(&master
->dev
->mode_config
.idr_mutex
);
137 ret
= _drm_lease_held_master(master
, id
);
138 mutex_unlock(&master
->dev
->mode_config
.idr_mutex
);
143 * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
144 * @file_priv: requestor file
145 * @crtcs_in: bitmask of crtcs to check
147 * Reconstructs a crtc mask based on the crtcs which are visible
148 * through the specified file.
150 uint32_t drm_lease_filter_crtcs(struct drm_file
*file_priv
, uint32_t crtcs_in
)
152 struct drm_master
*master
;
153 struct drm_device
*dev
;
154 struct drm_crtc
*crtc
;
155 int count_in
, count_out
;
156 uint32_t crtcs_out
= 0;
158 if (!file_priv
|| !file_priv
->master
|| !file_priv
->master
->lessor
)
161 master
= file_priv
->master
;
164 count_in
= count_out
= 0;
165 mutex_lock(&master
->dev
->mode_config
.idr_mutex
);
166 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
167 if (_drm_lease_held_master(master
, crtc
->base
.id
)) {
168 uint32_t mask_in
= 1ul << count_in
;
170 if ((crtcs_in
& mask_in
) != 0) {
171 uint32_t mask_out
= 1ul << count_out
;
173 crtcs_out
|= mask_out
;
179 mutex_unlock(&master
->dev
->mode_config
.idr_mutex
);
184 * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
185 * @lessor: lease holder (or owner) of objects
186 * @leases: objects to lease to the new drm_master
188 * Uses drm_master_create to allocate a new drm_master, then checks to
189 * make sure all of the desired objects can be leased, atomically
190 * leasing them to the new drmmaster.
192 * ERR_PTR(-EACCES) some other master holds the title to any object
193 * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
194 * ERR_PTR(-EBUSY) some other lessee holds title to this object
195 * ERR_PTR(-EEXIST) same object specified more than once in the provided list
196 * ERR_PTR(-ENOMEM) allocation failed
198 static struct drm_master
*drm_lease_create(struct drm_master
*lessor
, struct idr
*leases
)
200 struct drm_device
*dev
= lessor
->dev
;
202 struct drm_master
*lessee
;
207 DRM_DEBUG_LEASE("lessor %d\n", lessor
->lessee_id
);
209 lessee
= drm_master_create(lessor
->dev
);
211 DRM_DEBUG_LEASE("drm_master_create failed\n");
212 return ERR_PTR(-ENOMEM
);
215 mutex_lock(&dev
->mode_config
.idr_mutex
);
217 idr_for_each_entry(leases
, entry
, object
) {
219 if (!idr_find(&dev
->mode_config
.object_idr
, object
))
221 else if (_drm_has_leased(lessor
, object
))
225 DRM_DEBUG_LEASE("object %d failed %d\n", object
, error
);
230 /* Insert the new lessee into the tree */
231 id
= idr_alloc(&(drm_lease_owner(lessor
)->lessee_idr
), lessee
, 1, 0, GFP_KERNEL
);
237 lessee
->lessee_id
= id
;
238 lessee
->lessor
= drm_master_get(lessor
);
239 list_add_tail(&lessee
->lessee_list
, &lessor
->lessees
);
241 /* Move the leases over */
242 lessee
->leases
= *leases
;
243 DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee
->lessee_id
, lessee
, lessor
->lessee_id
, lessor
);
245 mutex_unlock(&dev
->mode_config
.idr_mutex
);
249 mutex_unlock(&dev
->mode_config
.idr_mutex
);
251 drm_master_put(&lessee
);
253 return ERR_PTR(error
);
257 * drm_lease_destroy - a master is going away (idr_mutex not held)
258 * @master: the drm_master being destroyed
260 * All lessees will have been destroyed as they
261 * hold a reference on their lessor. Notify any
262 * lessor for this master so that it can check
263 * the list of lessees.
265 void drm_lease_destroy(struct drm_master
*master
)
267 struct drm_device
*dev
= master
->dev
;
269 mutex_lock(&dev
->mode_config
.idr_mutex
);
271 DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master
->lessee_id
);
273 /* This master is referenced by all lessees, hence it cannot be destroyed
274 * until all of them have been
276 WARN_ON(!list_empty(&master
->lessees
));
278 /* Remove this master from the lessee idr in the owner */
279 if (master
->lessee_id
!= 0) {
280 DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master
->lessee_id
);
281 idr_remove(&(drm_lease_owner(master
)->lessee_idr
), master
->lessee_id
);
284 /* Remove this master from any lessee list it may be on */
285 list_del(&master
->lessee_list
);
287 mutex_unlock(&dev
->mode_config
.idr_mutex
);
289 if (master
->lessor
) {
290 /* Tell the master to check the lessee list */
291 drm_sysfs_lease_event(dev
);
292 drm_master_put(&master
->lessor
);
295 DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master
->lessee_id
);
299 * _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
300 * @top: the master losing its lease
302 static void _drm_lease_revoke(struct drm_master
*top
)
306 struct drm_master
*master
= top
;
308 lockdep_assert_held(&top
->dev
->mode_config
.idr_mutex
);
311 * Walk the tree starting at 'top' emptying all leases. Because
312 * the tree is fully connected, we can do this without recursing
315 DRM_DEBUG_LEASE("revoke leases for %p %d\n", master
, master
->lessee_id
);
317 /* Evacuate the lease */
318 idr_for_each_entry(&master
->leases
, entry
, object
)
319 idr_remove(&master
->leases
, object
);
321 /* Depth-first list walk */
324 if (!list_empty(&master
->lessees
)) {
325 master
= list_first_entry(&master
->lessees
, struct drm_master
, lessee_list
);
328 while (master
!= top
&& master
== list_last_entry(&master
->lessor
->lessees
, struct drm_master
, lessee_list
))
329 master
= master
->lessor
;
335 master
= list_next_entry(master
, lessee_list
);
341 * drm_lease_revoke - revoke access to all leased objects (idr_mutex not held)
342 * @top: the master losing its lease
344 void drm_lease_revoke(struct drm_master
*top
)
346 mutex_lock(&top
->dev
->mode_config
.idr_mutex
);
347 _drm_lease_revoke(top
);
348 mutex_unlock(&top
->dev
->mode_config
.idr_mutex
);
351 static int validate_lease(struct drm_device
*dev
,
353 struct drm_mode_object
**objects
,
354 bool universal_planes
)
358 int has_connector
= -1;
361 /* we want to confirm that there is at least one crtc, plane
364 for (o
= 0; o
< object_count
; o
++) {
365 if (objects
[o
]->type
== DRM_MODE_OBJECT_CRTC
&& has_crtc
== -1) {
368 if (objects
[o
]->type
== DRM_MODE_OBJECT_CONNECTOR
&& has_connector
== -1)
371 if (universal_planes
) {
372 if (objects
[o
]->type
== DRM_MODE_OBJECT_PLANE
&& has_plane
== -1)
376 if (has_crtc
== -1 || has_connector
== -1)
378 if (universal_planes
&& has_plane
== -1)
383 static int fill_object_idr(struct drm_device
*dev
,
384 struct drm_file
*lessor_priv
,
389 struct drm_mode_object
**objects
;
392 bool universal_planes
= READ_ONCE(lessor_priv
->universal_planes
);
394 objects
= kcalloc(object_count
, sizeof(struct drm_mode_object
*),
399 /* step one - get references to all the mode objects
400 and check for validity. */
401 for (o
= 0; o
< object_count
; o
++) {
402 objects
[o
] = drm_mode_object_find(dev
, lessor_priv
,
404 DRM_MODE_OBJECT_ANY
);
407 goto out_free_objects
;
410 if (!drm_mode_object_lease_required(objects
[o
]->type
)) {
411 DRM_DEBUG_KMS("invalid object for lease\n");
413 goto out_free_objects
;
417 ret
= validate_lease(dev
, object_count
, objects
, universal_planes
);
419 DRM_DEBUG_LEASE("lease validation failed\n");
420 goto out_free_objects
;
423 /* add their IDs to the lease request - taking into account
425 for (o
= 0; o
< object_count
; o
++) {
426 struct drm_mode_object
*obj
= objects
[o
];
427 u32 object_id
= objects
[o
]->id
;
429 DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id
);
432 * We're using an IDR to hold the set of leased
433 * objects, but we don't need to point at the object's
434 * data structure from the lease as the main object_idr
435 * will be used to actually find that. Instead, all we
436 * really want is a 'leased/not-leased' result, for
437 * which any non-NULL pointer will work fine.
439 ret
= idr_alloc(leases
, &drm_lease_idr_object
, object_id
, object_id
+ 1, GFP_KERNEL
);
441 DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
443 goto out_free_objects
;
445 if (obj
->type
== DRM_MODE_OBJECT_CRTC
&& !universal_planes
) {
446 struct drm_crtc
*crtc
= obj_to_crtc(obj
);
448 ret
= idr_alloc(leases
, &drm_lease_idr_object
, crtc
->primary
->base
.id
, crtc
->primary
->base
.id
+ 1, GFP_KERNEL
);
450 DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
452 goto out_free_objects
;
455 ret
= idr_alloc(leases
, &drm_lease_idr_object
, crtc
->cursor
->base
.id
, crtc
->cursor
->base
.id
+ 1, GFP_KERNEL
);
457 DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
459 goto out_free_objects
;
467 for (o
= 0; o
< object_count
; o
++) {
469 drm_mode_object_put(objects
[o
]);
476 * drm_mode_create_lease_ioctl - create a new lease
477 * @dev: the drm device
478 * @data: pointer to struct drm_mode_create_lease
479 * @lessor_priv: the file being manipulated
481 * The master associated with the specified file will have a lease
482 * created containing the objects specified in the ioctl structure.
483 * A file descriptor will be allocated for that and returned to the
486 int drm_mode_create_lease_ioctl(struct drm_device
*dev
,
487 void *data
, struct drm_file
*lessor_priv
)
489 struct drm_mode_create_lease
*cl
= data
;
493 struct drm_master
*lessor
= lessor_priv
->master
;
494 struct drm_master
*lessee
= NULL
;
495 struct file
*lessee_file
= NULL
;
496 struct file
*lessor_file
= lessor_priv
->filp
;
497 struct drm_file
*lessee_priv
;
499 uint32_t *object_ids
;
501 /* Can't lease without MODESET */
502 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
505 /* Do not allow sub-leases */
506 if (lessor
->lessor
) {
507 DRM_DEBUG_LEASE("recursive leasing not allowed\n");
511 /* need some objects */
512 if (cl
->object_count
== 0) {
513 DRM_DEBUG_LEASE("no objects in lease\n");
517 if (cl
->flags
&& (cl
->flags
& ~(O_CLOEXEC
| O_NONBLOCK
))) {
518 DRM_DEBUG_LEASE("invalid flags\n");
522 object_count
= cl
->object_count
;
524 object_ids
= memdup_user(u64_to_user_ptr(cl
->object_ids
),
525 array_size(object_count
, sizeof(__u32
)));
526 if (IS_ERR(object_ids
))
527 return PTR_ERR(object_ids
);
531 /* fill and validate the object idr */
532 ret
= fill_object_idr(dev
, lessor_priv
, &leases
,
533 object_count
, object_ids
);
536 DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret
);
537 idr_destroy(&leases
);
541 /* Allocate a file descriptor for the lease */
542 fd
= get_unused_fd_flags(cl
->flags
& (O_CLOEXEC
| O_NONBLOCK
));
544 idr_destroy(&leases
);
548 DRM_DEBUG_LEASE("Creating lease\n");
549 /* lessee will take the ownership of leases */
550 lessee
= drm_lease_create(lessor
, &leases
);
552 if (IS_ERR(lessee
)) {
553 ret
= PTR_ERR(lessee
);
554 idr_destroy(&leases
);
558 /* Clone the lessor file to create a new file for us */
559 DRM_DEBUG_LEASE("Allocating lease file\n");
560 lessee_file
= file_clone_open(lessor_file
);
561 if (IS_ERR(lessee_file
)) {
562 ret
= PTR_ERR(lessee_file
);
566 lessee_priv
= lessee_file
->private_data
;
567 /* Change the file to a master one */
568 drm_master_put(&lessee_priv
->master
);
569 lessee_priv
->master
= lessee
;
570 lessee_priv
->is_master
= 1;
571 lessee_priv
->authenticated
= 1;
573 /* Pass fd back to userspace */
574 DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd
, lessee
->lessee_id
);
576 cl
->lessee_id
= lessee
->lessee_id
;
579 fd_install(fd
, lessee_file
);
581 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
585 drm_master_put(&lessee
);
590 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret
);
595 * drm_mode_list_lessees_ioctl - list lessee ids
596 * @dev: the drm device
597 * @data: pointer to struct drm_mode_list_lessees
598 * @lessor_priv: the file being manipulated
600 * Starting from the master associated with the specified file,
601 * the master with the provided lessee_id is found, and then
602 * an array of lessee ids associated with leases from that master
606 int drm_mode_list_lessees_ioctl(struct drm_device
*dev
,
607 void *data
, struct drm_file
*lessor_priv
)
609 struct drm_mode_list_lessees
*arg
= data
;
610 __u32 __user
*lessee_ids
= (__u32 __user
*) (uintptr_t) (arg
->lessees_ptr
);
611 __u32 count_lessees
= arg
->count_lessees
;
612 struct drm_master
*lessor
= lessor_priv
->master
, *lessee
;
619 /* Can't lease without MODESET */
620 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
623 DRM_DEBUG_LEASE("List lessees for %d\n", lessor
->lessee_id
);
625 mutex_lock(&dev
->mode_config
.idr_mutex
);
628 drm_for_each_lessee(lessee
, lessor
) {
629 /* Only list un-revoked leases */
630 if (!idr_is_empty(&lessee
->leases
)) {
631 if (count_lessees
> count
) {
632 DRM_DEBUG_LEASE("Add lessee %d\n", lessee
->lessee_id
);
633 ret
= put_user(lessee
->lessee_id
, lessee_ids
+ count
);
641 DRM_DEBUG_LEASE("Lessor leases to %d\n", count
);
643 arg
->count_lessees
= count
;
645 mutex_unlock(&dev
->mode_config
.idr_mutex
);
651 * drm_mode_get_lease_ioctl - list leased objects
652 * @dev: the drm device
653 * @data: pointer to struct drm_mode_get_lease
654 * @lessee_priv: the file being manipulated
656 * Return the list of leased objects for the specified lessee
659 int drm_mode_get_lease_ioctl(struct drm_device
*dev
,
660 void *data
, struct drm_file
*lessee_priv
)
662 struct drm_mode_get_lease
*arg
= data
;
663 __u32 __user
*object_ids
= (__u32 __user
*) (uintptr_t) (arg
->objects_ptr
);
664 __u32 count_objects
= arg
->count_objects
;
665 struct drm_master
*lessee
= lessee_priv
->master
;
666 struct idr
*object_idr
;
675 /* Can't lease without MODESET */
676 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
679 DRM_DEBUG_LEASE("get lease for %d\n", lessee
->lessee_id
);
681 mutex_lock(&dev
->mode_config
.idr_mutex
);
683 if (lessee
->lessor
== NULL
)
684 /* owner can use all objects */
685 object_idr
= &lessee
->dev
->mode_config
.object_idr
;
687 /* lessee can only use allowed object */
688 object_idr
= &lessee
->leases
;
691 idr_for_each_entry(object_idr
, entry
, object
) {
692 if (count_objects
> count
) {
693 DRM_DEBUG_LEASE("adding object %d\n", object
);
694 ret
= put_user(object
, object_ids
+ count
);
701 DRM_DEBUG("lease holds %d objects\n", count
);
703 arg
->count_objects
= count
;
705 mutex_unlock(&dev
->mode_config
.idr_mutex
);
711 * drm_mode_revoke_lease_ioctl - revoke lease
712 * @dev: the drm device
713 * @data: pointer to struct drm_mode_revoke_lease
714 * @lessor_priv: the file being manipulated
716 * This removes all of the objects from the lease without
717 * actually getting rid of the lease itself; that way all
718 * references to it still work correctly
720 int drm_mode_revoke_lease_ioctl(struct drm_device
*dev
,
721 void *data
, struct drm_file
*lessor_priv
)
723 struct drm_mode_revoke_lease
*arg
= data
;
724 struct drm_master
*lessor
= lessor_priv
->master
;
725 struct drm_master
*lessee
;
728 DRM_DEBUG_LEASE("revoke lease for %d\n", arg
->lessee_id
);
730 /* Can't lease without MODESET */
731 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
734 mutex_lock(&dev
->mode_config
.idr_mutex
);
736 lessee
= _drm_find_lessee(lessor
, arg
->lessee_id
);
744 /* Lease is not held by lessor */
745 if (lessee
->lessor
!= lessor
) {
750 _drm_lease_revoke(lessee
);
753 mutex_unlock(&dev
->mode_config
.idr_mutex
);