From a3c890edbec5d4ee27e91dfca81d6872a4c06e84 Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Thu, 24 Feb 2011 14:12:44 -0500 Subject: [PATCH] Fix crash when dropping filesystem caches (#649871) --- ...n-dropping-the-last-gem-reference-v2.patch | 107 ++++++++++++++++++ kernel.spec | 9 ++ 2 files changed, 116 insertions(+) create mode 100644 drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch diff --git a/drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch b/drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch new file mode 100644 index 000000000..6b137dfcb --- /dev/null +++ b/drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch @@ -0,0 +1,107 @@ +From 39b4d07aa3583ceefe73622841303a0a3e942ca1 Mon Sep 17 00:00:00 2001 +From: Chris Wilson +Date: Thu, 30 Sep 2010 09:10:26 +0100 +Subject: drm: Hold the mutex when dropping the last GEM reference (v2) + +From: Chris Wilson + +commit 39b4d07aa3583ceefe73622841303a0a3e942ca1 upstream. + +In order to be fully threadsafe we need to check that the drm_gem_object +refcount is still 0 after acquiring the mutex in order to call the free +function. Otherwise, we may encounter scenarios like: + +Thread A: Thread B: +drm_gem_close +unreference_unlocked +kref_put mutex_lock +... i915_gem_evict +... kref_get -> BUG +... i915_gem_unbind +... kref_put +... i915_gem_object_free +... mutex_unlock +mutex_lock +i915_gem_object_free -> BUG +i915_gem_object_unbind +kfree +mutex_unlock + +Note that no driver is currently using the free_unlocked vfunc and it is +scheduled for removal, hasten that process. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30454 +Reported-and-Tested-by: Magnus Kessler +Signed-off-by: Chris Wilson +Signed-off-by: Dave Airlie +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/drm_gem.c | 22 ---------------------- + include/drm/drmP.h | 10 ++++++---- + 2 files changed, 6 insertions(+), 26 deletions(-) + +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -451,28 +451,6 @@ drm_gem_object_free(struct kref *kref) + } + EXPORT_SYMBOL(drm_gem_object_free); + +-/** +- * Called after the last reference to the object has been lost. +- * Must be called without holding struct_mutex +- * +- * Frees the object +- */ +-void +-drm_gem_object_free_unlocked(struct kref *kref) +-{ +- struct drm_gem_object *obj = (struct drm_gem_object *) kref; +- struct drm_device *dev = obj->dev; +- +- if (dev->driver->gem_free_object_unlocked != NULL) +- dev->driver->gem_free_object_unlocked(obj); +- else if (dev->driver->gem_free_object != NULL) { +- mutex_lock(&dev->struct_mutex); +- dev->driver->gem_free_object(obj); +- mutex_unlock(&dev->struct_mutex); +- } +-} +-EXPORT_SYMBOL(drm_gem_object_free_unlocked); +- + static void drm_gem_object_ref_bug(struct kref *list_kref) + { + BUG(); +--- a/include/drm/drmP.h ++++ b/include/drm/drmP.h +@@ -802,7 +802,6 @@ struct drm_driver { + */ + int (*gem_init_object) (struct drm_gem_object *obj); + void (*gem_free_object) (struct drm_gem_object *obj); +- void (*gem_free_object_unlocked) (struct drm_gem_object *obj); + + /* vga arb irq handler */ + void (*vgaarb_irq)(struct drm_device *dev, bool state); +@@ -1430,7 +1429,6 @@ int drm_gem_init(struct drm_device *dev) + void drm_gem_destroy(struct drm_device *dev); + void drm_gem_object_release(struct drm_gem_object *obj); + void drm_gem_object_free(struct kref *kref); +-void drm_gem_object_free_unlocked(struct kref *kref); + struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, + size_t size); + int drm_gem_object_init(struct drm_device *dev, +@@ -1456,8 +1454,12 @@ drm_gem_object_unreference(struct drm_ge + static inline void + drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) + { +- if (obj != NULL) +- kref_put(&obj->refcount, drm_gem_object_free_unlocked); ++ if (obj != NULL) { ++ struct drm_device *dev = obj->dev; ++ mutex_lock(&dev->struct_mutex); ++ kref_put(&obj->refcount, drm_gem_object_free); ++ mutex_unlock(&dev->struct_mutex); ++ } + } + + int drm_gem_handle_create(struct drm_file *file_priv, diff --git a/kernel.spec b/kernel.spec index 5de4a12c6..2126fe9a4 100644 --- a/kernel.spec +++ b/kernel.spec @@ -890,6 +890,9 @@ Patch13950: sunrpc-kernel-panic-when-mount-nfsv4.patch # rhbz#650151 Patch13951: bridge-fix-mglist-corruption-that-leads-to-memory-corruption.patch +# rhbz#649871 +Patch13952: drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1692,6 +1695,9 @@ ApplyPatch sunrpc-kernel-panic-when-mount-nfsv4.patch # rhbz#650151 ApplyPatch bridge-fix-mglist-corruption-that-leads-to-memory-corruption.patch +# rhbz#649871 +ApplyPatch drm-hold-the-mutex-when-dropping-the-last-gem-reference-v2.patch + # END OF PATCH APPLICATIONS %endif @@ -2312,6 +2318,9 @@ fi %kernel_variant_files %{with_pae_debug} PAEdebug %changelog +* Thu Feb 24 2011 Chuck Ebbert +- Fix crash when dropping filesystem caches (#649871) + * Mon Feb 14 2011 Kyle McMartin 2.6.34.8-68 - Backport commits from longterm-2.6.35.y to 'fix' Intel Sandy Bridge chipsets. (Requested by Intel folks.)