Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Nov 1998 21:35:37 -0500 (EST)
From:      "Larry S. Lile" <lile@stdio.com>
To:        hackers@FreeBSD.ORG
Subject:   "panic: free: multiple frees" VM bug? (long)
Message-ID:  <Pine.BSF.3.96.981102212308.17694B-100000@heathers.stdio.com>

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

I am working on a token ring driver and I cannot seem to find
out why this is happening.  I contigmalloc buffers for tranmsitting
frames and then free them later when they have been transmitted.
I have to use contigmalloc in order to get buffers below the
16M mark for dma.

Anyone see what is wrong? Should I not do this? Or have I
stumbled over a vm bug?

It looks like a vm bug to me, but I have been wrong before.

All pertinent information below...

Larry Lile
lile@stdio.com

Please ignore the soft-updates panic, I understand that happens
sometimes during a dump.

panicstr: page fault
panic messages:
---
panic: free: multiple frees

syncing disks... 

Fatal trap 12: page fault while in kernel mode
fault virtual address   = 0x30
fault code              = supervisor read, page not present
instruction pointer     = 0x8:0xf01cdf08
stack pointer           = 0x10:0xf024bf14
frame pointer           = 0x10:0xf024bf18
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, def32 1, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = Idle
interrupt mask          = net tty bio cam 
trap number             = 12
panic: page fault

---
#0  boot (howto=260) at ../../kern/kern_shutdown.c:268
268                     dumppcb.pcb_cr3 = rcr3();
(kgdb) bt
#0  boot (howto=260) at ../../kern/kern_shutdown.c:268
#1  0xf014932f in panic (fmt=0xf0242de9 "page fault")
    at ../../kern/kern_shutdown.c:430
#2  0xf01f796d in trap_fatal (frame=0xf024bed8) at
../../i386/i386/trap.c:879
#3  0xf01f7648 in trap_pfault (frame=0xf024bed8, usermode=0)
    at ../../i386/i386/trap.c:772
#4  0xf01f72a7 in trap (frame={tf_es = 16, tf_ds = 16, tf_edi = 0, 
      tf_esi = -252868608, tf_ebp = -266027240, tf_isp = -266027264, 
      tf_ebx = -265970844, tf_edx = -1073217472, tf_ecx = 0, tf_eax = 0, 
      tf_trapno = 12, tf_err = 0, tf_eip = -266543352, tf_cs = 8, 
      tf_eflags = 66182, tf_esp = -252868608, tf_ss = -266027208})
    at ../../i386/i386/trap.c:396
#5  0xf01cdf08 in acquire_lock (lk=0xf0259b64)
    at ../../ufs/ffs/ffs_softdep.c:268
#6  0xf01d1929 in softdep_update_inodeblock (ip=0xf0ed8800, bp=0xf368ac30, 
    waitfor=0) at ../../ufs/ffs/ffs_softdep.c:3482
#7  0xf01ccf1c in ffs_update (vp=0xf5ddc0c0, access=0xf024bfd0, 
    modify=0xf024bfd0, waitfor=0) at ../../ufs/ffs/ffs_inode.c:109
#8  0xf01d5f59 in ffs_fsync (ap=0xf024c00c) at
../../ufs/ffs/ffs_vnops.c:252
#9  0xf01d4383 in ffs_sync (mp=0xf0e40a00, waitfor=2, cred=0xf0dd3700, 
    p=0xf028a04c) at vnode_if.h:499
#10 0xf016b2a7 in sync (p=0xf028a04c, uap=0x0) at
../../kern/vfs_syscalls.c:527
#11 0xf0148faa in boot (howto=256) at ../../kern/kern_shutdown.c:201
#12 0xf014932f in panic (fmt=0xf023723e "free: multiple frees")
    at ../../kern/kern_shutdown.c:430
#13 0xf0146553 in free (addr=0xf5e62000, type=0xf0251980)
    at ../../kern/kern_malloc.c:334
#14 0xf01febe3 in DriverTransmitFrameCompleted (DriverHandle=0x0, 
    FrameHandle=0xa, TransmitStatus=0) at ../../i386/isa/if_oltr.c:936
#15 0xf022b252 in ReturnCompletedBuffers ()
#16 0x30001 in ?? ()
cannot read proc at 0
(kgdb) up 14
#14 0xf01febe3 in DriverTransmitFrameCompleted (DriverHandle=0x0, 
    FrameHandle=0xa, TransmitStatus=0) at ../../i386/isa/if_oltr.c:936
