From 7628acd8ee72924b811aad8c68150f6532ff36af Mon Sep 17 00:00:00 2001 From: Scott Long Date: Thu, 19 Apr 2007 18:53:52 +0000 Subject: [PATCH] Up until now, the free SCB pool received only a small initial allocation, and new SCBs were allocated on demand later if needed. This has two problems. First, allocating SCBs involves allocating contiguous memory, and if memory is exhausted then the VM will try to page out to satisfy the request, leading to recursion and deadlock. The second problem is that it can cause lock order reversals due to parts of the VM still being under Giant. Fix the problem be allocating the full pool at driver attach, when it is safe to do so. --- sys/dev/aic7xxx/aic79xx.c | 23 +++++++++++++---------- sys/dev/aic7xxx/aic79xx.h | 2 +- sys/dev/aic7xxx/aic7xxx.c | 12 +++++++----- sys/dev/aic7xxx/aic7xxx.h | 2 +- sys/dev/aic7xxx/aic7xxx_inline.h | 3 ++- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c index d65c3a4df4dc..aa771af927d7 100644 --- a/sys/dev/aic7xxx/aic79xx.c +++ b/sys/dev/aic7xxx/aic79xx.c @@ -5693,7 +5693,8 @@ ahd_init_scbdata(struct ahd_softc *ahd) scb_data->init_level++; /* Perform initial CCB allocation */ - ahd_alloc_scbs(ahd); + while (ahd_alloc_scbs(ahd) != 0) + ; if (scb_data->numscbs == 0) { printf("%s: ahd_init_scbdata - " @@ -5940,7 +5941,8 @@ ahd_get_scb(struct ahd_softc *ahd, u_int col_idx) if (tries++ != 0) return (NULL); - ahd_alloc_scbs(ahd); + if (ahd_alloc_scbs(ahd) == 0) + return (NULL); goto look_again; } LIST_REMOVE(scb, links.le); @@ -6011,7 +6013,7 @@ ahd_free_scb(struct ahd_softc *ahd, struct scb *scb) aic_platform_scb_free(ahd, scb); } -void +int ahd_alloc_scbs(struct ahd_softc *ahd) { struct scb_data *scb_data; @@ -6031,7 +6033,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) scb_data = &ahd->scb_data; if (scb_data->numscbs >= AHD_SCB_MAX_ALLOC) /* Can't allocate any more */ - return; + return (0); if (scb_data->scbs_left != 0) { int offset; @@ -6044,14 +6046,14 @@ ahd_alloc_scbs(struct ahd_softc *ahd) hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT); if (hscb_map == NULL) - return; + return (0); /* Allocate the next batch of hardware SCBs */ if (aic_dmamem_alloc(ahd, scb_data->hscb_dmat, (void **)&hscb_map->vaddr, BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) { free(hscb_map, M_DEVBUF); - return; + return (0); } SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links); @@ -6077,14 +6079,14 @@ ahd_alloc_scbs(struct ahd_softc *ahd) sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); if (sg_map == NULL) - return; + return (0); /* Allocate the next batch of S/G lists */ if (aic_dmamem_alloc(ahd, scb_data->sg_dmat, (void **)&sg_map->vaddr, BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) { free(sg_map, M_DEVBUF); - return; + return (0); } SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); @@ -6114,14 +6116,14 @@ ahd_alloc_scbs(struct ahd_softc *ahd) sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT); if (sense_map == NULL) - return; + return (0); /* Allocate the next batch of sense buffers */ if (aic_dmamem_alloc(ahd, scb_data->sense_dmat, (void **)&sense_map->vaddr, BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { free(sense_map, M_DEVBUF); - return; + return (0); } SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links); @@ -6210,6 +6212,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) sense_busaddr += AHD_SENSE_BUFSIZE; scb_data->numscbs++; } + return (i); } void diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h index 1703ab4b5958..e9c8847905b3 100644 --- a/sys/dev/aic7xxx/aic79xx.h +++ b/sys/dev/aic7xxx/aic79xx.h @@ -1402,7 +1402,7 @@ void ahd_set_unit(struct ahd_softc *, int); void ahd_set_name(struct ahd_softc *, char *); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); -void ahd_alloc_scbs(struct ahd_softc *ahd); +int ahd_alloc_scbs(struct ahd_softc *ahd); void ahd_free(struct ahd_softc *ahd); int ahd_reset(struct ahd_softc *ahd, int reinit); void ahd_shutdown(void *arg); diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index a5883e200b13..659b4e89984c 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -4444,7 +4444,8 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* Perform initial CCB allocation */ memset(scb_data->hscbs, 0, AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb)); - ahc_alloc_scbs(ahc); + while (ahc_alloc_scbs(ahc) != 0) + ; if (scb_data->numscbs == 0) { printf("%s: ahc_init_scbdata - " @@ -4522,7 +4523,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc) free(scb_data->scbarray, M_DEVBUF); } -void +int ahc_alloc_scbs(struct ahc_softc *ahc) { struct scb_data *scb_data; @@ -4536,21 +4537,21 @@ ahc_alloc_scbs(struct ahc_softc *ahc) scb_data = ahc->scb_data; if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC) /* Can't allocate any more */ - return; + return (0); next_scb = &scb_data->scbarray[scb_data->numscbs]; sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); if (sg_map == NULL) - return; + return (0); /* Allocate S/G space for the next batch of SCBS */ if (aic_dmamem_alloc(ahc, scb_data->sg_dmat, (void **)&sg_map->sg_vaddr, BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { free(sg_map, M_DEVBUF); - return; + return (0); } SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); @@ -4599,6 +4600,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) next_scb++; ahc->scb_data->numscbs++; } + return (i); } void diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index ac0bde23d23e..77acfe4d0a96 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -1227,7 +1227,7 @@ int ahc_resume(struct ahc_softc *ahc); void ahc_softc_insert(struct ahc_softc *); void ahc_set_unit(struct ahc_softc *, int); void ahc_set_name(struct ahc_softc *, char *); -void ahc_alloc_scbs(struct ahc_softc *ahc); +int ahc_alloc_scbs(struct ahc_softc *ahc); void ahc_free(struct ahc_softc *ahc); int ahc_reset(struct ahc_softc *ahc, int reinit); void ahc_shutdown(void *arg); diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h index 989ac79dfc24..c4a37b593676 100644 --- a/sys/dev/aic7xxx/aic7xxx_inline.h +++ b/sys/dev/aic7xxx/aic7xxx_inline.h @@ -363,7 +363,8 @@ ahc_get_scb(struct ahc_softc *ahc) struct scb *scb; if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) { - ahc_alloc_scbs(ahc); + if (ahc_alloc_scbs(ahc) == 0) + return (NULL); scb = SLIST_FIRST(&ahc->scb_data->free_scbs); if (scb == NULL) return (NULL);