ionic: protect adminq from early destroy
authorShannon Nelson <snelson@pensando.io>
Fri, 19 Mar 2021 00:48:10 +0000 (17:48 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Mar 2021 02:16:10 +0000 (19:16 -0700)
Don't destroy the adminq while there is an outstanding request.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_main.c

index 9b3afed..889d234 100644 (file)
@@ -393,6 +393,8 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
 static void ionic_qcqs_free(struct ionic_lif *lif)
 {
        struct device *dev = lif->ionic->dev;
+       struct ionic_qcq *adminqcq;
+       unsigned long irqflags;
 
        if (lif->notifyqcq) {
                ionic_qcq_free(lif, lif->notifyqcq);
@@ -401,9 +403,14 @@ static void ionic_qcqs_free(struct ionic_lif *lif)
        }
 
        if (lif->adminqcq) {
-               ionic_qcq_free(lif, lif->adminqcq);
-               devm_kfree(dev, lif->adminqcq);
+               spin_lock_irqsave(&lif->adminq_lock, irqflags);
+               adminqcq = READ_ONCE(lif->adminqcq);
                lif->adminqcq = NULL;
+               spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
+               if (adminqcq) {
+                       ionic_qcq_free(lif, adminqcq);
+                       devm_kfree(dev, adminqcq);
+               }
        }
 
        if (lif->rxqcqs) {
@@ -886,6 +893,7 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget)
        struct ionic_intr_info *intr = napi_to_cq(napi)->bound_intr;
        struct ionic_lif *lif = napi_to_cq(napi)->lif;
        struct ionic_dev *idev = &lif->ionic->idev;
+       unsigned long irqflags;
        unsigned int flags = 0;
        int n_work = 0;
        int a_work = 0;
@@ -895,9 +903,11 @@ static int ionic_adminq_napi(struct napi_struct *napi, int budget)
                n_work = ionic_cq_service(&lif->notifyqcq->cq, budget,
                                          ionic_notifyq_service, NULL, NULL);
 
+       spin_lock_irqsave(&lif->adminq_lock, irqflags);
        if (lif->adminqcq && lif->adminqcq->flags & IONIC_QCQ_F_INITED)
                a_work = ionic_cq_service(&lif->adminqcq->cq, budget,
                                          ionic_adminq_service, NULL, NULL);
+       spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
 
        work_done = max(n_work, a_work);
        if (work_done < budget && napi_complete_done(napi, work_done)) {
index 14ece90..c4b2906 100644 (file)
@@ -187,10 +187,17 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
 
 static void ionic_adminq_flush(struct ionic_lif *lif)
 {
-       struct ionic_queue *q = &lif->adminqcq->q;
        struct ionic_desc_info *desc_info;
+       unsigned long irqflags;
+       struct ionic_queue *q;
+
+       spin_lock_irqsave(&lif->adminq_lock, irqflags);
+       if (!lif->adminqcq) {
+               spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
+               return;
+       }
 
-       spin_lock(&lif->adminq_lock);
+       q = &lif->adminqcq->q;
 
        while (q->tail_idx != q->head_idx) {
                desc_info = &q->info[q->tail_idx];
@@ -199,7 +206,7 @@ static void ionic_adminq_flush(struct ionic_lif *lif)
                desc_info->cb_arg = NULL;
                q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
        }
-       spin_unlock(&lif->adminq_lock);
+       spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
 }
 
 static int ionic_adminq_check_err(struct ionic_lif *lif,
@@ -252,15 +259,18 @@ static void ionic_adminq_cb(struct ionic_queue *q,
 static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
 {
        struct ionic_desc_info *desc_info;
+       unsigned long irqflags;
        struct ionic_queue *q;
        int err = 0;
 
-       if (!lif->adminqcq)
+       spin_lock_irqsave(&lif->adminq_lock, irqflags);
+       if (!lif->adminqcq) {
+               spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
                return -EIO;
+       }
 
        q = &lif->adminqcq->q;
 
-       spin_lock(&lif->adminq_lock);
        if (!ionic_q_has_space(q, 1)) {
                err = -ENOSPC;
                goto err_out;
@@ -280,7 +290,7 @@ static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
        ionic_q_post(q, true, ionic_adminq_cb, ctx);
 
 err_out:
-       spin_unlock(&lif->adminq_lock);
+       spin_unlock_irqrestore(&lif->adminq_lock, irqflags);
 
        return err;
 }