ffs: Limit bulk transfer size to page size (4096 bytes) 70/191470/2 submit/tizen/20181018.104932
authorKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 17 Oct 2018 14:14:33 +0000 (16:14 +0200)
committerKarol Lewandowski <k.lewandowsk@samsung.com>
Wed, 17 Oct 2018 14:14:33 +0000 (16:14 +0200)
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] [<c001964c>] (unwind_backtrace) from [<c0014ec8>] (show_stack+0x20/0x24)
[ 2452.790000] [<c0014ec8>] (show_stack) from [<c03516d8>] (dump_stack+0x80/0x94)
[ 2452.795000] [<c03516d8>] (dump_stack) from [<c0139738>] (warn_alloc_failed+0xf0/0x130)
[ 2452.805000] [<c0139738>] (warn_alloc_failed) from [<c013cef0>] (__alloc_pages_nodemask+0x8f8/0xa98)
[ 2452.810000] [<c013cef0>] (__alloc_pages_nodemask) from [<c013d2bc>] (alloc_kmem_pages+0x28/0xc0)
[ 2452.810000] [<c013d2bc>] (alloc_kmem_pages) from [<c01585d4>] (kmalloc_order+0x20/0x38)
[ 2452.810000] [<c01585d4>] (kmalloc_order) from [<c0158618>] (kmalloc_order_trace+0x2c/0x110)
[ 2452.810000] [<c0158618>] (kmalloc_order_trace) from [<c01783ac>] (__kmalloc+0x2f4/0x364)
[ 2452.810000] [<c01783ac>] (__kmalloc) from [<c052b868>] (ffs_epfile_io+0xb0/0x4a4)
[ 2452.810000] [<c052b868>] (ffs_epfile_io) from [<c052be44>] (ffs_epfile_read_iter+0xb4/0x170)
[ 2452.810000] [<c052be44>] (ffs_epfile_read_iter) from [<c018b7e4>] (__vfs_read+0xbc/0xe4)
[ 2452.810000] [<c018b7e4>] (__vfs_read) from [<c018bfbc>] (vfs_read+0x88/0x114)
[ 2452.810000] [<c018bfbc>] (vfs_read) from [<c018c8e4>] (SyS_read+0x4c/0xa0)
[ 2452.810000] [<c018c8e4>] (SyS_read) from [<c0010ef4>] (__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

index dd9fa65..8111388 100644 (file)
@@ -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");