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>