summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-12-12 12:06:28 +0000
committerkib <kib@FreeBSD.org>2008-12-12 12:06:28 +0000
commit2ef4ea7ee81ea8c88c6424914105f12ff9b04a48 (patch)
tree13149bbd776ba4e1b4d0616e35c4078de60e92aa
parent9aa6bcff62ea1bb898209f15836407394f2fffcf (diff)
downloadFreeBSD-src-2ef4ea7ee81ea8c88c6424914105f12ff9b04a48.zip
FreeBSD-src-2ef4ea7ee81ea8c88c6424914105f12ff9b04a48.tar.gz
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
-rw-r--r--sys/kern/kern_prot.c2
-rw-r--r--sys/kern/kern_sysctl.c10
2 files changed, 9 insertions, 3 deletions
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 348acdf..3089638 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 5d79ca2..3e9878e 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -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 *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);
OpenPOWER on IntegriCloud