diff options
author | Dave Airlie <airlied@redhat.com> | 2017-10-14 02:15:08 +0100 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-10-14 02:29:30 +0100 |
commit | 579148e964dfeb7f01f462ee1c1119a243bcf804 (patch) | |
tree | 7fc42f0d7753e6fb18337a4a2630fa2366099e69 | |
parent | 8a432e4d687b08aae33d77cf7fc201e1a7d2e03e (diff) |
drm/lease: refactor lease idr setup and add some validationdrm-lease-v5
This is fairly simple validation, it verifies we hvae at least
one crtc/connector/plane in the lease.
(this could be relaxed later)
-rw-r--r-- | drivers/gpu/drm/drm_lease.c | 206 |
1 files changed, 134 insertions, 72 deletions
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c index 825bd6289c2a..4299513007fc 100644 --- a/drivers/gpu/drm/drm_lease.c +++ b/drivers/gpu/drm/drm_lease.c @@ -340,6 +340,128 @@ void _drm_lease_revoke(struct drm_master *top) } } +static int validate_lease(struct drm_device *dev, + struct drm_file *lessor_priv, + int object_count, + struct drm_mode_object **objects) +{ + int o; + int has_crtc = -1; + int has_connector = -1; + int has_plane = -1; + + /* we want to confirm that there is at least one crtc, plane + connector object. */ + + for (o = 0; o < object_count; o++) { + if (objects[o]->type == DRM_MODE_OBJECT_CRTC && has_crtc == -1) { + has_crtc = o; + } + if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1) + has_connector = o; + + if (lessor_priv->universal_planes) { + if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1) + has_plane = o; + } + } + if (has_crtc == -1 || has_connector == -1) + return -EINVAL; + if (lessor_priv->universal_planes && has_plane == -1) + return -EINVAL; + return 0; +} + +static int fill_object_idr(struct drm_device *dev, + struct drm_file *lessor_priv, + struct idr *leases, + int object_count, + u32 *object_ids) +{ + struct drm_mode_object **objects; + u32 o; + int ret; + objects = kcalloc(object_count, sizeof(struct drm_mode_object *), + GFP_KERNEL); + if (!objects) + return -ENOMEM; + + /* step one - get references to all the mode objects + and check for validity. */ + for (o = 0; o < object_count; o++) { + if ((int) object_ids[o] < 0) { + ret = -EINVAL; + goto out_free_objects; + } + + objects[o] = drm_mode_object_find(dev, lessor_priv, + object_ids[o], + DRM_MODE_OBJECT_ANY); + if (!objects[o]) { + ret = -ENOENT; + goto out_free_objects; + } + + if (!drm_mode_object_lease_required(objects[o]->type)) { + ret = -EINVAL; + goto out_free_objects; + } + } + + ret = validate_lease(dev, lessor_priv, object_count, objects); + if (ret) + goto out_free_objects; + + /* add their IDs to the lease request - taking into account + universal planes */ + for (o = 0; o < object_count; o++) { + struct drm_mode_object *obj = objects[o]; + u32 object_id = objects[o]->id; + DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id); + + /* + * We're using an IDR to hold the set of leased + * objects, but we don't need to point at the object's + * data structure from the lease as the main crtc_idr + * will be used to actually find that. Instead, all we + * really want is a 'leased/not-leased' result, for + * which any non-NULL pointer will work fine. + */ + ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL); + if (ret < 0) { + DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n", + object_id, ret); + goto out_free_objects; + } + if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) { + struct drm_crtc *crtc = obj_to_crtc(obj); + ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); + if (ret < 0) { + DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n", + object_id, ret); + goto out_free_objects; + } + if (crtc->cursor) { + ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL); + if (ret < 0) { + DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n", + object_id, ret); + goto out_free_objects; + } + } + } + } + + ret = 0; +out_free_objects: + for (o = 0; o < object_count; o++) { + if (objects[o]) + drm_mode_object_put(objects[o]); + } + kfree(objects); + return ret; +} + /** * drm_mode_create_lease_ioctl - create a new lease * @dev: the drm device @@ -356,7 +478,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, { struct drm_mode_create_lease *cl = data; size_t object_count; - size_t o; int ret = 0; struct idr leases; struct drm_master *lessor = lessor_priv->master; @@ -386,81 +507,22 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev, idr_init(&leases); + /* fill and validate the object idr */ + ret = fill_object_idr(dev, lessor_priv, &leases, + object_count, object_ids); + kfree(object_ids); + if (ret) { + idr_destroy(&leases); + return ret; + } + /* Allocate a file descriptor for the lease */ fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK)); if (fd < 0) { - kfree(object_ids); + idr_destroy(&leases); return fd; } - DRM_DEBUG_LEASE("Creating new lease\n"); - - /* Lookup the mode objects and add their IDs to the lease request */ - for (o = 0; o < object_count; o++) { - __u32 object_id = object_ids[o]; - struct drm_mode_object *obj; - - DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id); - - if ((int) object_id < 0) { - ret = -EINVAL; - goto out_leases; - } - - obj = drm_mode_object_find(dev, lessor_priv, object_id, - DRM_MODE_OBJECT_ANY); - if (!obj) { - ret = -ENOENT; - goto out_leases; - } - - /* only allow leasing on crtc/plane/connector objects */ - if (!drm_mode_object_lease_required(obj->type)) { - ret = -EINVAL; - drm_mode_object_put(obj); - goto out_leases; - } - - /* - * We're using an IDR to hold the set of leased - * objects, but we don't need to point at the object's - * data structure from the lease as the main crtc_idr - * will be used to actually find that. Instead, all we - * really want is a 'leased/not-leased' result, for - * which any non-NULL pointer will work fine. - */ - ret = idr_alloc(&leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL); - if (ret < 0) { - DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n", - object_id, ret); - drm_mode_object_put(obj); - goto out_leases; - } - if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) { - struct drm_crtc *crtc = obj_to_crtc(obj); - ret = idr_alloc(&leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL); - if (ret < 0) { - DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n", - object_id, ret); - drm_mode_object_put(obj); - goto out_leases; - } - if (crtc->cursor) { - ret = idr_alloc(&leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL); - if (ret < 0) { - DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n", - object_id, ret); - drm_mode_object_put(obj); - goto out_leases; - } - } - } - drm_mode_object_put(obj); - } - - kfree(object_ids); - object_ids = NULL; - mutex_lock(&dev->master_mutex); DRM_DEBUG_LEASE("Creating lease\n"); @@ -517,9 +579,9 @@ out_lessee: drm_master_put(&lessee); out_leases: - idr_destroy(&leases); put_unused_fd(fd); - kfree(object_ids); + idr_destroy(&leases); + DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret); return ret; } |