Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 1 May 2008 07:59:24 GMT
From:      Arthur Hartwig <arthur.hartwig@nokia.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/123288: Infinite loop in kernel on removal of USB serial adapter syslogd writes to
Message-ID:  <200805010759.m417xOCE051025@www.freebsd.org>
Resent-Message-ID: <200805010810.m418A1uE090243@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200805010759.m417xOCE051025>