Commit 2ed077e4 authored by Keith Packard's avatar Keith Packard Committed by Dave Airlie

drm: Add drm_object lease infrastructure [v5]

This provides new data structures to hold "lease" information about
drm mode setting objects, and provides for creating new drm_masters
which have access to a subset of the available drm resources.

An 'owner' is a drm_master which is not leasing the objects from
another drm_master, and hence 'owns' them.

A 'lessee' is a drm_master which is leasing objects from some other
drm_master. Each lessee holds the set of objects which it is leasing
from the lessor.

A 'lessor' is a drm_master which is leasing objects to another
drm_master. This is the same as the owner in the current code.

The set of objects any drm_master 'controls' is limited to the set of
objects it leases (for lessees) or all objects (for owners).

Objects not controlled by a drm_master cannot be modified through the
various state manipulating ioctls, and any state reported back to user
space will be edited to make them appear idle and/or unusable. For
instance, connectors always report 'disconnected', while encoders
report no possible crtcs or clones.

The full list of lessees leasing objects from an owner (either
directly, or indirectly through another lessee), can be searched from
an idr in the drm_master of the owner.

Changes for v2 as suggested by Daniel Vetter <daniel.vetter@ffwll.ch>:

* Sub-leasing has been disabled.

* BUG_ON for lock checking replaced with lockdep_assert_held

* 'change' ioctl has been removed.

* Leased objects can always be controlled by the lessor; the
  'mask_lease' flag has been removed

* Checking for leased status has been simplified, replacing
  the drm_lease_check function with drm_lease_held.

Changes in v3, some suggested by Dave Airlie <airlied@gmail.com>

* Add revocation. This allows leases to be effectively revoked by
  removing all of the objects they have access to. The lease itself
  hangs around as it's hanging off a file.

* Free the leases IDR when the master is destroyed

* _drm_lease_held should look at lessees, not lessor

* Allow non-master files to check for lease status

Changes in v4, suggested by Dave Airlie <airlied@gmail.com>

* Formatting and whitespace changes

Changes in v5 (airlied)

