2 * Copyright © 2017 Keith Packard <keithp@keithp.com>
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.
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.
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>
23 #define drm_for_each_lessee(lessee, lessor) \
24 list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)
26 static uint64_t drm_lease_idr_object
;
29 * drm_lease_owner - return ancestor owner drm_master
30 * @master: drm_master somewhere within tree of lessees and lessors
34 * drm_master at the top of the tree (i.e, with lessor NULL
36 struct drm_master
*drm_lease_owner(struct drm_master
*master
)
38 while (master
->lessor
!= NULL
)
39 master
= master
->lessor
;
44 * _drm_find_lessee - find lessee by id (idr_mutex held)
45 * @master: drm_master of lessor
50 * drm_master of the lessee if valid, NULL otherwise
53 static struct drm_master
*
54 _drm_find_lessee(struct drm_master
*master
, int lessee_id
)
56 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
57 return idr_find(&drm_lease_owner(master
)->lessee_idr
, lessee_id
);
61 * _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
62 * @master: the master to check the lease status of
63 * @id: the id to check
65 * Checks if the specified master holds a lease on the object. Return
68 * true 'master' holds a lease on (or owns) the object
69 * false 'master' does not hold a lease.
71 static int _drm_lease_held_master(struct drm_master
*master
, int id
)
73 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
75 return idr_find(&master
->leases
, id
) != NULL
;
80 * _drm_has_leased - check to see if an object has been leased (idr_mutex held)
81 * @master: the master to check the lease status of
82 * @id: the id to check
84 * Checks if any lessee of 'master' holds a lease on 'id'. Return
87 * true Some lessee holds a lease on the object.
88 * false No lessee has a lease on the object.
90 static bool _drm_has_leased(struct drm_master
*master
, int id
)
92 struct drm_master
*lessee
;
94 lockdep_assert_held(&master
->dev
->mode_config
.idr_mutex
);
95 drm_for_each_lessee(lessee
, master
)
96 if (_drm_lease_held_master(lessee
, id
))
102 * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
103 * @file_priv: the master drm_file
106 * Checks if the specified master holds a lease on the object. Return
109 * true 'master' holds a lease on (or owns) the object
110 * false 'master' does not hold a lease.
112 bool _drm_lease_held(struct drm_file
*file_priv
, int id
)
114 if (file_priv
== NULL
|| file_priv
->master
== NULL
)
117 return _drm_lease_held_master(file_priv
->master
, id
);
121 * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
122 * @file_priv: the master drm_file
125 * Checks if the specified master holds a lease on the object. Return
128 * true 'master' holds a lease on (or owns) the object
129 * false 'master' does not hold a lease.
131 bool drm_lease_held(struct drm_file
*file_priv
, int id
)
133 struct drm_master
*master
;
136 if (file_priv
== NULL
|| file_priv
->master
== NULL
)
139 master
= file_priv
->master
;
140 mutex_lock(&master
->dev
->mode_config
.idr_mutex
);
141 ret
= _drm_lease_held_master(master
, id
);
142 mutex_unlock(&master
->dev
->mode_config
.idr_mutex
);
147 * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
148 * @file_priv: requestor file
149 * @crtcs_in: bitmask of crtcs to check
151 * Reconstructs a crtc mask based on the crtcs which are visible
152 * through the specified file.
154 uint32_t drm_lease_filter_crtcs(struct drm_file
*file_priv
, uint32_t crtcs_in
)
156 struct drm_master
*master
;
157 struct drm_device
*dev
;
158 struct drm_crtc
*crtc
;
159 int count_in
, count_out
;
160 uint32_t crtcs_out
= 0;
162 if (file_priv
== NULL
|| file_priv
->master
== NULL
)
165 master
= file_priv
->master
;
168 count_in
= count_out
= 0;
169 mutex_lock(&master
->dev
->mode_config
.idr_mutex
);
170 list_for_each_entry(crtc
, &dev
->mode_config
.crtc_list
, head
) {
171 if (_drm_lease_held_master(master
, crtc
->base
.id
)) {
172 uint32_t mask_in
= 1ul << count_in
;
173 if ((crtcs_in
& mask_in
) != 0) {
174 uint32_t mask_out
= 1ul << count_out
;
175 crtcs_out
|= mask_out
;
181 mutex_unlock(&master
->dev
->mode_config
.idr_mutex
);
186 * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
187 * @lessor: lease holder (or owner) of objects
188 * @leases: objects to lease to the new drm_master
190 * Uses drm_master_create to allocate a new drm_master, then checks to
191 * make sure all of the desired objects can be leased, atomically
192 * leasing them to the new drmmaster.
194 * ERR_PTR(-EACCES) some other master holds the title to any object
195 * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
196 * ERR_PTR(-EBUSY) some other lessee holds title to this object
197 * ERR_PTR(-EEXIST) same object specified more than once in the provided list
198 * ERR_PTR(-ENOMEM) allocation failed
200 static struct drm_master
*drm_lease_create(struct drm_master
*lessor
, struct idr
*leases
)
202 struct drm_device
*dev
= lessor
->dev
;
204 struct drm_master
*lessee
;
209 DRM_DEBUG_LEASE("lessor %d\n", lessor
->lessee_id
);
211 lessee
= drm_master_create(lessor
->dev
);
213 DRM_DEBUG_LEASE("drm_master_create failed\n");
214 return ERR_PTR(-ENOMEM
);
217 mutex_lock(&dev
->mode_config
.idr_mutex
);
219 idr_for_each_entry(leases
, entry
, object
) {
221 if (!idr_find(&dev
->mode_config
.object_idr
, object
))
223 else if (!_drm_lease_held_master(lessor
, object
))
225 else if (_drm_has_leased(lessor
, object
))
229 DRM_DEBUG_LEASE("object %d failed %d\n", object
, error
);
234 /* Insert the new lessee into the tree */
235 id
= idr_alloc(&(drm_lease_owner(lessor
)->lessee_idr
), lessee
, 1, 0, GFP_KERNEL
);
241 lessee
->lessee_id
= id
;
242 lessee
->lessor
= drm_master_get(lessor
);
243 list_add_tail(&lessee
->lessee_list
, &lessor
->lessees
);
245 /* Move the leases over */
246 lessee
->leases
= *leases
;
247 DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee
->lessee_id
, lessee
, lessor
->lessee_id
, lessor
);
249 mutex_unlock(&dev
->mode_config
.idr_mutex
);
253 mutex_unlock(&dev
->mode_config
.idr_mutex
);
255 drm_master_put(&lessee
);
257 return ERR_PTR(error
);
261 * drm_lease_destroy - a master is going away (idr_mutex not held)
262 * @master: the drm_master being destroyed
264 * All lessees will have been destroyed as they
265 * hold a reference on their lessor. Notify any
266 * lessor for this master so that it can check
267 * the list of lessees.
269 void drm_lease_destroy(struct drm_master
*master
)
271 struct drm_device
*dev
= master
->dev
;
273 mutex_lock(&dev
->mode_config
.idr_mutex
);
275 DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master
->lessee_id
);
277 /* This master is referenced by all lessees, hence it cannot be destroyed
278 * until all of them have been
280 WARN_ON(!list_empty(&master
->lessees
));
282 /* Remove this master from the lessee idr in the owner */
283 if (master
->lessee_id
!= 0) {
284 DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master
->lessee_id
);
285 idr_remove(&(drm_lease_owner(master
)->lessee_idr
), master
->lessee_id
);
288 /* Remove this master from any lessee list it may be on */
289 list_del(&master
->lessee_list
);
291 mutex_unlock(&dev
->mode_config
.idr_mutex
);
293 if (master
->lessor
) {
294 /* Tell the master to check the lessee list */
295 drm_sysfs_lease_event(dev
);
296 drm_master_put(&master
->lessor
);
299 DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master
->lessee_id
);
303 * _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
304 * @top: the master losing its lease
306 static void _drm_lease_revoke(struct drm_master
*top
)
310 struct drm_master
*master
= top
;
312 lockdep_assert_held(&top
->dev
->mode_config
.idr_mutex
);
315 * Walk the tree starting at 'top' emptying all leases. Because
316 * the tree is fully connected, we can do this without recursing
319 DRM_DEBUG_LEASE("revoke leases for %p %d\n", master
, master
->lessee_id
);
321 /* Evacuate the lease */
322 idr_for_each_entry(&master
->leases
, entry
, object
)
323 idr_remove(&master
->leases
, object
);
325 /* Depth-first list walk */
328 if (!list_empty(&master
->lessees
)) {
329 master
= list_first_entry(&master
->lessees
, struct drm_master
, lessee_list
);
332 while (master
!= top
&& master
== list_last_entry(&master
->lessor
->lessees
, struct drm_master
, lessee_list
))
333 master
= master
->lessor
;
339 master
= list_next_entry(master
, lessee_list
);
345 * drm_lease_revoke - revoke access to all leased objects (idr_mutex not held)
346 * @top: the master losing its lease
348 void drm_lease_revoke(struct drm_master
*top
)
350 mutex_lock(&top
->dev
->mode_config
.idr_mutex
);
351 _drm_lease_revoke(top
);
352 mutex_unlock(&top
->dev
->mode_config
.idr_mutex
);
355 static int validate_lease(struct drm_device
*dev
,
357 struct drm_mode_object
**objects
,
358 bool universal_planes
)
362 int has_connector
= -1;
365 /* we want to confirm that there is at least one crtc, plane
368 for (o
= 0; o
< object_count
; o
++) {
369 if (objects
[o
]->type
== DRM_MODE_OBJECT_CRTC
&& has_crtc
== -1) {
372 if (objects
[o
]->type
== DRM_MODE_OBJECT_CONNECTOR
&& has_connector
== -1)
375 if (universal_planes
) {
376 if (objects
[o
]->type
== DRM_MODE_OBJECT_PLANE
&& has_plane
== -1)
380 if (has_crtc
== -1 || has_connector
== -1)
382 if (universal_planes
&& has_plane
== -1)
387 static int fill_object_idr(struct drm_device
*dev
,
388 struct drm_file
*lessor_priv
,
393 struct drm_mode_object
**objects
;
396 bool universal_planes
= READ_ONCE(lessor_priv
->universal_planes
);
398 objects
= kcalloc(object_count
, sizeof(struct drm_mode_object
*),
403 /* step one - get references to all the mode objects
404 and check for validity. */
405 for (o
= 0; o
< object_count
; o
++) {
406 if ((int) object_ids
[o
] < 0) {
408 goto out_free_objects
;
411 objects
[o
] = drm_mode_object_find(dev
, lessor_priv
,
413 DRM_MODE_OBJECT_ANY
);
416 goto out_free_objects
;
419 if (!drm_mode_object_lease_required(objects
[o
]->type
)) {
420 DRM_DEBUG_KMS("invalid object for lease\n");
422 goto out_free_objects
;
426 ret
= validate_lease(dev
, object_count
, objects
, universal_planes
);
428 DRM_DEBUG_LEASE("lease validation failed\n");
429 goto out_free_objects
;
432 /* add their IDs to the lease request - taking into account
434 for (o
= 0; o
< object_count
; o
++) {
435 struct drm_mode_object
*obj
= objects
[o
];
436 u32 object_id
= objects
[o
]->id
;
437 DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id
);
440 * We're using an IDR to hold the set of leased
441 * objects, but we don't need to point at the object's
442 * data structure from the lease as the main object_idr
443 * will be used to actually find that. Instead, all we
444 * really want is a 'leased/not-leased' result, for
445 * which any non-NULL pointer will work fine.
447 ret
= idr_alloc(leases
, &drm_lease_idr_object
, object_id
, object_id
+ 1, GFP_KERNEL
);
449 DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
451 goto out_free_objects
;
453 if (obj
->type
== DRM_MODE_OBJECT_CRTC
&& !universal_planes
) {
454 struct drm_crtc
*crtc
= obj_to_crtc(obj
);
455 ret
= idr_alloc(leases
, &drm_lease_idr_object
, crtc
->primary
->base
.id
, crtc
->primary
->base
.id
+ 1, GFP_KERNEL
);
457 DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
459 goto out_free_objects
;
462 ret
= idr_alloc(leases
, &drm_lease_idr_object
, crtc
->cursor
->base
.id
, crtc
->cursor
->base
.id
+ 1, GFP_KERNEL
);
464 DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
466 goto out_free_objects
;
474 for (o
= 0; o
< object_count
; o
++) {
476 drm_mode_object_put(objects
[o
]);
483 * drm_mode_create_lease_ioctl - create a new lease
484 * @dev: the drm device
485 * @data: pointer to struct drm_mode_create_lease
486 * @lessor_priv: the file being manipulated
488 * The master associated with the specified file will have a lease
489 * created containing the objects specified in the ioctl structure.
490 * A file descriptor will be allocated for that and returned to the
493 int drm_mode_create_lease_ioctl(struct drm_device
*dev
,
494 void *data
, struct drm_file
*lessor_priv
)
496 struct drm_mode_create_lease
*cl
= data
;
500 struct drm_master
*lessor
= lessor_priv
->master
;
501 struct drm_master
*lessee
= NULL
;
502 struct file
*lessee_file
= NULL
;
503 struct file
*lessor_file
= lessor_priv
->filp
;
504 struct drm_file
*lessee_priv
;
506 uint32_t *object_ids
;
508 /* Can't lease without MODESET */
509 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
512 /* Do not allow sub-leases */
513 if (lessor
->lessor
) {
514 DRM_DEBUG_LEASE("recursive leasing not allowed\n");
518 /* need some objects */
519 if (cl
->object_count
== 0) {
520 DRM_DEBUG_LEASE("no objects in lease\n");
524 if (cl
->flags
&& (cl
->flags
& ~(O_CLOEXEC
| O_NONBLOCK
))) {
525 DRM_DEBUG_LEASE("invalid flags\n");
529 object_count
= cl
->object_count
;
531 object_ids
= memdup_user(u64_to_user_ptr(cl
->object_ids
),
532 array_size(object_count
, sizeof(__u32
)));
533 if (IS_ERR(object_ids
))
534 return PTR_ERR(object_ids
);
538 /* fill and validate the object idr */
539 ret
= fill_object_idr(dev
, lessor_priv
, &leases
,
540 object_count
, object_ids
);
543 DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret
);
544 idr_destroy(&leases
);
548 /* Allocate a file descriptor for the lease */
549 fd
= get_unused_fd_flags(cl
->flags
& (O_CLOEXEC
| O_NONBLOCK
));
551 idr_destroy(&leases
);
555 DRM_DEBUG_LEASE("Creating lease\n");
556 lessee
= drm_lease_create(lessor
, &leases
);
558 if (IS_ERR(lessee
)) {
559 ret
= PTR_ERR(lessee
);
563 /* Clone the lessor file to create a new file for us */
564 DRM_DEBUG_LEASE("Allocating lease file\n");
565 lessee_file
= file_clone_open(lessor_file
);
566 if (IS_ERR(lessee_file
)) {
567 ret
= PTR_ERR(lessee_file
);
571 lessee_priv
= lessee_file
->private_data
;
572 /* Change the file to a master one */
573 drm_master_put(&lessee_priv
->master
);
574 lessee_priv
->master
= lessee
;
575 lessee_priv
->is_master
= 1;
576 lessee_priv
->authenticated
= 1;
578 /* Pass fd back to userspace */
579 DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd
, lessee
->lessee_id
);
581 cl
->lessee_id
= lessee
->lessee_id
;
584 fd_install(fd
, lessee_file
);
586 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
590 drm_master_put(&lessee
);
594 idr_destroy(&leases
);
596 DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret
);
601 * drm_mode_list_lessees_ioctl - list lessee ids
602 * @dev: the drm device
603 * @data: pointer to struct drm_mode_list_lessees
604 * @lessor_priv: the file being manipulated
606 * Starting from the master associated with the specified file,
607 * the master with the provided lessee_id is found, and then
608 * an array of lessee ids associated with leases from that master
612 int drm_mode_list_lessees_ioctl(struct drm_device
*dev
,
613 void *data
, struct drm_file
*lessor_priv
)
615 struct drm_mode_list_lessees
*arg
= data
;
616 __u32 __user
*lessee_ids
= (__u32 __user
*) (uintptr_t) (arg
->lessees_ptr
);
617 __u32 count_lessees
= arg
->count_lessees
;
618 struct drm_master
*lessor
= lessor_priv
->master
, *lessee
;
625 /* Can't lease without MODESET */
626 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
629 DRM_DEBUG_LEASE("List lessees for %d\n", lessor
->lessee_id
);
631 mutex_lock(&dev
->mode_config
.idr_mutex
);
634 drm_for_each_lessee(lessee
, lessor
) {
635 /* Only list un-revoked leases */
636 if (!idr_is_empty(&lessee
->leases
)) {
637 if (count_lessees
> count
) {
638 DRM_DEBUG_LEASE("Add lessee %d\n", lessee
->lessee_id
);
639 ret
= put_user(lessee
->lessee_id
, lessee_ids
+ count
);
647 DRM_DEBUG_LEASE("Lessor leases to %d\n", count
);
649 arg
->count_lessees
= count
;
651 mutex_unlock(&dev
->mode_config
.idr_mutex
);
657 * drm_mode_get_lease_ioctl - list leased objects
658 * @dev: the drm device
659 * @data: pointer to struct drm_mode_get_lease
660 * @lessee_priv: the file being manipulated
662 * Return the list of leased objects for the specified lessee
665 int drm_mode_get_lease_ioctl(struct drm_device
*dev
,
666 void *data
, struct drm_file
*lessee_priv
)
668 struct drm_mode_get_lease
*arg
= data
;
669 __u32 __user
*object_ids
= (__u32 __user
*) (uintptr_t) (arg
->objects_ptr
);
670 __u32 count_objects
= arg
->count_objects
;
671 struct drm_master
*lessee
= lessee_priv
->master
;
672 struct idr
*object_idr
;
681 /* Can't lease without MODESET */
682 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
685 DRM_DEBUG_LEASE("get lease for %d\n", lessee
->lessee_id
);
687 mutex_lock(&dev
->mode_config
.idr_mutex
);
689 if (lessee
->lessor
== NULL
)
690 /* owner can use all objects */
691 object_idr
= &lessee
->dev
->mode_config
.object_idr
;
693 /* lessee can only use allowed object */
694 object_idr
= &lessee
->leases
;
697 idr_for_each_entry(object_idr
, entry
, object
) {
698 if (count_objects
> count
) {
699 DRM_DEBUG_LEASE("adding object %d\n", object
);
700 ret
= put_user(object
, object_ids
+ count
);
707 DRM_DEBUG("lease holds %d objects\n", count
);
709 arg
->count_objects
= count
;
711 mutex_unlock(&dev
->mode_config
.idr_mutex
);
717 * drm_mode_revoke_lease_ioctl - revoke lease
718 * @dev: the drm device
719 * @data: pointer to struct drm_mode_revoke_lease
720 * @lessor_priv: the file being manipulated
722 * This removes all of the objects from the lease without
723 * actually getting rid of the lease itself; that way all
724 * references to it still work correctly
726 int drm_mode_revoke_lease_ioctl(struct drm_device
*dev
,
727 void *data
, struct drm_file
*lessor_priv
)
729 struct drm_mode_revoke_lease
*arg
= data
;
730 struct drm_master
*lessor
= lessor_priv
->master
;
731 struct drm_master
*lessee
;
734 DRM_DEBUG_LEASE("revoke lease for %d\n", arg
->lessee_id
);
736 /* Can't lease without MODESET */
737 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
740 mutex_lock(&dev
->mode_config
.idr_mutex
);
742 lessee
= _drm_find_lessee(lessor
, arg
->lessee_id
);
750 /* Lease is not held by lessor */
751 if (lessee
->lessor
!= lessor
) {
756 _drm_lease_revoke(lessee
);
759 mutex_unlock(&dev
->mode_config
.idr_mutex
);