kern/123288: Infinite loop in kernel on removal of USB serial
adapter syslogd writes to
Arthur Hartwig
arthur.hartwig at nokia.com
Thu May 1 08:10:01 UTC 2008
>Number: 123288
>Category: kern
>Synopsis: Infinite loop in kernel on removal of USB serial adapter syslogd writes to
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Thu May 01 08:10:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator: Arthur Hartwig
>Release: 6.3
>Organization:
Nokia
>Environment:
>Description:
In devfs_allocv() in fs/devfs/devfs_vnops.c if vget() returns ENOENT the code loops calling vget() the going to label loop the calling vget() then going to label loop etc etc.
>How-To-Repeat:
Insert USB serial adapter in system, run getty on the created ttyU<x> device, login as root so syslogd uses /dev/ttyU<x> for syslog output. After verifying syslogd is using /dev/ttyU<x> as output device remove USB serial adapter.
It may not be necessary to login on the ttyU<x> device if there is another way to get syslogd to use it as an output device.
A quick glance at the source code suggests the same problem exists in FreeBSD 7.0.
>Fix:
If vget() returns ENOENT give up rather than looping indefinitely hoping vget() will eventually return 0.
Suggested code patch for FreeBSD 6.3: In devfs_allocv() change
loop:
DEVFS_DE_HOLD(de);
DEVFS_DMP_HOLD(dmp);
mtx_lock(&devfs_de_interlock);
vp = de->de_vnode;
if (vp != NULL) {
VI_LOCK(vp);
mtx_unlock(&devfs_de_interlock);
sx_xunlock(&dmp->dm_lock);
error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td);
sx_xlock(&dmp->dm_lock);
if (devfs_allocv_drop_refs(0, dmp, de)) {
if (error == 0)
vput(vp);
return (ENOENT);
}
else if (error)
goto loop;
sx_xunlock(&dmp->dm_lock);
to
loop:
DEVFS_DE_HOLD(de);
DEVFS_DMP_HOLD(dmp);
mtx_lock(&devfs_de_interlock);
vp = de->de_vnode;
if (vp != NULL) {
VI_LOCK(vp);
mtx_unlock(&devfs_de_interlock);
sx_xunlock(&dmp->dm_lock);
error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td);
sx_xlock(&dmp->dm_lock);
if (devfs_allocv_drop_refs(0, dmp, de)) {
if (error == 0)
vput(vp);
return (ENOENT);
}
else if (error == ENOENT) {
sx_xunlock(&dmp->dm_lock);
return (ENOENT);
}
else if (error)
goto loop;
sx_xunlock(&dmp->dm_lock);
I observed this problem on a SMP kernel running on a single CPU system. Its possible the problem might not occur on a MP system in that the locks and unlocks in the loop might give another thread an opportunity to do something (e.g. garbage collect) that causes vget() to return 0 in reasonable time. I have not explored this possibility.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list