Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2/drm Serialize drm_read so we can back ...



details:   https://anonhg.NetBSD.org/src/rev/c5087fa144c1
branches:  trunk
changeset: 1027855:c5087fa144c1
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Sun Dec 19 00:58:11 2021 +0000

description:
Serialize drm_read so we can back out on uiomove without reordering.

Upstream commit 9b2c0b7fb4ce79566d830d03ce7aa11cccc39f97.

diffstat:

 sys/external/bsd/drm2/drm/drm_cdevsw.c |  88 ++++++++++++++++++++++++++++-----
 1 files changed, 74 insertions(+), 14 deletions(-)

diffs (133 lines):

diff -r 18f5db9ae60b -r c5087fa144c1 sys/external/bsd/drm2/drm/drm_cdevsw.c
--- a/sys/external/bsd/drm2/drm/drm_cdevsw.c    Sun Dec 19 00:58:04 2021 +0000
+++ b/sys/external/bsd/drm2/drm/drm_cdevsw.c    Sun Dec 19 00:58:11 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: drm_cdevsw.c,v 1.19 2021/12/19 00:48:45 riastradh Exp $        */
+/*     $NetBSD: drm_cdevsw.c,v 1.20 2021/12/19 00:58:11 riastradh Exp $        */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_cdevsw.c,v 1.19 2021/12/19 00:48:45 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_cdevsw.c,v 1.20 2021/12/19 00:58:11 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -274,35 +274,82 @@
     int flags)
 {
        struct drm_file *const file = fp->f_data;
+       struct drm_device *const dev = file->minor->dev;
        struct drm_pending_event *event;
        bool first;
-       int error = 0;
+       int ret = 0;
+
+       /*
+        * Only one event reader at a time, so that if copyout faults
+        * after dequeueing one event and we have to put the event
+        * back, another reader won't see out-of-order events.
+        */
+       spin_lock(&dev->event_lock);
+       DRM_SPIN_WAIT_NOINTR_UNTIL(ret, &file->event_read_wq, &dev->event_lock,
+           file->event_read_lock == NULL);
+       if (ret) {
+               spin_unlock(&dev->event_lock);
+               /* XXX errno Linux->NetBSD */
+               return -ret;
+       }
+       file->event_read_lock = curlwp;
+       spin_unlock(&dev->event_lock);
 
        for (first = true; ; first = false) {
                int f = 0;
+               off_t offset;
+               size_t resid;
 
                if (!first || ISSET(fp->f_flag, FNONBLOCK))
                        f |= FNONBLOCK;
 
-               /* XXX errno Linux->NetBSD */
-               error = -drm_dequeue_event(file, uio->uio_resid, &event, f);
-               if (error) {
-                       if ((error == EWOULDBLOCK) && !first)
-                               error = 0;
+               ret = drm_dequeue_event(file, uio->uio_resid, &event, f);
+               if (ret) {
+                       if ((ret == -EWOULDBLOCK) && !first)
+                               ret = 0;
                        break;
                }
                if (event == NULL)
                        break;
-               error = uiomove(event->event, event->event->length, uio);
-               if (error)      /* XXX Requeue the event?  */
+
+               offset = uio->uio_offset;
+               resid = uio->uio_resid;
+               /* XXX errno NetBSD->Linux */
+               ret = -uiomove(event->event, event->event->length, uio);
+               if (ret) {
+                       /*
+                        * Faulted on copyout.  Put the event back and
+                        * stop here.
+                        */
+                       if (!first) {
+                               /*
+                                * Already transferred some events.
+                                * Rather than back them all out, just
+                                * say we succeeded at returning those.
+                                */
+                               ret = 0;
+                       }
+                       uio->uio_offset = offset;
+                       uio->uio_resid = resid;
+                       drm_requeue_event(file, event);
                        break;
-               (*event->destroy)(event);
+               }
+               kfree(event);
        }
 
+       /* Release the event read lock.  */
+       spin_lock(&dev->event_lock);
+       KASSERT(file->event_read_lock == curlwp);
+       file->event_read_lock = NULL;
+       DRM_SPIN_WAKEUP_ONE(&file->event_read_wq, &dev->event_lock);
+       spin_unlock(&dev->event_lock);
+
+       /* XXX errno Linux->NetBSD */
+
        /* Success!  */
-       if (error == ERESTARTSYS)
-               error = ERESTART;
-       return error;
+       if (ret == ERESTARTSYS)
+               ret = ERESTART;
+       return -ret;
 }
 
 static int
@@ -343,6 +390,19 @@
        return ret;
 }
 
+static void
+drm_requeue_event(struct drm_file *file, struct drm_pending_event *event)
+{
+       struct drm_device *const dev = file->minor->dev;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev->event_lock, irqflags);
+       list_add(&event->link, &file->event_list);
+       KASSERT(file->event_space >= event->event->length);
+       file->event_space -= event->event->length;
+       spin_unlock_irqrestore(&dev->event_lock, irqflags);
+}
+
 static int
 drm_ioctl_shim(struct file *fp, unsigned long cmd, void *data)
 {



Home | Main Index | Thread Index | Old Index