936
free(sc->tx_buffer[frame].frame->TransmitFragment[i].VirtualAddress,
M_DEVBUF);
(kgdb) list
931             printf("oltr%d: Unused buffer returned *boggle*\n",
sc->unit);
932         } else {
933             for (i = 0; i < sc->tx_buffer[frame].frame->FragmentCount;
i++) {
934                 printf("oltr%d: freeing fragment %d frame %d\n",
sc->unit, i, frame);
935                 sc->tx_frags--;
936
free(sc->tx_buffer[frame].frame->TransmitFragment[i].VirtualAddress,
M_DEVBUF);
937             }
938         }
939
940         printf("Oltr%d: %d total frags in use.\n", sc->unit,
sc->tx_frags);
(kgdb) 

I know that I have not called free on the same buffer twice by
looking at the debug messages.

Nov  2 21:11:43 anarchy /kernel: oltr0: output frame 0 - 1 fragments (1
fragments in use total)
Nov  2 21:11:43 anarchy /kernel: iso88025_input: Packet queued. 
Nov  2 21:11:43 anarchy /kernel: oltr0: transmit complete frame 0 - 1
fragments (1 total fragments in use total)
Nov  2 21:11:43 anarchy /kernel: oltr0: freeing fragment 0 frame 0
Nov  2 21:11:43 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:56 anarchy /kernel: oltr0: output frame 1 - 1 fragments (1
fragments in use total)
Nov  2 21:11:56 anarchy /kernel: iso88025_input: Packet queued.
Nov  2 21:11:56 anarchy /kernel: oltr0: transmit complete frame 1 - 1
fragments (1 total fragments in use total)
Nov  2 21:11:56 anarchy /kernel: oltr0: freeing fragment 0 frame 1 
Nov  2 21:11:56 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:56 anarchy /kernel: iso88025_input: Packet queued.
Nov  2 21:11:56 anarchy /kernel: oltr0: output frame 2 - 2 fragments (2
fragments in use total)
Nov  2 21:11:56 anarchy /kernel: oltr0: transmit complete frame 2 - 2
fragments (2 total fragments in use total)
Nov  2 21:11:56 anarchy /kernel: oltr0: freeing fragment 0 frame 2
Nov  2 21:11:56 anarchy /kernel: oltr0: freeing fragment 1 frame 2
Nov  2 21:11:57 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:57 anarchy /kernel: iso88025_input: Packet queued.
Nov  2 21:11:57 anarchy /kernel: oltr0: output frame 3 - 1 fragments (1
fragments in use total)
Nov  2 21:11:57 anarchy /kernel: oltr0: transmit complete frame 3 - 1
fragments (1 total fragments in use total)
Nov  2 21:11:57 anarchy /kernel: oltr0: freeing fragment 0 frame 3
Nov  2 21:11:57 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:59 anarchy /kernel: oltr0: output frame 4 - 2 fragments (2
fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: transmit complete frame 4 - 2
fragments (2 total fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 0 frame 4
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 1 frame 4
Nov  2 21:11:59 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:59 anarchy /kernel: iso88025_input: Packet queued.
Nov  2 21:11:59 anarchy /kernel: oltr0: output frame 5 - 2 fragments (2
fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: transmit complete frame 5 - 2
fragments (2 total fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 0 frame 5
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 1 frame 5 
Nov  2 21:11:59 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:59 anarchy /kernel: oltr0: output frame 6 - 2 fragments (2
fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: transmit complete frame 6 - 2
fragments (2 total fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 0 frame 6 
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 1 frame 6
Nov  2 21:11:59 anarchy /kernel: Oltr0: 0 total frags in use.
Nov  2 21:11:59 anarchy /kernel: iso88025_input: Packet queued.
Nov  2 21:11:59 anarchy /kernel: oltr0: output frame 7 - 2 fragments (2
fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: transmit complete frame 7 - 2
fragments (2 total fragments in use total)
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 0 frame 7
Nov  2 21:11:59 anarchy /kernel: oltr0: freeing fragment 1 frame 7
Nov  2 21:11:59 anarchy /kernel: Oltr0: 0 total frags in use.

How the buffers get allocated:

void *
oltr_malloc(Size, Adapter)
    ssize_t Size;
    TRlldAdapterConfig_t *Adapter;
{

    /* If the adapter needs memory below 16M for DMA then use contigmalloc
*/
    if (Adapter->mode & TRLLD_MODE_16M)  /* Adapter using ISA DMA buffer
below 16M */
        return(contigmalloc(Size, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
1ul, 0x10000ul));
    else
        return(malloc(Size, M_DEVBUF, M_NOWAIT));
}

Where the frames get built:

static void
oltr_start(ifp)
    struct ifnet *ifp;
{
    struct oltr_softc *sc = &oltr_softc[ifp->if_unit];
    struct mbuf *m0, *m;
    struct iso88025_header *th;
    int  len, i, j, k, rc, s;

    /*printf("oltr%d: oltr_start\n", sc->unit);*/

    s = splimp();

    /* Check to see if we have enough room to transmit */
    if (sc->tx_avail <= 0) {
        /* No free buffers, hold off the upper layers */
        /*printf("oltr%d: transmit queue full.\n", sc->unit);*/
        ifp->if_flags |= IFF_OACTIVE;
        splx(s);
        return;
    }
    IF_DEQUEUE(&ifp->if_snd, m);
    if (m == 0) {
        printf("oltr%d: oltr_start NULL packet dequeued.\n", sc->unit);
        ifp->if_flags &= ~IFF_OACTIVE;
        splx(s);
        return;
    }

    th = mtod(m, struct iso88025_header *);
    th->ac = 0x10;
    th->fc = 0x40;

    /* Keep a pointer to the head of the packet */
    m0 = m;

    i = (sc->tx_next & TX_LIST_MASK); /* Just to shorten thing up */
    if (sc->tx_buffer[i].inuse) {
        printf("oltr%d: Transmit ring buffer blown!\n", sc->unit);
        oltr_stop(sc);
        splx(s);
        return;
    }

    for (len = 0, j = 0; m != 0; m = m->m_next, j++) {
        sc->tx_frags++;
        sc->tx_buffer[i].frame->TransmitFragment[j].VirtualAddress = (char
*)oltr_malloc(m->m_len, sc->config);
        if (!sc->tx_buffer[i].frame->TransmitFragment[j].VirtualAddress) {
            printf("oltr%d: unable to allocate memory.\n", sc->unit);
            /* Free up the other fragments */
            for (k = 0; k < j; k++) {
                sc->tx_frags--;

free(sc->tx_buffer[i].frame->TransmitFragment[k].VirtualAddress,
M_DEVBUF);
            }
            goto bad;
        }
        sc->tx_buffer[i].frame->TransmitFragment[j].PhysicalAddress =
kvtop(sc->tx_buffer[i].frame->TransmitFragment[j].VirtualAd
dress);
        sc->tx_buffer[i].frame->TransmitFragment[j].count = m->m_len;
        bcopy(mtod(m, caddr_t),
sc->tx_buffer[i].frame->TransmitFragment[j].VirtualAddress, m->m_len);
        len += m->m_len;
    }
    sc->tx_buffer[i].frame->FragmentCount = j;
    sc->tx_buffer[i].inuse = 1;

    rc = TRlldTransmitFrame(sc->TRlldAdapter, (TRlldTransmit_t
*)sc->tx_buffer[i].frame, (void *)sc->tx_buffer[i].index);
    if (rc != TRLLD_TRANSMIT_OK) {
        printf("oltr%d: TRlldTransmitFrame returned (%x)\n", sc->unit,
rc);
        ifp->if_oerrors++;
        for (j = 0; j < sc->tx_buffer[i].frame->FragmentCount; j++)  {
            sc->tx_frags--;

free(sc->tx_buffer[i].frame->TransmitFragment[j].VirtualAddress,
M_DEVBUF);
        }
        sc->tx_buffer[i].inuse = 0;
        goto bad;
    }

    printf("oltr%d: output frame %d - %d fragments (%d fragments in use
total)\n", sc->unit, i, sc->tx_buffer[i].frame->FragmentC
ount, sc->tx_frags);
    
    sc->tx_next++;
    sc->tx_avail--;
    
#if NBPFILTER > 0
    if (ifp->if_bpf)
        bpf_mtap(ifp, m0);
#endif

bad:
    m_freem(m);
    splx(s); 
    return;
}

Where they get freed;

static void
DriverCloseCompleted(DriverHandle)
    void *DriverHandle;
{   
    struct oltr_softc *sc = &oltr_softc[(int)DriverHandle];
           
    /*printf("oltr%d: DriverCloseCompleted\n", sc->unit);*/
                            
    untimeout(oltr_timeout, (void *)sc->unit, sc->oltr_ch);
    wakeup_one((void *)sc->unit);
                            
    if ((sc->hw_state != HW_CLOSING) && (sc->hw_state != HW_CLOSING2) &&
(sc->hw_state != HW_CLOSED)) {
        printf("oltr%d: adapter close complete called in wrong state
(%d)\n", sc->unit, sc->hw_state);
        return;             
    }                       
    sc->hw_state = HW_CLOSING2;
    if (sc->config->dmalevel != TRLLD_DMA_PIO)
        isa_dma_release(sc->config->dmalevel);
                        
}                   



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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.96.981102212308.17694B-100000>