drm: provide device-refcount
Lets not trick ourselves into thinking "drm_device" objects are not ref-counted. That's just utterly stupid. We manage "drm_minor" objects on each drm-device and each minor can have an unlimited number of open handles. Each of these handles has the drm_minor (and thus the drm_device) as private-data in the file-handle. Therefore, we may not destroy "drm_device" until all these handles are closed. It is *not* possible to reset all these pointers atomically and restrict access to them, and this is *not* how this is done! Instead, we use ref-counts to make sure the object is valid and not freed. Note that we currently use "dev->open_count" for that, which is *exactly* the same as a reference-count, just open coded. So this patch doesn't change any semantics on DRM devices (well, this patch just introduces the ref-count, anyway. Follow-up patches will replace open_count by it). Also note that generic VFS revoke support could allow us to drop this ref-count again. We could then just synchronously disable any fops->xy() calls. However, this is not the case, yet, and no such patches are in sight (and I seriously question the idea of dropping the ref-cnt again). Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
Родитель
cb8a239b03
Коммит
099d1c290e
|
@ -351,7 +351,7 @@ err_agp:
|
|||
drm_pci_agp_destroy(dev);
|
||||
pci_disable_device(pdev);
|
||||
err_free:
|
||||
drm_dev_free(dev);
|
||||
drm_dev_unref(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_pci_dev);
|
||||
|
|
|
@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev,
|
|||
return 0;
|
||||
|
||||
err_free:
|
||||
drm_dev_free(dev);
|
||||
drm_dev_unref(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ void drm_put_dev(struct drm_device *dev)
|
|||
}
|
||||
|
||||
drm_dev_unregister(dev);
|
||||
drm_dev_free(dev);
|
||||
drm_dev_unref(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_put_dev);
|
||||
|
||||
|
@ -425,6 +425,9 @@ EXPORT_SYMBOL(drm_unplug_dev);
|
|||
* Call drm_dev_register() to advertice the device to user space and register it
|
||||
* with other core subsystems.
|
||||
*
|
||||
* The initial ref-count of the object is 1. Use drm_dev_ref() and
|
||||
* drm_dev_unref() to take and drop further ref-counts.
|
||||
*
|
||||
* RETURNS:
|
||||
* Pointer to new DRM device, or NULL if out of memory.
|
||||
*/
|
||||
|
@ -438,6 +441,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
|
|||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
kref_init(&dev->ref);
|
||||
dev->dev = parent;
|
||||
dev->driver = driver;
|
||||
|
||||
|
@ -481,18 +485,10 @@ err_free:
|
|||
}
|
||||
EXPORT_SYMBOL(drm_dev_alloc);
|
||||
|
||||
/**
|
||||
* drm_dev_free - Free DRM device
|
||||
* @dev: DRM device to free
|
||||
*
|
||||
* Free a DRM device that has previously been allocated via drm_dev_alloc().
|
||||
* You must not use kfree() instead or you will leak memory.
|
||||
*
|
||||
* This must not be called once the device got registered. Use drm_put_dev()
|
||||
* instead, which then calls drm_dev_free().
|
||||
*/
|
||||
void drm_dev_free(struct drm_device *dev)
|
||||
static void drm_dev_release(struct kref *ref)
|
||||
{
|
||||
struct drm_device *dev = container_of(ref, struct drm_device, ref);
|
||||
|
||||
drm_put_minor(dev->control);
|
||||
drm_put_minor(dev->render);
|
||||
drm_put_minor(dev->primary);
|
||||
|
@ -506,7 +502,39 @@ void drm_dev_free(struct drm_device *dev)
|
|||
kfree(dev->devname);
|
||||
kfree(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_free);
|
||||
|
||||
/**
|
||||
* drm_dev_ref - Take reference of a DRM device
|
||||
* @dev: device to take reference of or NULL
|
||||
*
|
||||
* This increases the ref-count of @dev by one. You *must* already own a
|
||||
* reference when calling this. Use drm_dev_unref() to drop this reference
|
||||
* again.
|
||||
*
|
||||
* This function never fails. However, this function does not provide *any*
|
||||
* guarantee whether the device is alive or running. It only provides a
|
||||
* reference to the object and the memory associated with it.
|
||||
*/
|
||||
void drm_dev_ref(struct drm_device *dev)
|
||||
{
|
||||
if (dev)
|
||||
kref_get(&dev->ref);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_ref);
|
||||
|
||||
/**
|
||||
* drm_dev_unref - Drop reference of a DRM device
|
||||
* @dev: device to drop reference of or NULL
|
||||
*
|
||||
* This decreases the ref-count of @dev by one. The device is destroyed if the
|
||||
* ref-count drops to zero.
|
||||
*/
|
||||
void drm_dev_unref(struct drm_device *dev)
|
||||
{
|
||||
if (dev)
|
||||
kref_put(&dev->ref, drm_dev_release);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dev_unref);
|
||||
|
||||
/**
|
||||
* drm_dev_register - Register DRM device
|
||||
|
@ -581,7 +609,7 @@ EXPORT_SYMBOL(drm_dev_register);
|
|||
*
|
||||
* Unregister the DRM device from the system. This does the reverse of
|
||||
* drm_dev_register() but does not deallocate the device. The caller must call
|
||||
* drm_dev_free() to free all resources.
|
||||
* drm_dev_unref() to drop their final reference.
|
||||
*/
|
||||
void drm_dev_unregister(struct drm_device *dev)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ int drm_get_usb_dev(struct usb_interface *interface,
|
|||
return 0;
|
||||
|
||||
err_free:
|
||||
drm_dev_free(dev);
|
||||
drm_dev_unref(dev);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
|
|||
return 0;
|
||||
|
||||
err_free:
|
||||
drm_dev_free(drm);
|
||||
drm_dev_unref(drm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <asm/current.h>
|
||||
#endif /* __alpha__ */
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -1102,6 +1103,7 @@ struct drm_device {
|
|||
|
||||
/** \name Lifetime Management */
|
||||
/*@{ */
|
||||
struct kref ref; /**< Object ref-count */
|
||||
struct device *dev; /**< Device structure of bus-device */
|
||||
struct drm_driver *driver; /**< DRM driver managing the device */
|
||||
void *dev_private; /**< DRM driver private data */
|
||||
|
@ -1666,7 +1668,8 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map)
|
|||
|
||||
struct drm_device *drm_dev_alloc(struct drm_driver *driver,
|
||||
struct device *parent);
|
||||
void drm_dev_free(struct drm_device *dev);
|
||||
void drm_dev_ref(struct drm_device *dev);
|
||||
void drm_dev_unref(struct drm_device *dev);
|
||||
int drm_dev_register(struct drm_device *dev, unsigned long flags);
|
||||
void drm_dev_unregister(struct drm_device *dev);
|
||||
/*@}*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче