-avoid lock leak in error case
-Free AGP memory on close, to avoid a memory leak in case the X server doesn't free it explicitely. (It appears that the X server never calls AGPIOC_DEALLOCATE.) Fixes PR kern/17869 by Emmanuel Dreyfus.
This commit is contained in:
parent
e52744d883
commit
29c16c72fb
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: agp.c,v 1.15 2002/06/27 18:37:10 drochner Exp $ */
|
||||
/* $NetBSD: agp.c,v 1.16 2002/08/11 12:40:47 drochner Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 Doug Rabson
|
||||
|
@ -65,7 +65,7 @@
|
|||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: agp.c,v 1.15 2002/06/27 18:37:10 drochner Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: agp.c,v 1.16 2002/08/11 12:40:47 drochner Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -514,8 +514,10 @@ agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
|
|||
for (contigpages = 8; contigpages > 0; contigpages >>= 1) {
|
||||
nseg = (mem->am_size / (contigpages * PAGE_SIZE)) + 1;
|
||||
segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK);
|
||||
if (segs == NULL)
|
||||
if (segs == NULL) {
|
||||
lockmgr(&sc->as_lock, LK_RELEASE, 0);
|
||||
return ENOMEM;
|
||||
}
|
||||
if (bus_dmamem_alloc(sc->as_dmat, mem->am_size, PAGE_SIZE, 0,
|
||||
segs, nseg, &mem->am_nseg,
|
||||
contigpages > 1 ?
|
||||
|
@ -669,7 +671,8 @@ agp_release_helper(struct agp_softc *sc, enum agp_acquire_state state)
|
|||
return EBUSY;
|
||||
|
||||
/*
|
||||
* Clear out the aperture and free any outstanding memory blocks.
|
||||
* Clear out outstanding aperture mappings.
|
||||
* (should not be necessary, done by caller)
|
||||
*/
|
||||
TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
|
||||
if (mem->am_is_bound) {
|
||||
|
@ -798,12 +801,31 @@ int
|
|||
agpclose(dev_t dev, int fflag, int devtype, struct proc *p)
|
||||
{
|
||||
struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev));
|
||||
struct agp_memory *mem;
|
||||
|
||||
/*
|
||||
* Clear the GATT and force release on last close
|
||||
*/
|
||||
if (sc->as_state == AGP_ACQUIRE_USER)
|
||||
if (sc->as_state == AGP_ACQUIRE_USER) {
|
||||
while ((mem = TAILQ_FIRST(&sc->as_memory))) {
|
||||
if (mem->am_is_bound) {
|
||||
printf("agpclose: mem %d is bound\n",
|
||||
mem->am_id);
|
||||
AGP_UNBIND_MEMORY(sc, mem);
|
||||
}
|
||||
/*
|
||||
* XXX it is not documented, but if the protocol allows
|
||||
* allocate->acquire->bind, it would be possible that
|
||||
* memory ranges are allocated by the kernel here,
|
||||
* which we shouldn't free. We'd have to keep track of
|
||||
* the memory range's owner.
|
||||
* The kernel API is unsed yet, so we get away with
|
||||
* freeing all.
|
||||
*/
|
||||
AGP_FREE_MEMORY(sc, mem);
|
||||
}
|
||||
agp_release_helper(sc, AGP_ACQUIRE_USER);
|
||||
}
|
||||
sc->as_isopen = 0;
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue