On 3/8/25 11:20 PM, Shuai Xue wrote: > The idxd_setup_internals() is missing some cleanup when things fail in > the middle. > > Add the appropriate cleanup routines: > > - cleanup groups > - cleanup enginces > - cleanup wqs > > to make sure it exits gracefully. > > Fixes: defe49f96012 ("dmaengine: idxd: fix group conf_dev lifetime") > Cc: stable@xxxxxxxxxxxxxxx > Suggested-by: Fenghua Yu <fenghuay@xxxxxxxxxx> > Signed-off-by: Shuai Xue <xueshuai@xxxxxxxxxxxxxxxxx> Reviewed-by: Dave Jiang <dave.jiang@xxxxxxxxx> > --- > drivers/dma/idxd/init.c | 59 ++++++++++++++++++++++++++++++++++++----- > 1 file changed, 52 insertions(+), 7 deletions(-) > > diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c > index fe4a14813bba..7334085939dc 100644 > --- a/drivers/dma/idxd/init.c > +++ b/drivers/dma/idxd/init.c > @@ -155,6 +155,26 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd) > pci_free_irq_vectors(pdev); > } > > +static void idxd_clean_wqs(struct idxd_device *idxd) > +{ > + struct idxd_wq *wq; > + struct device *conf_dev; > + int i; > + > + for (i = 0; i < idxd->max_wqs; i++) { > + wq = idxd->wqs[i]; > + if (idxd->hw.wq_cap.op_config) > + bitmap_free(wq->opcap_bmap); > + kfree(wq->wqcfg); > + conf_dev = wq_confdev(wq); > + put_device(conf_dev); > + kfree(wq); > + > + } > + bitmap_free(idxd->wq_enable_map); > + kfree(idxd->wqs); > +} > + > static int idxd_setup_wqs(struct idxd_device *idxd) > { > struct device *dev = &idxd->pdev->dev; > @@ -245,6 +265,21 @@ static int idxd_setup_wqs(struct idxd_device *idxd) > return rc; > } > > +static void idxd_clean_engines(struct idxd_device *idxd) > +{ > + struct idxd_engine *engine; > + struct device *conf_dev; > + int i; > + > + for (i = 0; i < idxd->max_engines; i++) { > + engine = idxd->engines[i]; > + conf_dev = engine_confdev(engine); > + put_device(conf_dev); > + kfree(engine); > + } > + kfree(idxd->engines); > +} > + > static int idxd_setup_engines(struct idxd_device *idxd) > { > struct idxd_engine *engine; > @@ -296,6 +331,19 @@ static int idxd_setup_engines(struct idxd_device *idxd) > return rc; > } > > +static void idxd_clean_groups(struct idxd_device *idxd) > +{ > + struct idxd_group *group; > + int i; > + > + for (i = 0; i < idxd->max_groups; i++) { > + group = idxd->groups[i]; > + put_device(group_confdev(group)); > + kfree(group); > + } > + kfree(idxd->groups); > +} > + > static int idxd_setup_groups(struct idxd_device *idxd) > { > struct device *dev = &idxd->pdev->dev; > @@ -410,7 +458,7 @@ static int idxd_init_evl(struct idxd_device *idxd) > static int idxd_setup_internals(struct idxd_device *idxd) > { > struct device *dev = &idxd->pdev->dev; > - int rc, i; > + int rc; > > init_waitqueue_head(&idxd->cmd_waitq); > > @@ -441,14 +489,11 @@ static int idxd_setup_internals(struct idxd_device *idxd) > err_evl: > destroy_workqueue(idxd->wq); > err_wkq_create: > - for (i = 0; i < idxd->max_groups; i++) > - put_device(group_confdev(idxd->groups[i])); > + idxd_clean_groups(idxd); > err_group: > - for (i = 0; i < idxd->max_engines; i++) > - put_device(engine_confdev(idxd->engines[i])); > + idxd_clean_engines(idxd); > err_engine: > - for (i = 0; i < idxd->max_wqs; i++) > - put_device(wq_confdev(idxd->wqs[i])); > + idxd_clean_wqs(idxd); > err_wqs: > return rc; > }