Index: sys/x86/x86/mca.c =================================================================== --- sys/x86/x86/mca.c +++ sys/x86/x86/mca.c @@ -560,16 +560,29 @@ mca_fill_freelist(void) { struct mca_internal *rec; - int desired; + int desired_high, desired_low; /* * Ensure we have at least one record for each bank and one - * record per CPU. + * record per CPU. Also, free excess entries which have crept onto + * our list. Do the frees first in case a concurrent thread begins + * using the free list entries while this thread is still working. */ - desired = imax(mp_ncpus, mca_banks); + desired_low = imax(mp_ncpus, mca_banks); + desired_high = imax(mp_ncpus, mca_banks) * 2; mtx_lock_spin(&mca_lock); - while (mca_freecount < desired) { + while (mca_freecount > desired_high) { + rec = STAILQ_FIRST(&mca_freelist); + KASSERT(rec != NULL, ("mca_freecount is %d, but list is empty", + mca_freecount)); + STAILQ_REMOVE_HEAD(&mca_freelist, link); + mca_freecount--; mtx_unlock_spin(&mca_lock); + free(rec, M_MCA); + mtx_lock_spin(&mca_lock); + } + while (mca_freecount < desired_low) { + mtx_unlock_spin(&mca_lock); rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_freelist, rec, link); @@ -821,13 +834,17 @@ thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); - STAILQ_FOREACH(mca, &mca_records, link) { + while ((mca = STAILQ_FIRST(&mca_records)) != NULL) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } + STAILQ_REMOVE_HEAD(&mca_records, link); + STAILQ_INSERT_TAIL(&mca_freelist, rec, link); + mca_freecount++; } mtx_unlock_spin(&mca_lock); + mca_fill_freelist(); } } @@ -1334,13 +1351,18 @@ /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); - STAILQ_FOREACH(mca, &mca_records, link) { + while ((mca = STAILQ_FIRST(&mca_records)) != NULL) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } + STAILQ_REMOVE_HEAD(&mca_records, link); + STAILQ_INSERT_TAIL(&mca_freelist, rec, link); + mca_freecount++; } mtx_unlock_spin(&mca_lock); + if (!cold) + taskqueue_enqueue(mca_tq, &mca_refill_task); } } #endif