Author: kib
Date: Fri Dec 12 12:06:28 2008
New Revision: 185983
URL: http://svn.freebsd.org/changeset/base/185983

Log:
  The userland_sysctl() function retries sysctl_root() until returned
  error is not EAGAIN. Several sysctls that inspect another process use
  p_candebug() for checking access right for the curproc. p_candebug()
  returns EAGAIN for some reasons, in particular, for the process doing
  exec() now. If execing process tries to lock Giant, we get a livelock,
  because sysctl handlers are covered by Giant, and often do not sleep.
  
  Break the livelock by dropping Giant and allowing other threads to
  execute in the EAGAIN loop.
  
  Also, do not return EAGAIN from p_candebug() when process is executing,
  use more appropriate EBUSY error [1].
  
  Reported and tested by:       pho
  Suggested by: rwatson [1]
  Reviewed by:  rwatson, des
  MFC after:    1 week

Modified:
  head/sys/kern/kern_prot.c
  head/sys/kern/kern_sysctl.c

Modified: head/sys/kern/kern_prot.c
==============================================================================
--- head/sys/kern/kern_prot.c   Fri Dec 12 11:58:27 2008        (r185982)
+++ head/sys/kern/kern_prot.c   Fri Dec 12 12:06:28 2008        (r185983)
@@ -1679,7 +1679,7 @@ p_candebug(struct thread *td, struct pro
         * should be moved to the caller's of p_candebug().
         */
        if ((p->p_flag & P_INEXEC) != 0)
-               return (EAGAIN);
+               return (EBUSY);
 
        return (0);
 }

Modified: head/sys/kern/kern_sysctl.c
==============================================================================
--- head/sys/kern/kern_sysctl.c Fri Dec 12 11:58:27 2008        (r185982)
+++ head/sys/kern/kern_sysctl.c Fri Dec 12 12:06:28 2008        (r185983)
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mutex.h>
 #include <sys/sx.h>
 #include <sys/sysproto.h>
+#include <sys/uio.h>
 #include <sys/vimage.h>
 
 #include <security/mac/mac_framework.h>
@@ -1416,11 +1417,16 @@ userland_sysctl(struct thread *td, int *
        SYSCTL_LOCK();
        CURVNET_SET(TD_TO_VNET(curthread));
 
-       do {
+       for (;;) {
                req.oldidx = 0;
                req.newidx = 0;
                error = sysctl_root(0, name, namelen, &req);
-       } while (error == EAGAIN);
+               if (error != EAGAIN)
+                       break;
+               DROP_GIANT();
+               uio_yield();
+               PICKUP_GIANT();
+       }
 
        if (req.lock == REQ_WIRED && req.validlen > 0)
                vsunlock(req.oldptr, req.validlen);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to