Commit e768929d authored by Shannon Nelson's avatar Shannon Nelson Committed by David S. Miller
Browse files

ionic: protect adminq from early destroy



Don't destroy the adminq while there is an outstanding request.

Signed-off-by: default avatarShannon Nelson <snelson@pensando.io>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e8eaf84
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -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)) {
+16 −6
Original line number Diff line number Diff line
@@ -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;
}