mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2025-12-26 18:10:12 +01:00
Add name/open ioctls, separate handle and pointer ref counts.
Names are just another unique integer set (from another idr object). Names are removed when the user refernces (handles) are all destroyed -- this required that handles for objects be counted separately from internal kernel references (so that we can tell when the handles are all gone).
This commit is contained in:
parent
49e8e3372a
commit
39e20bcd5f
5 changed files with 233 additions and 40 deletions
|
|
@ -618,6 +618,9 @@ struct drm_gem_object {
|
|||
/** Reference count of this object */
|
||||
struct kref refcount;
|
||||
|
||||
/** Handle count of this object. Each handle also holds a reference */
|
||||
struct kref handlecount;
|
||||
|
||||
/** Related drm device */
|
||||
struct drm_device *dev;
|
||||
|
||||
|
|
@ -630,6 +633,12 @@ struct drm_gem_object {
|
|||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* Global name for this object, starts at 1. 0 means unnamed.
|
||||
* Access is covered by the object_name_lock in the related drm_device
|
||||
*/
|
||||
int name;
|
||||
|
||||
void *driver_private;
|
||||
};
|
||||
|
||||
|
|
@ -923,6 +932,12 @@ struct drm_device {
|
|||
spinlock_t drw_lock;
|
||||
struct idr drw_idr;
|
||||
/*@} */
|
||||
|
||||
/** \name GEM information */
|
||||
/*@{ */
|
||||
spinlock_t object_name_lock;
|
||||
struct idr object_name_idr;
|
||||
/*@} */
|
||||
};
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
|
|
@ -1307,6 +1322,9 @@ static inline struct drm_memrange *drm_get_mm(struct drm_memrange_node *block)
|
|||
|
||||
void
|
||||
drm_gem_object_free (struct kref *kref);
|
||||
|
||||
void
|
||||
drm_gem_object_handle_free (struct kref *kref);
|
||||
|
||||
/* Graphics Execution Manager library functions (drm_gem.c) */
|
||||
static inline void drm_gem_object_reference(struct drm_gem_object *obj)
|
||||
|
|
@ -1322,6 +1340,26 @@ static inline void drm_gem_object_unreference(struct drm_gem_object *obj)
|
|||
kref_put (&obj->refcount, drm_gem_object_free);
|
||||
}
|
||||
|
||||
static inline void drm_gem_object_handle_reference (struct drm_gem_object *obj)
|
||||
{
|
||||
drm_gem_object_reference (obj);
|
||||
kref_get(&obj->handlecount);
|
||||
}
|
||||
|
||||
static inline void drm_gem_object_handle_unreference (struct drm_gem_object *obj)
|
||||
{
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Must bump handle count first as this may be the last
|
||||
* ref, in which case the object would disappear before we
|
||||
* checked for a name
|
||||
*/
|
||||
kref_put (&obj->handlecount, drm_gem_object_handle_free);
|
||||
drm_gem_object_unreference (obj);
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||
int handle);
|
||||
|
|
@ -1335,6 +1373,11 @@ int drm_gem_pwrite_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_file *file_priv);
|
||||
int drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int drm_gem_name_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
int drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
void drm_gem_open(struct drm_device *dev, struct drm_file *file_private);
|
||||
void drm_gem_release(struct drm_device *dev, struct drm_file *file_private);
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,8 @@ static struct drm_ioctl_desc drm_ioctls[] = {
|
|||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_PREAD, drm_gem_pread_ioctl, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_PWRITE, drm_gem_pwrite_ioctl, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_MMAP, drm_gem_mmap_ioctl, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_NAME, drm_gem_name_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
|
||||
};
|
||||
|
||||
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
|
|||
}
|
||||
|
||||
kref_init (&obj->refcount);
|
||||
kref_init (&obj->handlecount);
|
||||
obj->size = size;
|
||||
|
||||
if (dev->driver->gem_init_object != NULL &&
|
||||
|
|
@ -96,8 +97,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
|
|||
* Removes the mapping from handle to filp for this object.
|
||||
*/
|
||||
static int
|
||||
drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp,
|
||||
int handle)
|
||||
drm_gem_handle_delete(struct drm_file *filp, int handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
|
|
@ -121,10 +121,45 @@ drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp,
|
|||
|
||||
/* Release reference and decrement refcount. */
|
||||
idr_remove(&filp->object_idr, handle);
|
||||
drm_gem_object_unreference(obj);
|
||||
|
||||
spin_unlock(&filp->table_lock);
|
||||
|
||||
drm_gem_object_handle_unreference(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handle for this object. This adds a handle reference
|
||||
* to the object, which includes a regular reference count. Callers
|
||||
* will likely want to dereference the object afterwards.
|
||||
*/
|
||||
static int
|
||||
drm_gem_handle_create (struct drm_file *file_priv,
|
||||
struct drm_gem_object *obj,
|
||||
int *handlep)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Get the user-visible handle using idr.
|
||||
*/
|
||||
again:
|
||||
/* ensure there is space available to allocate a handle */
|
||||
if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) {
|
||||
kfree(obj);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* do the allocation under our spinlock */
|
||||
spin_lock (&file_priv->table_lock);
|
||||
ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep);
|
||||
spin_unlock (&file_priv->table_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
drm_gem_object_handle_reference (obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -171,27 +206,11 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data,
|
|||
if (obj == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get the user-visible handle using idr.
|
||||
*
|
||||
* I'm not really sure why the idr api needs us to do this in two
|
||||
* repeating steps. It handles internal locking of its data
|
||||
* structure, yet insists that we keep its memory allocation step
|
||||
* separate from its slot-finding step for locking purposes.
|
||||
*/
|
||||
do {
|
||||
if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) {
|
||||
kfree(obj);
|
||||
return -EFAULT;
|
||||
}
|
||||
ret = drm_gem_handle_create (file_priv, obj, &handle);
|
||||
drm_gem_object_handle_unreference(obj);
|
||||
|
||||
ret = idr_get_new_above(&file_priv->object_idr, obj, 1,
|
||||
&handle);
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
if (ret != 0) {
|
||||
drm_gem_object_unreference(obj);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
args->handle = handle;
|
||||
|
||||
|
|
@ -208,7 +227,7 @@ drm_gem_unreference_ioctl(struct drm_device *dev, void *data,
|
|||
struct drm_gem_unreference *args = data;
|
||||
int ret;
|
||||
|
||||
ret = drm_gem_handle_delete(dev, file_priv, args->handle);
|
||||
ret = drm_gem_handle_delete(file_priv, args->handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -315,6 +334,87 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a global name for an object, returning the name.
|
||||
*
|
||||
* Note that the name does not hold a reference; when the object
|
||||
* is freed, the name goes away.
|
||||
*/
|
||||
int
|
||||
drm_gem_name_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_name *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||
if (obj == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
again:
|
||||
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
spin_lock(&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
spin_unlock (&dev->object_name_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
ret = idr_get_new_above (&dev->object_name_idr, obj, 1,
|
||||
&obj->name);
|
||||
spin_unlock (&dev->object_name_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0) {
|
||||
drm_gem_object_unreference(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave the reference from the lookup around as the
|
||||
* name table now holds one
|
||||
*/
|
||||
args->name = (uint64_t) obj->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an object using the global name, returning a handle and the size.
|
||||
*
|
||||
* This handle (of course) holds a reference to the object, so the object
|
||||
* will not go away until the handle is deleted.
|
||||
*/
|
||||
int
|
||||
drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_open *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
int handle;
|
||||
|
||||
spin_lock (&dev->object_name_lock);
|
||||
obj = idr_find (&dev->object_name_idr, (int) args->name);
|
||||
if (obj)
|
||||
drm_gem_object_reference (obj);
|
||||
spin_unlock (&dev->object_name_lock);
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
ret = drm_gem_handle_create (file_priv, obj, &handle);
|
||||
drm_gem_object_unreference (obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
args->handle = handle;
|
||||
args->size = obj->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at device open time, sets up the structure for handling refcounting
|
||||
* of mm objects.
|
||||
|
|
@ -325,13 +425,13 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
|
|||
idr_init(&file_private->object_idr);
|
||||
}
|
||||
|
||||
/** Called at device close to release the file's references on objects. */
|
||||
/** Called at device close to release the file's handle references on objects. */
|
||||
static int
|
||||
drm_gem_object_release(int id, void *ptr, void *data)
|
||||
drm_gem_object_release_handle (int id, void *ptr, void *data)
|
||||
{
|
||||
struct drm_gem_object *obj = ptr;
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
drm_gem_object_handle_unreference(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -344,11 +444,16 @@ drm_gem_object_release(int id, void *ptr, void *data)
|
|||
void
|
||||
drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
|
||||
{
|
||||
idr_for_each(&file_private->object_idr, &drm_gem_object_release, NULL);
|
||||
idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, NULL);
|
||||
|
||||
idr_destroy(&file_private->object_idr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the last reference to the object has been lost.
|
||||
*
|
||||
* Frees the object
|
||||
*/
|
||||
void
|
||||
drm_gem_object_free (struct kref *kref)
|
||||
{
|
||||
|
|
@ -359,6 +464,36 @@ drm_gem_object_free (struct kref *kref)
|
|||
dev->driver->gem_free_object(obj);
|
||||
|
||||
fput(obj->filp);
|
||||
|
||||
kfree(obj);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_object_free);
|
||||
|
||||
/**
|
||||
* Called after the last handle to the object has been closed
|
||||
*
|
||||
* Removes any name for the object. Note that this must be
|
||||
* called before drm_gem_object_free or we'll be touching
|
||||
* freed memory
|
||||
*/
|
||||
void
|
||||
drm_gem_object_handle_free (struct kref *kref)
|
||||
{
|
||||
struct drm_gem_object *obj = container_of (kref, struct drm_gem_object, handlecount);
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
/* Remove any name for this object */
|
||||
spin_lock (&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
idr_remove (&dev->object_name_idr, obj->name);
|
||||
spin_unlock (&dev->object_name_lock);
|
||||
/*
|
||||
* The object name held a reference to this object, drop
|
||||
* that now.
|
||||
*/
|
||||
drm_gem_object_unreference (obj);
|
||||
} else
|
||||
spin_unlock (&dev->object_name_lock);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_object_handle_free);
|
||||
|
|
|
|||
|
|
@ -105,8 +105,10 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
|
|||
|
||||
if (alignment == 0)
|
||||
alignment = PAGE_SIZE;
|
||||
if (alignment & (PAGE_SIZE - 1))
|
||||
if (alignment & (PAGE_SIZE - 1)) {
|
||||
DRM_ERROR("Invalid object alignment requested %u\n", alignment);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
free_space = drm_memrange_search_free(&dev_priv->mm.gtt_space,
|
||||
obj->size,
|
||||
|
|
|
|||
|
|
@ -983,16 +983,6 @@ struct drm_gem_unreference {
|
|||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct drm_gem_link {
|
||||
/** Handle for the object being given a name. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/** Requested file name to export the object under. */
|
||||
uint64_t name_ptr; /* char *, but pointers are not 32/64 compatible */
|
||||
/** Requested file mode to export the object under. */
|
||||
mode_t mode;
|
||||
};
|
||||
|
||||
struct drm_gem_pread {
|
||||
/** Handle for the object being read. */
|
||||
uint32_t handle;
|
||||
|
|
@ -1033,6 +1023,25 @@ struct drm_gem_mmap {
|
|||
uint64_t addr_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
};
|
||||
|
||||
struct drm_gem_name {
|
||||
/** Handle for the object being named */
|
||||
uint32_t handle;
|
||||
|
||||
/** Returned global name */
|
||||
uint32_t name;
|
||||
};
|
||||
|
||||
struct drm_gem_open {
|
||||
/** Name of object being opened */
|
||||
uint32_t name;
|
||||
|
||||
/** Returned handle for the object */
|
||||
uint32_t handle;
|
||||
|
||||
/** Returned size of the object */
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* \name Ioctls Definitions
|
||||
*/
|
||||
|
|
@ -1058,6 +1067,8 @@ struct drm_gem_mmap {
|
|||
#define DRM_IOCTL_GEM_PREAD DRM_IOW(0x0b, struct drm_gem_pread)
|
||||
#define DRM_IOCTL_GEM_PWRITE DRM_IOW(0x0c, struct drm_gem_pwrite)
|
||||
#define DRM_IOCTL_GEM_MMAP DRM_IOWR(0x0d, struct drm_gem_mmap)
|
||||
#define DRM_IOCTL_GEM_NAME DRM_IOWR(0x0e, struct drm_gem_name)
|
||||
#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0f, struct drm_gem_open)
|
||||
|
||||
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
|
||||
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue