From 65dd0e68ff0e0e354925adb7d5fffeb0ffbb485c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 11 Apr 2008 09:36:12 +0200 Subject: Fix up buffer manager locking. --- linux-core/drm_bo_lock.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'linux-core/drm_bo_lock.c') diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index 2795384e..32ebfbe2 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -49,7 +49,7 @@ * unmappable regions to mappable. It's a bug to leave kernel space with the * read lock held. * - * Both read- and write lock taking is interruptible for low signal-delivery + * Both read- and write lock taking may be interruptible for low signal-delivery * latency. The locking functions will return -EAGAIN if interrupted by a * signal. * @@ -71,14 +71,20 @@ void drm_bo_read_unlock(struct drm_bo_lock *lock) if (unlikely(atomic_add_negative(-1, &lock->readers))) BUG(); if (atomic_read(&lock->readers) == 0) - wake_up_interruptible(&lock->queue); + wake_up_all(&lock->queue); } EXPORT_SYMBOL(drm_bo_read_unlock); -int drm_bo_read_lock(struct drm_bo_lock *lock) +int drm_bo_read_lock(struct drm_bo_lock *lock, int interruptible) { while (unlikely(atomic_read(&lock->write_lock_pending) != 0)) { int ret; + + if (!interruptible) { + wait_event(lock->queue, + atomic_read(&lock->write_lock_pending) == 0); + continue; + } ret = wait_event_interruptible (lock->queue, atomic_read(&lock->write_lock_pending) == 0); if (ret) @@ -87,8 +93,14 @@ int drm_bo_read_lock(struct drm_bo_lock *lock) while (unlikely(!atomic_add_unless(&lock->readers, 1, -1))) { int ret; + + if (!interruptible) { + wait_event(lock->queue, + atomic_read(&lock->readers) != -1); + continue; + } ret = wait_event_interruptible - (lock->queue, atomic_add_unless(&lock->readers, 1, -1)); + (lock->queue, atomic_read(&lock->readers) != -1); if (ret) return -EAGAIN; } @@ -100,9 +112,7 @@ static int __drm_bo_write_unlock(struct drm_bo_lock *lock) { if (unlikely(atomic_cmpxchg(&lock->readers, -1, 0) != -1)) return -EINVAL; - if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 1, 0) != 1)) - return -EINVAL; - wake_up_interruptible(&lock->queue); + wake_up_all(&lock->queue); return 0; } @@ -116,21 +126,26 @@ static void drm_bo_write_lock_remove(struct drm_file *file_priv, BUG_ON(ret); } -int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) +int drm_bo_write_lock(struct drm_bo_lock *lock, int interruptible, + struct drm_file *file_priv) { int ret = 0; struct drm_device *dev; - if (unlikely(atomic_cmpxchg(&lock->write_lock_pending, 0, 1) != 0)) - return -EINVAL; + atomic_inc(&lock->write_lock_pending); while (unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) { + if (!interruptible) { + wait_event(lock->queue, + atomic_read(&lock->readers) == 0); + continue; + } ret = wait_event_interruptible - (lock->queue, atomic_cmpxchg(&lock->readers, 0, -1) == 0); + (lock->queue, atomic_read(&lock->readers) == 0); if (ret) { - atomic_set(&lock->write_lock_pending, 0); - wake_up_interruptible(&lock->queue); + atomic_dec(&lock->write_lock_pending); + wake_up_all(&lock->queue); return -EAGAIN; } } @@ -141,6 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) * while holding it. */ + atomic_dec(&lock->write_lock_pending); dev = file_priv->minor->dev; mutex_lock(&dev->struct_mutex); ret = drm_add_user_object(file_priv, &lock->base, 0); -- cgit v1.2.3 From c5955c652302d66719984cb5a218cb590c74ad42 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 14 Apr 2008 12:10:50 +0200 Subject: Fix buffer object creation validation. BO lock fixes. --- linux-core/drm_bo_lock.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_bo_lock.c') diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index 32ebfbe2..08b1c6be 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -68,9 +68,7 @@ void drm_bo_init_lock(struct drm_bo_lock *lock) void drm_bo_read_unlock(struct drm_bo_lock *lock) { - if (unlikely(atomic_add_negative(-1, &lock->readers))) - BUG(); - if (atomic_read(&lock->readers) == 0) + if (atomic_dec_and_test(&lock->readers)) wake_up_all(&lock->queue); } EXPORT_SYMBOL(drm_bo_read_unlock); @@ -79,7 +77,7 @@ int drm_bo_read_lock(struct drm_bo_lock *lock, int interruptible) { while (unlikely(atomic_read(&lock->write_lock_pending) != 0)) { int ret; - + if (!interruptible) { wait_event(lock->queue, atomic_read(&lock->write_lock_pending) == 0); @@ -93,7 +91,6 @@ int drm_bo_read_lock(struct drm_bo_lock *lock, int interruptible) while (unlikely(!atomic_add_unless(&lock->readers, 1, -1))) { int ret; - if (!interruptible) { wait_event(lock->queue, atomic_read(&lock->readers) != -1); @@ -156,7 +153,8 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, int interruptible, * while holding it. */ - atomic_dec(&lock->write_lock_pending); + if (atomic_dec_and_test(&lock->write_lock_pending)) + wake_up_all(&lock->queue); dev = file_priv->minor->dev; mutex_lock(&dev->struct_mutex); ret = drm_add_user_object(file_priv, &lock->base, 0); -- cgit v1.2.3