From 7d2335910dbd6434409acb6510578044c0057992 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 26 Oct 2018 10:41:41 +0900 Subject: [PATCH] usb: gadget: f_fs: Give chance to retry malloc for large size buffer The f_fs daemons usually use large size buffer for increasing transfer performance, but it can cause memory allocation failure in case of that buddy space is fragmented. Since this, instead of just returning error in this case, give the chance to retry to allocate memory with a half length in order to prevent daemon crash due to failure of buffer allocation. Change-Id: I2171932b8cb565102d63eb82c114987b85d26ed9 Signed-off-by: Dongwoo Lee --- drivers/usb/gadget/function/f_fs.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index f8bcfc5..6f0c28f 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1016,10 +1016,34 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE; spin_unlock_irq(&epfile->ffs->eps_lock); - data = ffs_alloc_buffer(io_data, data_len); +retry_malloc: + data = kmalloc(data_len, GFP_KERNEL | __GFP_NOWARN); if (unlikely(!data)) { - ret = -ENOMEM; - goto error_mutex; + /* + * f_fs daemons usually use large size buffer for + * performance. However, this can cause failure of + * kmalloc() due to buddy fragmentation, even if there + * is available memory and thus it can be compacted by + * by kswapd. Therefore, instead of just returning error + * to daemon in the case of failure of kmalloc(), give + * the second chance to allocate buffer with a half size + * until it really fails due to memory shortage. + */ + if (unlikely(data_len <= PAGE_SIZE)) { + ret = -ENOMEM; + goto error_mutex; + } + + data_len = data_len >> 1; + + if (io_data->read) { + spin_lock_irq(&epfile->ffs->eps_lock); + data_len = usb_ep_align_maybe(gadget, + ep->ep, data_len); + spin_unlock_irq(&epfile->ffs->eps_lock); + } + + goto retry_malloc; } if (!io_data->read && !copy_from_iter_full(data, data_len, &io_data->data)) { -- 2.7.4