* check DRIVER_MODESET before lease destroy call
* check DRIVER_MODESET for lease revoke (Chris)
* Use idr_mutex uniformly for all lease elements of struct drm_master. (Keith)
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent e7646f84
...@@ -17,7 +17,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ ...@@ -17,7 +17,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_encoder.o drm_mode_object.o drm_property.o \ drm_encoder.o drm_mode_object.o drm_property.o \
drm_plane.o drm_color_mgmt.o drm_print.o \ drm_plane.o drm_color_mgmt.o drm_print.o \
drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
drm_syncobj.o drm_syncobj.o drm_lease.o
drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
drm-$(CONFIG_DRM_VM) += drm_vm.o drm-$(CONFIG_DRM_VM) += drm_vm.o
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include "drm_internal.h" #include "drm_internal.h"
#include "drm_legacy.h" #include "drm_legacy.h"
#include <drm/drm_lease.h>
/** /**
* DOC: master and authentication * DOC: master and authentication
...@@ -93,7 +94,7 @@ int drm_authmagic(struct drm_device *dev, void *data, ...@@ -93,7 +94,7 @@ int drm_authmagic(struct drm_device *dev, void *data,
return file ? 0 : -EINVAL; return file ? 0 : -EINVAL;
} }
static struct drm_master *drm_master_create(struct drm_device *dev) struct drm_master *drm_master_create(struct drm_device *dev)
{ {
struct drm_master *master; struct drm_master *master;
...@@ -107,6 +108,14 @@ static struct drm_master *drm_master_create(struct drm_device *dev) ...@@ -107,6 +108,14 @@ static struct drm_master *drm_master_create(struct drm_device *dev)
idr_init(&master->magic_map); idr_init(&master->magic_map);
master->dev = dev; master->dev = dev;
/* initialize the tree of output resource lessees */
master->lessor = NULL;
master->lessee_id = 0;
INIT_LIST_HEAD(&master->lessees);
INIT_LIST_HEAD(&master->lessee_list);
idr_init(&master->leases);
idr_init(&master->lessee_idr);
return master; return master;
} }
...@@ -189,6 +198,12 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, ...@@ -189,6 +198,12 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
goto out_unlock; goto out_unlock;
} }
if (file_priv->master->lessor != NULL) {
DRM_DEBUG_LEASE("Attempt to set lessee %d as master\n", file_priv->master->lessee_id);
ret = -EINVAL;
goto out_unlock;
}
ret = drm_set_master(dev, file_priv, false); ret = drm_set_master(dev, file_priv, false);
out_unlock: out_unlock:
mutex_unlock(&dev->master_mutex); mutex_unlock(&dev->master_mutex);
...@@ -270,6 +285,13 @@ void drm_master_release(struct drm_file *file_priv) ...@@ -270,6 +285,13 @@ void drm_master_release(struct drm_file *file_priv)
if (dev->master == file_priv->master) if (dev->master == file_priv->master)
drm_drop_master(dev, file_priv); drm_drop_master(dev, file_priv);
out: out:
if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
/* Revoke any leases held by this or lessees, but only if
* this is the "real" master
*/
drm_lease_revoke(master);
}
/* drop the master reference held by the file priv */ /* drop the master reference held by the file priv */
if (file_priv->master) if (file_priv->master)
drm_master_put(&file_priv->master); drm_master_put(&file_priv->master);
...@@ -310,12 +332,18 @@ static void drm_master_destroy(struct kref *kref) ...@@ -310,12 +332,18 @@ static void drm_master_destroy(struct kref *kref)
struct drm_master *master = container_of(kref, struct drm_master, refcount); struct drm_master *master = container_of(kref, struct drm_master, refcount);
struct drm_device *dev = master->dev; struct drm_device *dev = master->dev;
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_lease_destroy(master);
if (dev->driver->master_destroy) if (dev->driver->master_destroy)
dev->driver->master_destroy(dev, master); dev->driver->master_destroy(dev, master);
drm_legacy_master_rmmaps(dev, master); drm_legacy_master_rmmaps(dev, master);
idr_destroy(&master->magic_map); idr_destroy(&master->magic_map);
idr_destroy(&master->leases);
idr_destroy(&master->lessee_idr);
kfree(master->unique); kfree(master->unique);
kfree(master); kfree(master);
} }
......
This diff is collapsed.
...@@ -52,6 +52,12 @@ struct drm_lock_data { ...@@ -52,6 +52,12 @@ struct drm_lock_data {
* @dev: Link back to the DRM device * @dev: Link back to the DRM device
* @lock: DRI1 lock information. * @lock: DRI1 lock information.
* @driver_priv: Pointer to driver-private information. * @driver_priv: Pointer to driver-private information.
* @lessor: Lease holder
* @lessee_id: id for lessees. Owners always have id 0
* @lessee_list: other lessees of the same master
* @lessees: drm_masters leasing from this one
* @leases: Objects leased to this drm_master.
* @lessee_idr: All lessees under this owner (only used where lessor == NULL)
* *
* Note that master structures are only relevant for the legacy/primary device * Note that master structures are only relevant for the legacy/primary device
* nodes, hence there can only be one per device, not one per drm_minor. * nodes, hence there can only be one per device, not one per drm_minor.
...@@ -76,10 +82,25 @@ struct drm_master { ...@@ -76,10 +82,25 @@ struct drm_master {
struct idr magic_map; struct idr magic_map;
struct drm_lock_data lock; struct drm_lock_data lock;
void *driver_priv; void *driver_priv;
/* Tree of display resource leases, each of which is a drm_master struct
* All of these get activated simultaneously, so drm_device master points
* at the top of the tree (for which lessor is NULL). Protected by
* &drm_device.mode_config.idr_mutex.
*/
struct drm_master *lessor;
int lessee_id;
struct list_head lessee_list;
struct list_head lessees;
struct idr leases;
struct idr lessee_idr;
}; };
struct drm_master *drm_master_get(struct drm_master *master); struct drm_master *drm_master_get(struct drm_master *master);
void drm_master_put(struct drm_master **master); void drm_master_put(struct drm_master **master);
bool drm_is_current_master(struct drm_file *fpriv); bool drm_is_current_master(struct drm_file *fpriv);
struct drm_master *drm_master_create(struct drm_device *dev);
#endif #endif
/*
* Copyright © 2017 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _DRM_LEASE_H_
#define _DRM_LEASE_H_
struct drm_file;
struct drm_device;
struct drm_master;
struct drm_master *drm_lease_owner(struct drm_master *master);
void drm_lease_destroy(struct drm_master *lessee);
bool drm_lease_held(struct drm_file *file_priv, int id);
bool _drm_lease_held(struct drm_file *file_priv, int id);
void drm_lease_revoke(struct drm_master *master);
uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs);
uint32_t drm_lease_filter_encoders(struct drm_file *file_priv, uint32_t encoders);
#endif /* _DRM_LEASE_H_ */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define __DRM_MODESET_H__ #define __DRM_MODESET_H__
#include <linux/kref.h> #include <linux/kref.h>
#include <drm/drm_lease.h>
struct drm_object_properties; struct drm_object_properties;
struct drm_property; struct drm_property;
struct drm_device; struct drm_device;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment