[PATCH v2] wifi: mt76: fix potential memory leakage
Sujuan Chen (陈素娟)
Sujuan.Chen at mediatek.com
Mon Dec 19 20:42:33 PST 2022
On Mon, 2022-12-19 at 10:55 +0100, Lorenzo Bianconi wrote:
> > From: Bo Jiao <Bo.Jiao at mediatek.com>
> >
> > fix potential memory leakage, recycle rxwi when mt76_dma_add_buf()
> > call fail.
> >
> > Signed-off-by: Bo Jiao <Bo.Jiao at mediatek.com>
> > ---
> > v2:
> > - recycle rxwi when page_frag_alloc() and dma_map_single() fail.
> > ---
> > drivers/net/wireless/mediatek/mt76/dma.c | 27 ++++++++++++++----
> > ------
> > 1 file changed, 16 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/dma.c
> > b/drivers/net/wireless/mediatek/mt76/dma.c
> > index fc24b35..76ad47d 100644
> > --- a/drivers/net/wireless/mediatek/mt76/dma.c
> > +++ b/drivers/net/wireless/mediatek/mt76/dma.c
> > @@ -580,24 +580,29 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct
> > mt76_queue *q)
> >
> > buf = page_frag_alloc(&q->rx_page, q->buf_size,
> > GFP_ATOMIC);
> > if (!buf)
> > - break;
> > + goto out;
> >
> > addr = dma_map_single(dev->dma_dev, buf, len,
> > DMA_FROM_DEVICE);
> > - if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {
> > - skb_free_frag(buf);
> > - break;
> > - }
> > + if (unlikely(dma_mapping_error(dev->dma_dev, addr)))
> > + goto free;
> >
> > qbuf.addr = addr + offset;
> > qbuf.len = len - offset;
> > qbuf.skip_unmap = false;
> > - if (mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t) < 0)
> > {
> > - dma_unmap_single(dev->dma_dev, addr, len,
> > - DMA_FROM_DEVICE);
> > - skb_free_frag(buf);
> > - break;
> > - }
> > + if (mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t) < 0)
> > + goto umap;
> > +
> > frames++;
> > + continue;
> > +
> > +umap:
> > + dma_unmap_single(dev->dma_dev, addr, len,
> > + DMA_FROM_DEVICE);
> > +free:
> > + skb_free_frag(buf);
> > +out:
> > + mt76_put_rxwi(dev, t);
> > + break;
> > }
> >
> > if (frames)
>
> Hi Bo,
>
> I guess in the way below, the code is more readable, what do you
> think?
>
> Regards,
> Lorenzo
>
> diff --git a/drivers/net/wireless/mediatek/mt76/dma.c
> b/drivers/net/wireless/mediatek/mt76/dma.c
> index fad5fe19fe18..001538f698f1 100644
> --- a/drivers/net/wireless/mediatek/mt76/dma.c
> +++ b/drivers/net/wireless/mediatek/mt76/dma.c
> @@ -571,13 +571,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct
> mt76_queue *q)
> struct mt76_queue_buf qbuf;
> void *buf = NULL;
>
> - if ((q->flags & MT_QFLAG_WED) &&
> - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) ==
> MT76_WED_Q_RX) {
> - t = mt76_get_rxwi(dev);
> - if (!t)
> - break;
> - }
> -
> buf = page_frag_alloc(&q->rx_page, q->buf_size,
> GFP_ATOMIC);
> if (!buf)
> break;
> @@ -588,16 +581,27 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct
> mt76_queue *q)
> break;
> }
>
> + if ((q->flags & MT_QFLAG_WED) &&
> + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) ==
> MT76_WED_Q_RX) {
> + t = mt76_get_rxwi(dev);
> + if (!t)
> + goto unmap;
> + }
> +
> qbuf.addr = addr + offset;
> qbuf.len = len - offset;
> qbuf.skip_unmap = false;
> - if (mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t) < 0)
> {
> - dma_unmap_single(dev->dma_dev, addr, len,
> - DMA_FROM_DEVICE);
> - skb_free_frag(buf);
> - break;
> +
> + if (!mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t)) {
> + frames++;
> + continue;
> }
> - frames++;
> +
> +unmap:
> + dma_unmap_single(dev->dma_dev, addr, len,
> DMA_FROM_DEVICE);
> + skb_free_frag(buf);
> + mt76_put_rxwi(dev, t);
> + break;
> }
>
> if (frames)
>
Hi Lore,
we love your patch, but we have another patch to avoid memory
fragmentation by duplicating the rx skb after mt76_dma_dequeue(). it
requires mt76_get_rxwi() be placed before page_frag_alloc().
the below patch(need rebase) will be sent after the current patch is
accepted.
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -386,9 +386,11 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct
mt76_queue *q, int idx,
SKB_WITH_OVERHEAD(q->buf_size),
DMA_FROM_DEVICE);
- buf = t->ptr;
+ buf = page_frag_alloc(&q->rx_page, q->buf_size,
GFP_ATOMIC);
+ if (!buf)
+ return NULL;
+ memcpy(buf, t->ptr, SKB_WITH_OVERHEAD(q->buf_size));
t->dma_addr = 0;
- t->ptr = NULL;
mt76_put_rxwi(dev, t);
@@ -569,6 +571,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct
mt76_queue *q)
while (q->queued < q->ndesc - 1) {
struct mt76_txwi_cache *t = NULL;
struct mt76_queue_buf qbuf;
+ bool skip_alloc = false;
void *buf = NULL;
if ((q->flags & MT_QFLAG_WED) &&
@@ -576,11 +579,19 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct
mt76_queue *q)
t = mt76_get_rxwi(dev);
if (!t)
break;
+
+ if (t->ptr) {
+ skip_alloc = true;
+ buf = t->ptr;
+ }
}
- buf = page_frag_alloc(&q->rx_page, q->buf_size,
GFP_ATOMIC);
- if (!buf)
- break;
+ if (!skip_alloc) {
+ buf = page_frag_alloc(&q->rx_page, q->buf_size,
+ GFP_ATOMIC);
+ if (!buf)
+ break;
+ }
addr = dma_map_single(dev->dma_dev, buf, len,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {
--
2.18.0
> > --
> > 2.18.0
> >
More information about the Linux-mediatek
mailing list