Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Apr 2000 04:30:11 -0700 (PDT)
From:      peter.edwards@ireland.com
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/18270: [PATCH] kldunload "vn" doesn't clean up enough, and causes panics.
Message-ID:  <200004281130.EAA21678@freefall.freebsd.org>

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

>Number:         18270
>Category:       kern
>Synopsis:       [PATCH] kldunload "vn" doesn't clean up enough, and causes panics.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Apr 28 04:40:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Peter Edwards
>Release:        4.0-STABLE/5.0-CURRENT
>Organization:
>Environment:
FreeBSD rocklobster 4.0-STABLE FreeBSD 4.0-STABLE #1: Thu Apr 27 09:32:28 IST 2000     petere@rocklobster:/usr/src/sys/compile/MAR27  i386

>Description:
Some reports on current@freebsd.org
indicated that after "kldunload"ing the vn device, further use of
/dev/vn* caused panics.

I saw a few problems, and attach a patch that addresses them
and appears to fix the crashes on my -stable box.

1: There is no cdesw_remove() when the module is unloaded.

2: Any dev_t's that make it to the driver get associated with a vn
softc. After the driver is unloaded and reloaded, these pointers
are still set in the dev_t's, but refer to the old, free()d softcs.

3: There are no calls to destroy_dev to match the calls to make_dev.


The included patch is complicated slightly because more than one dev_t
can be associated with a vn_softc, and for each softc, only one call to make_dev
is made. The patch keeps track of the "aliases" for the vn_softc by
chaining such aliases through the si_drv2 field in the dev_t.


I reproduced the problem on 4.0-STABLE, and after the patch, several
"kldunload vn.ko/vnconfig" operations leave my machine in one piece.
The problem probably exists in -current, and the patch applies cleanly
(modulo line offset changes) to the -current vn.c also

I'm not the most experienced FreeBSD Kernel Hacker, so a solid review
and comments would be appreciated. I really think there is some ugliness
in the way the vn device sets up the softc's and devices. It should
probably do a make_dev for each different dev_t that refers to a unit
when the unit is first opened, and probably also a make_dev() for a
configurable number of vn's at load time, to get them to appear under
devfs. If someone can confirm that this is an accurate analysis, I'll
spend some time fixing it up, if no one else has time.
>How-To-Repeat:

>Fix:
I've attached the patch as compressed uuencoded, as well as plaintext,
to get around cut-n-paste whitespace corruption.


*** vn.c.old    Wed Apr 26 16:23:03 2000
--- vn.c        Fri Apr 28 11:56:41 2000
***************
*** 139,144 ****
--- 139,148 ----
        int              sc_maxactive;  /* max # of active requests     */
        struct buf       sc_tab;        /* transfer queue               */
        u_long           sc_options;    /* options                      */
+       dev_t            sc_devlist;    /* list of devices which refer to
+                                          the same vn unit. The last
+                                          one on the list is the one
+                                          created by make_dev          */
        SLIST_ENTRY(vn_softc) sc_list;
  };
  
***************
*** 179,200 ****
        unit = dkunit(dev);
        vn = dev->si_drv1;
        if (!vn) {
                SLIST_FOREACH(vn, &vn_list, sc_list) {
                        if (vn->sc_unit == unit) {
                                dev->si_drv1 = vn;
                                break;
                        }
                }
        }
        if (!vn) {
                vn = malloc(sizeof *vn, M_DEVBUF, M_WAITOK);
                if (!vn)
                        return (NULL);
                bzero(vn, sizeof *vn);
                vn->sc_unit = unit;
                dev->si_drv1 = vn;
!               make_dev(&vn_cdevsw, 0, 
                    UID_ROOT, GID_OPERATOR, 0640, "vn%d", unit);
                SLIST_INSERT_HEAD(&vn_list, vn, sc_list);
        }
        return (vn);
--- 183,221 ----
        unit = dkunit(dev);
        vn = dev->si_drv1;
        if (!vn) {
+               /* See if we have already a vn softc for this disk unit. */
                SLIST_FOREACH(vn, &vn_list, sc_list) {
                        if (vn->sc_unit == unit) {
+                               /* Just add to the alias list. */
+                               dev->si_drv2 = vn->sc_devlist;
+                               vn->sc_devlist = dev;
                                dev->si_drv1 = vn;
                                break;
                        }
                }
        }
        if (!vn) {
+               /*
+                * No previous uses of this vn unit: construct its softc and
+                * "canonical" device.
+                */
+               dev_t canonical_dev;
                vn = malloc(sizeof *vn, M_DEVBUF, M_WAITOK);
                if (!vn)
                        return (NULL);
                bzero(vn, sizeof *vn);
                vn->sc_unit = unit;
                dev->si_drv1 = vn;
!               canonical_dev = make_dev(&vn_cdevsw, 0, 
                    UID_ROOT, GID_OPERATOR, 0640, "vn%d", unit);
+               canonical_dev->si_drv1 = vn;
+               canonical_dev->si_drv2 = 0;
+               vn->sc_devlist = canonical_dev;
+               if (canonical_dev != dev) {
+                       /* Add the alias we are opening to the alias list */
+                       dev->si_drv2 = vn->sc_devlist;
+                       vn->sc_devlist = dev;
+               }
                SLIST_INSERT_HEAD(&vn_list, vn, sc_list);
        }
        return (vn);
***************
*** 763,776 ****
--- 784,812 ----
                /* fall through */
        case MOD_SHUTDOWN:
                for (;;) {
+                       dev_t dev, next;
                        vn = SLIST_FIRST(&vn_list);
                        if (!vn)
                                break;
                        SLIST_REMOVE_HEAD(&vn_list, sc_list);
                        if (vn->sc_flags & VNF_INITED)
                                vnclear(vn);
+ 
+                       /*
+                        * Cleanup all the dev_t's that refer to this vn
+                        * unit, and destroy_dev the canonical device
+                        * created with make_dev
+                        */
+                       for (dev = vn->sc_devlist; dev; dev = next) {
+                               next = dev->si_drv2;
+                               dev->si_drv1 = dev->si_drv2 = 0;
+ 
+                               if (next == 0)
+                                       destroy_dev(dev);
+                       }
                        free(vn, M_DEVBUF);
                }
+               cdevsw_remove(&vn_cdevsw);
                break;
        default:
                break;

UUencoded:begin 644 patch.Z
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
G902+<FJ-_KK#%_32AC><A:)0M,._+)J\Y9D&..6L`QOHP,]K<50!





>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




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