diff options
Diffstat (limited to 'linux/lock.c')
-rw-r--r-- | linux/lock.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/linux/lock.c b/linux/lock.c index 55082727..e5fd435f 100644 --- a/linux/lock.c +++ b/linux/lock.c @@ -218,8 +218,41 @@ int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd, DRM_DEBUG("\n"); - copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); drm_flush_unblock(dev, lock.context, lock.flags); return ret; } + +/* If we get here, it means that the process has called DRM_IOCTL_LOCK + without calling DRM_IOCTL_UNLOCK. + + If the lock is not held, then let the signal proceed as usual. + + If the lock is held, then set the contended flag and keep the signal + blocked. + + + Return 1 if the signal should be delivered normally. + Return 0 if the signal should be blocked. */ + +int drm_notifier(void *priv) +{ + drm_sigdata_t *s = (drm_sigdata_t *)priv; + unsigned int old, new, prev; + + + /* Allow signal delivery if lock isn't held */ + if (!_DRM_LOCK_IS_HELD(s->lock->lock) + || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; + + /* Otherwise, set flag to force call to + drmUnlock */ + do { + old = s->lock->lock; + new = old | _DRM_LOCK_CONT; + prev = cmpxchg(&s->lock->lock, old, new); + } while (prev != old); + return 0; +} |