From af80b2c90182cbbc0580d237bf3049090d511897 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Fri, 12 Dec 2008 12:06:28 +0000 Subject: [PATCH] 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 --- sys/kern/kern_prot.c | 2 +- sys/kern/kern_sysctl.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 348acdf131a..30896385ee9 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1679,7 +1679,7 @@ p_candebug(struct thread *td, struct proc *p) * should be moved to the caller's of p_candebug(). */ if ((p->p_flag & P_INEXEC) != 0) - return (EAGAIN); + return (EBUSY); return (0); } diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 5d79ca2e8e7..3e9878e2a24 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -1416,11 +1417,16 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, 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);