Module Name: src Committed By: yamaguchi Date: Tue Dec 1 04:39:03 UTC 2020
Modified Files: src/sys/dev/pci: if_iavf.c Log Message: Dequeue aqb from sc_atq_live even when the last command is failed iavf(4) didn't dequeue aqb from sc_atq_live that is a list for buffer in use when a command is failed by ETIMEDOUT. This causes a panic in the following sequence: 1. enqueue an aqb to sc_atq_live at iavf_aqb_post() 2. the last command is failed by ETIMEDOUT 3. enqueue the aqb used in the failed command to sc_atq_idle at an error handling in iavf_attach() 4. dequeue the same aqb from sc_atq_live and enqueue sc_atq_idle again at iavf_cleanup_admin_queue() - sc_atq_idle is broken at that time 5. free the aqb in sc_atq_idle more than once Fix PR/55822 reviewed by knakahara@n.o. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/if_iavf.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_iavf.c diff -u src/sys/dev/pci/if_iavf.c:1.6 src/sys/dev/pci/if_iavf.c:1.7 --- src/sys/dev/pci/if_iavf.c:1.6 Thu Sep 17 06:34:43 2020 +++ src/sys/dev/pci/if_iavf.c Tue Dec 1 04:39:03 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_iavf.c,v 1.6 2020/09/17 06:34:43 yamaguchi Exp $ */ +/* $NetBSD: if_iavf.c,v 1.7 2020/12/01 04:39:03 yamaguchi Exp $ */ /* * Copyright (c) 2013-2015, Intel Corporation @@ -75,7 +75,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_iavf.c,v 1.6 2020/09/17 06:34:43 yamaguchi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_iavf.c,v 1.7 2020/12/01 04:39:03 yamaguchi Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -4164,7 +4164,6 @@ iavf_atq_poll(struct iavf_softc *sc, uns { struct ixl_aq_desc *atq, *slot; struct ixl_aq_desc iaq; - struct ixl_aq_buf *aqb; unsigned int prod; unsigned int t; int dbg; @@ -4194,13 +4193,6 @@ iavf_atq_poll(struct iavf_softc *sc, uns bus_dmamap_sync(sc->sc_dmat, IXL_DMA_MAP(&sc->sc_atq), 0, IXL_DMA_LEN(&sc->sc_atq), BUS_DMASYNC_PREREAD); - aqb = iavf_aqb_get_locked(&sc->sc_atq_live); - if (aqb != NULL) { - bus_dmamap_sync(sc->sc_dmat, IXL_AQB_MAP(aqb), - 0, IXL_AQB_LEN(aqb), BUS_DMASYNC_POSTWRITE); - /* no need to do iavf_aqb_put(&sc->sc_atq_idle, aqb) */ - } - if (iaq.iaq_retval != htole16(IXL_AQ_RC_OK)) { if (dbg >= 2) { device_printf(sc->sc_dev, @@ -4286,6 +4278,18 @@ iavf_adminq_poll_locked(struct iavf_soft iavf_atq_post(sc, iaq, aqb); error = iavf_atq_poll(sc, retry); + + /* + * collect the aqb used in the current command and + * added to sc_atq_live at iavf_atq_post(), + * whether or not the command succeeded. + */ + if (aqb != NULL) { + (void)iavf_aqb_get_locked(&sc->sc_atq_live); + bus_dmamap_sync(sc->sc_dmat, IXL_AQB_MAP(aqb), + 0, IXL_AQB_LEN(aqb), BUS_DMASYNC_POSTWRITE); + } + if (error) return error;