From patchwork Mon Aug 29 11:33:34 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Per Forlin X-Patchwork-Id: 3763 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 15AFF23F41 for ; Mon, 29 Aug 2011 11:34:16 +0000 (UTC) Received: from mail-fx0-f52.google.com (mail-fx0-f52.google.com [209.85.161.52]) by fiordland.canonical.com (Postfix) with ESMTP id 0913BA188B8 for ; Mon, 29 Aug 2011 11:34:16 +0000 (UTC) Received: by mail-fx0-f52.google.com with SMTP id 18so6401918fxd.11 for ; Mon, 29 Aug 2011 04:34:16 -0700 (PDT) Received: by 10.223.22.14 with SMTP id l14mr3334969fab.100.1314617655931; Mon, 29 Aug 2011 04:34:15 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.152.11.8 with SMTP id m8cs93063lab; Mon, 29 Aug 2011 04:34:15 -0700 (PDT) Received: by 10.204.142.144 with SMTP id q16mr2065726bku.267.1314617655583; Mon, 29 Aug 2011 04:34:15 -0700 (PDT) Received: from mail-bw0-f50.google.com (mail-bw0-f50.google.com [209.85.214.50]) by mx.google.com with ESMTPS id l2si2665761bke.162.2011.08.29.04.34.14 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 29 Aug 2011 04:34:15 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.214.50 is neither permitted nor denied by best guess record for domain of per.forlin@linaro.org) client-ip=209.85.214.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.214.50 is neither permitted nor denied by best guess record for domain of per.forlin@linaro.org) smtp.mail=per.forlin@linaro.org Received: by mail-bw0-f50.google.com with SMTP id zu5so5471497bkb.37 for ; Mon, 29 Aug 2011 04:34:14 -0700 (PDT) Received: by 10.204.152.86 with SMTP id f22mr1296960bkw.176.1314617654341; Mon, 29 Aug 2011 04:34:14 -0700 (PDT) Received: from localhost.localdomain (c-c37f71d5.029-82-6c756e10.cust.bredbandsbolaget.se [213.113.127.195]) by mx.google.com with ESMTPS id s10sm1185215bka.64.2011.08.29.04.34.12 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 29 Aug 2011 04:34:13 -0700 (PDT) From: Per Forlin To: linux-kernel@vger.kernel.org, Linus Walleij , Rabin Vincent Cc: Vinod Koul , linaro-dev@lists.linaro.org, Per Forlin Subject: [PATCH 3/4] dmaengine/ste_dma40: fix Oops due to double free of client descriptor Date: Mon, 29 Aug 2011 13:33:34 +0200 Message-Id: <1314617615-2394-4-git-send-email-per.forlin@linaro.org> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1314617615-2394-1-git-send-email-per.forlin@linaro.org> References: <1314617615-2394-1-git-send-email-per.forlin@linaro.org> The client list may exist in two lists at the same time. This makes free fail since the same desc is freed multiple times. Remove desc from client list when adding it to the pending queue. Move free of client owned descriptors from free_dma() to terminate_all(). Unable to handle kernel paging request at virtual address 00100104 pgd = dea8c000 [00100104] *pgd=1ea62831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] PREEMPT SMP Modules linked in: CPU: 0 Not tainted (3.1.0-rc3+ #58) PC is at d40_free_chan_resources+0x64/0x330 Signed-off-by: Per Forlin --- drivers/dma/ste_dma40.c | 22 ++++++++++++---------- 1 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 37388d1..92ec0a2 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -644,8 +644,11 @@ static struct d40_desc *d40_first_active_get(struct d40_chan *d40c) return d; } +/* remove desc from current queue and add it to the pending_queue */ static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc) { + d40_desc_remove(desc); + desc->is_in_client_list = false; list_add_tail(&desc->node, &d40c->pending_queue); } @@ -803,6 +806,7 @@ done: static void d40_term_all(struct d40_chan *d40c) { struct d40_desc *d40d; + struct d40_desc *_d; /* Release active descriptors */ while ((d40d = d40_first_active_get(d40c))) { @@ -822,6 +826,14 @@ static void d40_term_all(struct d40_chan *d40c) d40_desc_free(d40c, d40d); } + /* Release client owned descriptors */ + if (!list_empty(&d40c->client)) + list_for_each_entry_safe(d40d, _d, &d40c->client, node) { + d40_desc_remove(d40d); + d40_desc_free(d40c, d40d); + } + + d40c->pending_tx = 0; d40c->busy = false; } @@ -1594,20 +1606,10 @@ static int d40_free_dma(struct d40_chan *d40c) u32 event; struct d40_phy_res *phy = d40c->phy_chan; bool is_src; - struct d40_desc *d; - struct d40_desc *_d; - /* Terminate all queued and active transfers */ d40_term_all(d40c); - /* Release client owned descriptors */ - if (!list_empty(&d40c->client)) - list_for_each_entry_safe(d, _d, &d40c->client, node) { - d40_desc_remove(d); - d40_desc_free(d40c, d); - } - if (phy == NULL) { chan_err(d40c, "phy == null\n"); return -EINVAL;