bug fix for mmc queue.c

Wang, Yalin
2014-01-21T09:44:37Z

[-- Attachment #1: Type: text/plain, Size: 5851 bytes --]

Hi

We encounter a problem when use sdcard ,
The driver probe will failed like this :

<6>[ 121.644102] mmc0: mmc_start_bkops: Starting bkops
<6>[ 133.039845] mmc0: mmc_start_bkops: raw_bkops_status=0x2, from_exception=0
<6>[ 133.039888] mmc0: mmc_start_bkops: Starting bkops
<6>[ 147.931642] mmc0: mmc_start_bkops: raw_bkops_status=0x2, from_exception=1
<6>[ 148.634009] mmc0: mmc_start_bkops: Starting bkops
<6>[ 164.279748] mmc1: slot status change detected (0 -> 1), GPIO_ACTIVE_LOW
<6>[ 164.612904] mmc1: new high speed SD card at address 1234
<4>[ 164.620819] kworker/u:29: page allocation failure: order:5, mode:0x40d0
<6>[ 164.629745] [<c010c514>] (unwind_backtrace+0x0/0x11c) from [<c0217e78>] (warn_alloc_failed+0x104/0x130)
<6>[ 164.629789] [<c0217e78>] (warn_alloc_failed+0x104/0x130) from [<c021b39c>] (__alloc_pages_nodemask+0x7d4/0x8f4)
<6>[ 164.629828] [<c021b39c>] (__alloc_pages_nodemask+0x7d4/0x8f4) from [<c021b510>] (__get_free_pages+0x10/0x24)
<6>[ 164.629867] [<c021b510>] (__get_free_pages+0x10/0x24) from [<c0246630>] (kmalloc_order_trace+0x20/0xe0)
<6>[ 164.629904] [<c0246630>] (kmalloc_order_trace+0x20/0xe0) from [<c0249550>] (__kmalloc+0x30/0x270)
<6>[ 164.629939] [<c0249550>] (__kmalloc+0x30/0x270) from [<c061cdbc>] (mmc_alloc_sg+0x18/0x40)
<6>[ 164.629974] [<c061cdbc>] (mmc_alloc_sg+0x18/0x40) from [<c061d524>] (mmc_init_queue+0x418/0x4fc)
<6>[ 164.630008] [<c061d524>] (mmc_init_queue+0x418/0x4fc) from [<c06195a0>] (mmc_blk_alloc_req+0x18c/0x3d0)
<6>[ 164.630043] [<c06195a0>] (mmc_blk_alloc_req+0x18c/0x3d0) from [<c061b2a8>] (mmc_blk_probe+0x74/0x2c0)
<6>[ 164.630078] [<c061b2a8>] (mmc_blk_probe+0x74/0x2c0) from [<c060d68c>] (mmc_bus_probe+0x14/0x18)
<6>[ 164.630115] [<c060d68c>] (mmc_bus_probe+0x14/0x18) from [<c045a928>] (driver_probe_device+0x134/0x334)
<6>[ 164.630154] [<c045a928>] (driver_probe_device+0x134/0x334) from [<c0458e0c>] (bus_for_each_drv+0x48/0x8c)
<6>[ 164.630190] [<c0458e0c>] (bus_for_each_drv+0x48/0x8c) from [<c045a77c>] (device_attach+0x7c/0xa0)
<6>[ 164.630222] [<c045a77c>] (device_attach+0x7c/0xa0) from [<c0459ca0>] (bus_probe_device+0x28/0x98)
<6>[ 164.630257] [<c0459ca0>] (bus_probe_device+0x28/0x98) from [<c04583f0>] (device_add+0x3f4/0x5a8)
<6>[ 164.630292] [<c04583f0>] (device_add+0x3f4/0x5a8) from [<c060dd7c>] (mmc_add_card+0x1f0/0x2e8)
<6>[ 164.630329] [<c060dd7c>] (mmc_add_card+0x1f0/0x2e8) from [<c0613990>] (mmc_attach_sd+0x234/0x278)
<6>[ 164.630364] [<c0613990>] (mmc_attach_sd+0x234/0x278) from [<c060cab8>] (mmc_rescan+0x24c/0x2cc)
<6>[ 164.630400] [<c060cab8>] (mmc_rescan+0x24c/0x2cc) from [<c01a2a40>] (process_one_work+0x200/0x400)
<6>[ 164.630438] [<c01a2a40>] (process_one_work+0x200/0x400) from [<c01a2df0>] (worker_thread+0x184/0x2a4)
<6>[ 164.630474] [<c01a2df0>] (worker_thread+0x184/0x2a4) from [<c01a74ac>] (kthread+0x80/0x90)
<6>[ 164.630510] [<c01a74ac>] (kthread+0x80/0x90) from [<c0106aec>] (kernel_thread_exit+0x0/0x8)
<6>[ 164.630529] Mem-info:
<6>[ 164.630542] Normal per-cpu:
<6>[ 164.630559] CPU 0: hi: 186, btch: 31 usd: 0
<6>[ 164.630573] HighMem per-cpu:
<6>[ 164.630588] CPU 0: hi: 90, btch: 15 usd: 0
<6>[ 164.630624] active_anon:96301 inactive_anon:586 isolated_anon:4
<6>[ 164.630633] active_file:26021 inactive_file:25748 isolated_file:0
<6>[ 164.630641] unevictable:694 dirty:4 writeback:0 unstable:0
<6>[ 164.630649] free:5131 slab_reclaimable:3282 slab_unreclaimable:5632
<6>[ 164.630658] mapped:36273 shmem:649 pagetables:3794 bounce:0
<6>[ 164.630666] free_cma:139
<6>[ 164.630716] Normal free:18660kB min:3136kB low:3920kB high:4704kB active_anon:183052kB inactive_anon:1980kB active_file:98188kB inactive_file:98364kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:616020kB mlocked:0kB dirty:8kB writeback:0kB mapped:134632kB shmem:1992kB slab_reclaimable:13128kB slab_unreclaimable:22528kB kernel_stack:10528kB pagetables:15176kB unstable:0kB bounce:0kB free_cma:112kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
<6>[ 164.630769] lowmem_reserve[]: 0 1691 1691
<6>[ 164.630831] HighMem free:1864kB min:208kB low:480kB high:756kB active_anon:202152kB inactive_anon:364kB active_file:5896kB inactive_file:4628kB unevictable:2776kB isolated(anon):16kB isolated(file):0kB present:216488kB mlocked:0kB dirty:8kB writeback:0kB mapped:10460kB shmem:604kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_cma:444kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
<6>[ 164.630883] lowmem_reserve[]: 0 0 0
<6>[ 164.630913] Normal: 1215*4kB (UEMC) 421*8kB (UEMC) 396*16kB (UM) 114*32kB (UM) 7*64kB (UM) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 18660kB
<6>[ 164.631034] HighMem: 190*4kB (UMRC) 26*8kB (UMRC) 9*16kB (UMC) 1*32kB (C) 0*64kB 1*128kB (C) 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 1272kB
<6>[ 164.631154] 53112 total pagecache pages
<6>[ 164.631167] 0 pages in swap cache
<6>[ 164.631183] Swap cache stats: add 0, delete 0, find 0/0
<6>[ 164.631197] Free swap = 0kB
<6>[ 164.631209] Total swap = 0kB
<6>[ 164.648069] 230912 pages of RAM
<6>[ 164.648087] 12304 free pages
<6>[ 164.648099] 30954 reserved pages
<6>[ 164.648111] 5947 slab pages
<6>[ 164.648123] 358720 pages shared
<6>[ 164.648135] 0 pages swap cached
<4>[ 164.648468] mmcblk: probe of mmc1:1234 failed with error -12

The reason is that mmc_alloc_sg() function will use kmalloc to init
Scatterlist , in this issue, it is 32KB memory , the kmalloc will fail if there is
Not enough low memory , instead, we can use vmalloc if the request memory is larger than
A PAGE_SIZE , we make a patch for this problems (see attachment patch.diff) ,
Hope can be merged into mainline .

Thanks

[-- Attachment #2: patch.diff --]
[-- Type: application/octet-stream, Size: 2508 bytes --]

diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index cef1a41..839b506 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -15,6 +15,7 @@
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
+#include <linux/vmalloc.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -198,8 +199,13 @@ static void mmc_urgent_request(struct request_queue *q)
static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
{
struct scatterlist *sg;
+ size_t size = sizeof(struct scatterlist)*sg_len;
+
+ if (size > PAGE_SIZE)
+ sg = vmalloc(size);
+ else
+ sg = kmalloc(size, GFP_KERNEL);

- sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
if (!sg)
*err = -ENOMEM;
else {
@@ -210,6 +216,14 @@ static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
return sg;
}

+static void mmc_alloc_free(const void *addr)
+{
+ if (is_vmalloc_addr(addr))
+ vfree(addr);
+ else
+ kfree(addr);
+}
+
static void mmc_queue_setup_discard(struct request_queue *q,
struct mmc_card *card)
{
@@ -397,20 +411,20 @@ success:

return 0;
free_bounce_sg:
- kfree(mqrq_cur->bounce_sg);
+ mmc_alloc_free(mqrq_cur->bounce_sg);
mqrq_cur->bounce_sg = NULL;
- kfree(mqrq_prev->bounce_sg);
+ mmc_alloc_free(mqrq_prev->bounce_sg);
mqrq_prev->bounce_sg = NULL;

cleanup_queue:
- kfree(mqrq_cur->sg);
+ mmc_alloc_free(mqrq_cur->sg);
mqrq_cur->sg = NULL;
- kfree(mqrq_cur->bounce_buf);
+ mmc_alloc_free(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;

- kfree(mqrq_prev->sg);
+ mmc_alloc_free(mqrq_prev->sg);
mqrq_prev->sg = NULL;
- kfree(mqrq_prev->bounce_buf);
+ mmc_alloc_free(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;

blk_cleanup_queue(mq->queue);
@@ -436,22 +450,22 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);

- kfree(mqrq_cur->bounce_sg);
+ mmc_alloc_free(mqrq_cur->bounce_sg);
mqrq_cur->bounce_sg = NULL;

- kfree(mqrq_cur->sg);
+ mmc_alloc_free(mqrq_cur->sg);
mqrq_cur->sg = NULL;

- kfree(mqrq_cur->bounce_buf);
+ mmc_alloc_free(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;

- kfree(mqrq_prev->bounce_sg);
+ mmc_alloc_free(mqrq_prev->bounce_sg);
mqrq_prev->bounce_sg = NULL;

- kfree(mqrq_prev->sg);
+ mmc_alloc_free(mqrq_prev->sg);
mqrq_prev->sg = NULL;

- kfree(mqrq_prev->bounce_buf);
+ mmc_alloc_free(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;

mq->card = NULL;