Author: markj
Date: Wed Apr 19 16:12:02 2017
New Revision: 317148
URL: https://svnweb.freebsd.org/changeset/base/317148

Log:
  Drop Giant before sleeping in linux_wait_for_{timeout_,}common().
  
  Reported and tested by:       Pete Wright <p...@nomadlogic.org>
  Reviewed by:  hselasky (previous version)
  MFC after:    2 weeks
  Differential Revision:        https://reviews.freebsd.org/D10414

Modified:
  head/sys/compat/linuxkpi/common/src/linux_compat.c

Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_compat.c  Wed Apr 19 15:59:16 
2017        (r317147)
+++ head/sys/compat/linuxkpi/common/src/linux_compat.c  Wed Apr 19 16:12:02 
2017        (r317148)
@@ -1321,28 +1321,38 @@ linux_complete_common(struct completion 
 long
 linux_wait_for_common(struct completion *c, int flags)
 {
+       long error;
+
        if (SCHEDULER_STOPPED())
                return (0);
 
+       DROP_GIANT();
+
        if (flags != 0)
                flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
        else
                flags = SLEEPQ_SLEEP;
+       error = 0;
        for (;;) {
                sleepq_lock(c);
                if (c->done)
                        break;
                sleepq_add(c, NULL, "completion", flags, 0);
                if (flags & SLEEPQ_INTERRUPTIBLE) {
-                       if (sleepq_wait_sig(c, 0) != 0)
-                               return (-ERESTARTSYS);
+                       if (sleepq_wait_sig(c, 0) != 0) {
+                               error = -ERESTARTSYS;
+                               goto intr;
+                       }
                } else
                        sleepq_wait(c, 0);
        }
        c->done--;
        sleepq_release(c);
 
-       return (0);
+intr:
+       PICKUP_GIANT();
+
+       return (error);
 }
 
 /*
@@ -1351,18 +1361,22 @@ linux_wait_for_common(struct completion 
 long
 linux_wait_for_timeout_common(struct completion *c, long timeout, int flags)
 {
-       long end = jiffies + timeout;
+       long end = jiffies + timeout, error;
+       int ret;
 
        if (SCHEDULER_STOPPED())
                return (0);
 
+       DROP_GIANT();
+
        if (flags != 0)
                flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
        else
                flags = SLEEPQ_SLEEP;
-       for (;;) {
-               int ret;
 
+       error = 0;
+       ret = 0;
+       for (;;) {
                sleepq_lock(c);
                if (c->done)
                        break;
@@ -1375,16 +1389,20 @@ linux_wait_for_timeout_common(struct com
                if (ret != 0) {
                        /* check for timeout or signal */
                        if (ret == EWOULDBLOCK)
-                               return (0);
+                               error = 0;
                        else
-                               return (-ERESTARTSYS);
+                               error = -ERESTARTSYS;
+                       goto intr;
                }
        }
        c->done--;
        sleepq_release(c);
 
+intr:
+       PICKUP_GIANT();
+
        /* return how many jiffies are left */
-       return (linux_timer_jiffies_until(end));
+       return (ret != 0 ? error : linux_timer_jiffies_until(end));
 }
 
 int
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to