Hi people,
At work, one of our SpamAssassin/ClamAV filtering machines just entered
a deadlock state:
FreeBSD/i386 (xxx.qsp.nl) (cuad0)
login: root
load: 0.00  cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k
load: 0.00  cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k
load: 0.00  cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k
load: 0.00  cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k
load: 0.00  cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k
After inspection, I believe the following code in
kern/kern_sysctl.c:userland_sysctl() is the culprit:
        SYSCTL_LOCK();
        do {
                req.oldidx = 0;
                req.newidx = 0;
                error = sysctl_root(0, name, namelen, &req);
        } while (error == EAGAIN);
        if (req.lock == REQ_WIRED && req.validlen > 0)
                vsunlock(req.oldptr, req.validlen);
        SYSCTL_UNLOCK();
Clearly, should sysctl_root() always return EAGAIN, this will cause a
serious deadlock condition. It appears this is possible.
The only plausible reference to sysctl's returning EGAIN seems to be in 
kern/kern_proc.c:sysctl_out_proc(). However, this code returns ESRCH
if the process couldn't have been found in the fast place, and since the
complete handler function will be called by sysctl_root() every
iteration, and thus will do a pfind() and return ESRCH if it failed and
not EAGAIN as it will later on in the code path.
The machine is a 6.0-STABLE SMP machine of 30-Mar-2006. No debugging
options are in the kernel as the machine has quite some load. The only
console messages were a lot of 'calcru' messages.
Any help is very much appreciated. For now, I'd like to propose a change
to kern/kern_sysctl.c:userland_sysctl(), to ensure this will never keep
looping on EAGAIN states (preferably, it should trigger a panic or at
least a KASSERT should such a condition occour). I know this is a
bandaid for a problem we don't really quite understand yet, but this may
ease debugging later on (especially as it will help us understand where
exactly it is going bad)
Any comments? It looks to me this deadlock is quite rare (in fact, I've
never seen it before), but I believe it is serious enough to be
addressed, even with such a bandaid until the real solution is presented
by someone who knows the sysctl internals better than I do.
Thanks,
-- 
Rink P.W. Springer                                - http://rink.nu
"It is such a quiet thing, to fall. But yet a far more terrible thing,
 to admit it."                                    - Darth Traya
Rink Springer wrote:> Hi people, > > At work, one of our SpamAssassin/ClamAV filtering machines just entered > a deadlock state: > > FreeBSD/i386 (xxx.qsp.nl) (cuad0) > > login: root > load: 0.00 cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k > load: 0.00 cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k > load: 0.00 cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k > load: 0.00 cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k > load: 0.00 cmd: login 683 [sysctl lock] 0.00u 0.00s 0% 148k > > After inspection, I believe the following code in > kern/kern_sysctl.c:userland_sysctl() is the culprit: > > SYSCTL_LOCK(); > > do { > req.oldidx = 0; > req.newidx = 0; > error = sysctl_root(0, name, namelen, &req); > } while (error == EAGAIN); > > if (req.lock == REQ_WIRED && req.validlen > 0) > vsunlock(req.oldptr, req.validlen); > > SYSCTL_UNLOCK(); > > Clearly, should sysctl_root() always return EAGAIN, this will cause a > serious deadlock condition. It appears this is possible. > > The only plausible reference to sysctl's returning EGAIN seems to be in > kern/kern_proc.c:sysctl_out_proc(). However, this code returns ESRCH > if the process couldn't have been found in the fast place, and since the > complete handler function will be called by sysctl_root() every > iteration, and thus will do a pfind() and return ESRCH if it failed and > not EAGAIN as it will later on in the code path. > > The machine is a 6.0-STABLE SMP machine of 30-Mar-2006. No debugging > options are in the kernel as the machine has quite some load. The only > console messages were a lot of 'calcru' messages. > > Any help is very much appreciated. For now, I'd like to propose a change > to kern/kern_sysctl.c:userland_sysctl(), to ensure this will never keep > looping on EAGAIN states (preferably, it should trigger a panic or at > least a KASSERT should such a condition occour). I know this is a > bandaid for a problem we don't really quite understand yet, but this may > ease debugging later on (especially as it will help us understand where > exactly it is going bad) > > Any comments? It looks to me this deadlock is quite rare (in fact, I've > never seen it before), but I believe it is serious enough to be > addressed, even with such a bandaid until the real solution is presented > by someone who knows the sysctl internals better than I do. > >Interesting. Twice I have had a 6.2 system stuck where sendmail was holding the sysctl lock while another process was holding the proctree and/or allproc lock, if I remember correctly. Guy