Fix multi-function card memory problems:

- centralize pcmcia function allocation and free'ing.
- free the cfe too, not just the pf in the multifunction card case.
- don't free pointers while walking the list, because free() will
  fill the memory with deadbeef, thus killing list walking.
This commit is contained in:
christos 2002-08-15 10:37:02 +00:00
parent bbe21e45f5
commit 4251568ad8
3 changed files with 59 additions and 46 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmcia_cis.c,v 1.30 2002/06/01 23:51:02 lukem Exp $ */
/* $NetBSD: pcmcia_cis.c,v 1.31 2002/08/15 10:37:02 christos Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pcmcia_cis.c,v 1.30 2002/06/01 23:51:02 lukem Exp $");
__KERNEL_RCSID(0, "$NetBSD: pcmcia_cis.c,v 1.31 2002/08/15 10:37:02 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -61,8 +61,45 @@ struct cis_state {
int pcmcia_parse_cis_tuple __P((struct pcmcia_tuple *, void *));
static int decode_funce __P((struct pcmcia_tuple *, struct pcmcia_function *));
static void create_pf __P((struct cis_state *));
static void
create_pf(struct cis_state *state)
{
state->pf = malloc(sizeof(*state->pf), M_DEVBUF, M_NOWAIT|M_ZERO);
state->pf->number = state->count++;
state->pf->last_config_index = -1;
SIMPLEQ_INIT(&state->pf->cfe_head);
SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf, pf_list);
}
void
pcmcia_free_pf(struct pcmcia_function_head *pfhead)
{
struct pcmcia_function *pf, *opf = NULL;
struct pcmcia_config_entry *cfe, *ocfe = NULL;
SIMPLEQ_FOREACH(pf, pfhead, pf_list) {
SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
if (ocfe)
free(ocfe, M_DEVBUF);
ocfe = cfe;
}
if (ocfe) {
free(ocfe, M_DEVBUF);
ocfe = NULL;
}
if (opf)
free(opf, M_DEVBUF);
opf = pf;
}
if (opf)
free(opf, M_DEVBUF);
SIMPLEQ_INIT(pfhead);
}
void
pcmcia_read_cis(sc)
struct pcmcia_softc *sc;
@ -690,17 +727,11 @@ pcmcia_parse_cis_tuple(tuple, arg)
* rather not change it.
*/
if (state->gotmfc == 1) {
struct pcmcia_function *pf;
SIMPLEQ_FOREACH(pf, &state->card->pf_head, pf_list) {
free(pf, M_DEVBUF);
}
SIMPLEQ_INIT(&state->card->pf_head);
state->count = 0;
state->gotmfc = 2;
state->count = 0;
state->pf = NULL;
pcmcia_free_pf(&state->card->pf_head);
}
break;
case PCMCIA_CISTPL_LONGLINK_MFC:
@ -710,7 +741,11 @@ pcmcia_parse_cis_tuple(tuple, arg)
* functions declared before the MFC link can be cleaned
* up.
*/
state->gotmfc = 1;
if (state->gotmfc == 0) {
state->gotmfc = 1;
} else {
DPRINTF(("got LONGLINK_MFC again!"));
}
break;
#ifdef PCMCIACISDEBUG
case PCMCIA_CISTPL_DEVICE:
@ -849,16 +884,8 @@ pcmcia_parse_cis_tuple(tuple, arg)
state->pf = NULL;
}
}
if (state->pf == NULL) {
state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
M_NOWAIT|M_ZERO);
state->pf->number = state->count++;
state->pf->last_config_index = -1;
SIMPLEQ_INIT(&state->pf->cfe_head);
SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf,
pf_list);
}
if (state->pf == NULL)
create_pf(state);
state->pf->function = pcmcia_tuple_read_1(tuple, 0);
DPRINTF(("CISTPL_FUNCID\n"));
@ -897,15 +924,7 @@ pcmcia_parse_cis_tuple(tuple, arg)
break;
}
if (state->pf == NULL) {
state->pf = malloc(sizeof(*state->pf),
M_DEVBUF, M_NOWAIT|M_ZERO);
state->pf->number = state->count++;
state->pf->last_config_index = -1;
SIMPLEQ_INIT(&state->pf->cfe_head);
SIMPLEQ_INSERT_TAIL(&state->card->pf_head,
state->pf, pf_list);
create_pf(state);
state->pf->function = PCMCIA_FUNCTION_UNSPEC;
}
state->pf->last_config_index =

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmcia_cis_quirks.c,v 1.19 2002/06/01 23:51:02 lukem Exp $ */
/* $NetBSD: pcmcia_cis_quirks.c,v 1.20 2002/08/15 10:37:02 christos Exp $ */
/*
* Copyright (c) 1998 Marc Horowitz. All rights reserved.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pcmcia_cis_quirks.c,v 1.19 2002/06/01 23:51:02 lukem Exp $");
__KERNEL_RCSID(0, "$NetBSD: pcmcia_cis_quirks.c,v 1.20 2002/08/15 10:37:02 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -284,17 +284,7 @@ void pcmcia_check_cis_quirks(sc)
}
printf("\n");
}
SIMPLEQ_FOREACH(pf, &sc->card.pf_head,
pf_list) {
SIMPLEQ_FOREACH(cfe, &pf->cfe_head,
cfe_list) {
free(cfe, M_DEVBUF);
}
free(pf, M_DEVBUF);
}
SIMPLEQ_INIT(&sc->card.pf_head);
pcmcia_free_pf(&sc->card.pf_head);
wiped = 1;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcmciavar.h,v 1.16 2002/06/01 23:51:02 lukem Exp $ */
/* $NetBSD: pcmciavar.h,v 1.17 2002/08/15 10:37:02 christos Exp $ */
/*
* Copyright (c) 1997 Marc Horowitz. All rights reserved.
@ -155,6 +155,8 @@ struct pcmcia_function {
/* pf_flags */
#define PFF_ENABLED 0x0001 /* function is enabled */
SIMPLEQ_HEAD(pcmcia_function_head, pcmcia_function);
struct pcmcia_card {
int cis1_major;
int cis1_minor;
@ -172,7 +174,7 @@ struct pcmcia_card {
#define PCMCIA_PRODUCT_INVALID -1
u_int16_t error;
#define PCMCIA_CIS_INVALID { NULL, NULL, NULL, NULL }
SIMPLEQ_HEAD(, pcmcia_function) pf_head;
struct pcmcia_function_head pf_head;
};
struct pcmcia_softc {
@ -297,6 +299,8 @@ int pcmcia_io_map __P((struct pcmcia_function *, int, bus_addr_t,
bus_size_t, struct pcmcia_io_handle *, int *));
void pcmcia_io_unmap __P((struct pcmcia_function *, int));
void pcmcia_free_pf __P((struct pcmcia_function_head *));
#define pcmcia_mem_alloc(pf, size, pcmhp) \
(pcmcia_chip_mem_alloc((pf)->sc->pct, (pf)->sc->pch, (size), (pcmhp)))