Allow me to trim the message a bit.
On Thu, Jul 25, 2019 at 11:27:45AM +0200, Dafna Hirschfeld wrote:
> > > [ 70.219867] cma: cma_alloc(cma (____ptrval____), count 4050,
> > > align 8)
> > > [ 70.237878] cma: cma_alloc: alloc failed, req-size: 4050 pages,
> > > ret: -12
It shows that cma_alloc() failed so the dma_alloc_contigudous()
does fallback alloc_pages_node(). It should be same as previous
__dma_direct_alloc_pages(), but would you like to confirm after
partially reverting the change at kernel/dma/direct.c file? It
is not necessary for debugging to entirely revert the commit as
build break might happen since the helper functions are called
by other files too. Something like this:
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index b67f0aa08aa3..6688e1cee7d1 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -96,6 +96,8 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t
phys, size_t size)
struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
{
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ int page_order = get_order(size);
struct page *page = NULL;
u64 phys_mask;
@@ -107,9 +109,20 @@ struct page *__dma_direct_alloc_pages(struct device *dev,
size_t size,
gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask,
&phys_mask);
again:
- page = dma_alloc_contiguous(dev, size, gfp);
+ /* CMA can be used only in the context which permits sleeping */
+ if (gfpflags_allow_blocking(gfp)) {
+ page = dma_alloc_from_contiguous(dev, count, page_order,
+ gfp & __GFP_NOWARN);
+ if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
+ dma_release_from_contiguous(dev, page, count);
+ page = NULL;
+ }
+ }
+ if (!page)
+ page = alloc_pages_node(dev_to_node(dev), gfp, page_order);
+
if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) {
- dma_free_contiguous(dev, page, size);
+ __free_pages(page, page_order);
page = NULL;
if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
@@ -141,7 +154,7 @@ void *dma_direct_alloc_pages(struct device *dev, size_t
size,
if (PageHighMem(page)) {
/*
* Depending on the cma= arguments and per-arch setup
- * dma_alloc_contiguous could return highmem pages.
+ * dma_alloc_from_contiguous could return highmem pages.
* Without remapping there is no way to return them here,
* so log an error and fail.
*/
@@ -170,7 +183,10 @@ void *dma_direct_alloc_pages(struct device *dev, size_t
size,
void __dma_direct_free_pages(struct device *dev, size_t size, struct page
*page)
{
- dma_free_contiguous(dev, page, size);
+ unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+ if (!dma_release_from_contiguous(dev, page, count))
+ __free_pages(page, get_order(size));
}
void dma_direct_free_pages(struct device *dev, size_t size, void *cpu_addr,
> > > [ 70.244599] cma: number of available pages: 72@184+3886@4306=>
> > > 3958 free of 8192 total pages
> > > [ 70.253066] cma: cma_alloc(): returned (____ptrval____)
> > > [ 70.264893] cma: cma_release(page (____ptrval____))
> > > [ 70.272871] cma: cma_release(page (____ptrval____))
> > > [ 70.277800] BUG: Bad page state in process v4l2-ctl pfn:b5a00
> > > [ 70.283652] page:ffff7e0001d68000 refcount:13 mapcount:0
> > > mapping:0000000000000000 index:0x0 compound_mapcount: 0
> > > [ 70.293874] flags: 0xffff00000010000(head)
> > > [ 70.297999] raw: 0ffff00000010000 dead000000000100
> > > dead000000000122 0000000000000000
> > > [ 70.305772] raw: 0000000000000000 0000000000000000
> > > 0000000dffffffff 0000000000000000
> > > [ 70.313526] page dumped because: nonzero _refcount
> > > [ 70.318327] Modules linked in:
> > > [ 70.321399] CPU: 2 PID: 482 Comm: v4l2-ctl Not tainted 5.3.0-
> > > rc1+ #159
> > > [ 70.327927] Hardware name: Boundary Devices i.MX8MQ Nitrogen8M
> > > (DT)
> > > [ 70.334196] Call trace:
> > > [ 70.336654] dump_backtrace+0x0/0x148
> > > [ 70.340319] show_stack+0x14/0x20
> > > [ 70.343640] dump_stack+0x9c/0xc4
> > > [ 70.346959] bad_page+0xe4/0x148
> > > [ 70.350188] free_pages_check_bad+0x70/0xa8
> > > [ 70.354375] __free_pages_ok+0x294/0x2b0
> > > [ 70.358301] __free_pages+0x38/0x50
> > > [ 70.361795] dma_free_contiguous+0x90/0x98
> > > [ 70.365892] __dma_direct_free_pages+0x18/0x20
Here shows cma_release() has failed as those pages aren't from
CMA, so it uses the fallback __free_pages(). I just scrutinized
my commit once again and found that the free routine has missed
a PAGE_ALIGN() operation for the size parameter. Though it does
not likely cause the problem, yet would you please try this?
diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
index bfc0c17f2a3d..a2d872a82be9 100644
--- a/kernel/dma/contiguous.c
+++ b/kernel/dma/contiguous.c
@@ -266,7 +266,8 @@ struct page *dma_alloc_contiguous(struct device *dev,
size_t size, gfp_t gfp)
*/
void dma_free_contiguous(struct device *dev, struct page *page, size_t size)
{
- if (!cma_release(dev_get_cma_area(dev), page, size >> PAGE_SHIFT))
+ if (!cma_release(dev_get_cma_area(dev), page,
+ PAGE_ALIGN(size) >> PAGE_SHIFT))
__free_pages(page, get_order(size));
}