drm_read() to paged-out memory area
Chris Wilson
chris at chris-wilson.co.uk
Tue Nov 24 14:14:20 PST 2015
On Tue, Nov 24, 2015 at 09:49:58PM +0100, Thomas Hellstrom wrote:
> Hi, Chris,
>
> With your new (well sort of) implementation of drm_read() it looks to me
> like a drm_read() to a paged out
> memory area will always fail with -EFAULT. From what I can tell, there's
> nothing there to generate a page-fault to get the destination paged back
> into memory?
True. Whoops.
If we take the first event (remove it from the list from a second reader
cannot see it), fail to copy it and replace it at the head, the second
reader may then get an out-of-order event.
First we need something like:
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index c59ce4d0ef75..b9ca549e0e99 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -509,14 +509,21 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
ret = 0;
} else {
struct drm_pending_event *e;
+ int unwritten;
e = list_first_entry(&file_priv->event_list,
struct drm_pending_event, link);
if (e->event->length + ret > count)
break;
- if (__copy_to_user_inatomic(buffer + ret,
- e->event, e->event->length)) {
+ list_del(&e->link);
+
+ spin_unlock_irq(&dev->event_lock);
+ unwritten = copy_to_user(buffer + ret,
+ e->event, e->event->length);
+ spin_lock_irq(&dev->event_lock);
+ if (unwritten) {
+ list_add(&e->link, &file_priv->event_list);
if (ret == 0)
ret = -EFAULT;
break;
@@ -524,7 +531,6 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
file_priv->event_space += e->event->length;
ret += e->event->length;
- list_del(&e->link);
e->destroy(e);
}
}
A task for tomorrow (along with a suitable testcase).
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
More information about the dri-devel
mailing list