From fb2b9232685cf0ca860f4129dc05ddf3941d1768 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 17 Oct 2018 16:14:33 +0200 Subject: [PATCH] ffs: Limit bulk transfer size to page size (4096 bytes) This commit it intended to fix page allocation failures in kernel due to ffs trying to allocate continuous memory of length specified by userspace. [ 2452.765000] sdbd: page allocation failure: order:6, mode:0x24040c0 [ 2452.770000] CPU: 2 PID: 6253 Comm: sdbd Not tainted 4.4.71-00002-g4b213b7 #130 [ 2452.780000] Hardware name: s5p4418 [ 2452.780000] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [ 2452.790000] [] (show_stack) from [] (dump_stack+0x80/0x94) [ 2452.795000] [] (dump_stack) from [] (warn_alloc_failed+0xf0/0x130) [ 2452.805000] [] (warn_alloc_failed) from [] (__alloc_pages_nodemask+0x8f8/0xa98) [ 2452.810000] [] (__alloc_pages_nodemask) from [] (alloc_kmem_pages+0x28/0xc0) [ 2452.810000] [] (alloc_kmem_pages) from [] (kmalloc_order+0x20/0x38) [ 2452.810000] [] (kmalloc_order) from [] (kmalloc_order_trace+0x2c/0x110) [ 2452.810000] [] (kmalloc_order_trace) from [] (__kmalloc+0x2f4/0x364) [ 2452.810000] [] (__kmalloc) from [] (ffs_epfile_io+0xb0/0x4a4) [ 2452.810000] [] (ffs_epfile_io) from [] (ffs_epfile_read_iter+0xb4/0x170) [ 2452.810000] [] (ffs_epfile_read_iter) from [] (__vfs_read+0xbc/0xe4) [ 2452.810000] [] (__vfs_read) from [] (vfs_read+0x88/0x114) [ 2452.810000] [] (vfs_read) from [] (SyS_read+0x4c/0xa0) [ 2452.810000] [] (SyS_read) from [] (__sys_trace_return+0x0/0x10) [ 2452.895000] Mem-Info: [ 2452.895000] active_anon:22405 inactive_anon:183 isolated_anon:0 [ 2452.895000] active_file:12599 inactive_file:42754 isolated_file:4 [ 2452.895000] unevictable:3 dirty:29 writeback:0 unstable:0 [ 2452.895000] slab_reclaimable:3331 slab_unreclaimable:4106 [ 2452.895000] mapped:14507 shmem:325 pagetables:960 bounce:0 [ 2452.895000] free:30893 free_pcp:21 free_cma:30150 [ 2452.930000] DMA free:124524kB min:2360kB low:2948kB high:3540kB active_anon:89620kB inactive_anon:732kB active_file:50376kB inactive_file:169800kB unevictable:12kB isolated(anon):0kB isolated(file):16kB present:507904kB managed:488348kB mlocked:12kB dirty:116kB writeback:0kB mapped:58028kB shmem:1300kB slab_reclaimable:13324kB slab_unreclaimable:16424kB kernel_stack:2648kB pagetables:3840kB unstable:0kB bounce:0kB free_pcp:452kB local_pcp:0kB free_cma:120600kB writeback_tmp:0kB pages_scanned:428 all_unreclaimable? no [ 2452.975000] lowmem_reserve[]: 0 0 0 0 [ 2452.980000] DMA: 389*4kB (UMC) 125*8kB (MEC) 84*16kB (UMEC) 52*32kB (UMC) 34*64kB (UC) 35*128kB (UC) 30*256kB (UC) 28*512kB (C) 20*1024kB (C) 14*2048kB (C) 10*4096kB (C) = 124348kB [ 2452.995000] 55510 total pagecache pages [ 2453.000000] 126976 pages RAM [ 2453.005000] 0 pages HighMem/MovableOnly [ 2453.005000] 4889 pages reserved [ 2453.010000] 32768 pages cma reserved Change-Id: I3cef431057ac9e22483f4960bc3265132f6c4b41 --- src/usb_funcfs_client.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/usb_funcfs_client.c b/src/usb_funcfs_client.c index dd9fa65..8111388 100644 --- a/src/usb_funcfs_client.c +++ b/src/usb_funcfs_client.c @@ -39,6 +39,22 @@ static const char ep0_path[] = USB_FUNCFS_SDB_PATH"/ep0"; static const char ep1_path[] = USB_FUNCFS_SDB_PATH"/ep1"; static const char ep2_path[] = USB_FUNCFS_SDB_PATH"/ep2"; +/* Limit bulk read/write transfers to page size (usually 4096 bytes) + * + * This is the size individual transfer that sdbd will request to/from + * kernel (via read/write(endpoint, ...). While the buffer could be + * bigger (ffs allows that) this size is also the size of the + * _continuous memory_ buffer allocated in kernel. Continous memory + * is scarce resource and allocation of higher order can often fail in + * a system with fragmented memory (kernel message: "sdbd: page + * allocation failure: order:6, mode:0x24040c0"). + * + * Only page-sized allocation are guaranteed to succeed and this is + * used as default below (ffs_usb_init() will update to system's page + * size, if possible). + */ +#define XFER_MAX_DEFAULT 4096 +static int xfer_max = XFER_MAX_DEFAULT; /* A local struct to store state of application */ struct usb_handle @@ -332,7 +348,8 @@ static int bulk_write(int bulkin_fd, const void *buf, size_t length) int ret; do { - ret = sdb_write(bulkin_fd, buf + count, length - count); + int xfer_len = length - count > xfer_max ? xfer_max : length - count; + ret = sdb_write(bulkin_fd, buf + count, xfer_len); if (ret < 0) { if (errno != EINTR) return ret; @@ -357,7 +374,8 @@ static int bulk_read(int bulkout_fd, void *buf, size_t length) int ret; do { - ret = sdb_read(bulkout_fd, buf + count, length - count); + int xfer_len = length - count > xfer_max ? xfer_max : length - count; + ret = sdb_read(bulkout_fd, buf + count, xfer_len); if (ret < 0) { if (errno != EINTR) { @@ -417,6 +435,10 @@ void ffs_usb_init() D("[ usb_init - using FunctionFS ]\n"); + int pagesize = sysconf(_SC_PAGESIZE); + if (pagesize > 0) + xfer_max = pagesize; + h = calloc(1, sizeof(usb_handle)); if (h == NULL) { perror("[ failed to allocate memory for usb FunctionFS bulk device ]\n"); -- 2.34.1