summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongwoo Lee <dwoo08.lee@samsung.com>2018-10-26 10:41:41 +0900
committerDongwoo Lee <dwoo08.lee@samsung.com>2019-12-20 14:27:55 +0900
commit868788459b5403009d82575fd4834efbfe11e7b2 (patch)
tree73783373c7da6479942daa01e6a39639dbab1898
parent2f0922a3c1e0ede0b5f67e881775424c183f2874 (diff)
downloadlinux-4.9-exynos9110-868788459b5403009d82575fd4834efbfe11e7b2.tar.gz
linux-4.9-exynos9110-868788459b5403009d82575fd4834efbfe11e7b2.tar.bz2
linux-4.9-exynos9110-868788459b5403009d82575fd4834efbfe11e7b2.zip
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 <dwoo08.lee@samsung.com>
-rw-r--r--drivers/usb/gadget/function/f_fs.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 59c69db43041..a429ee374921 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -948,10 +948,34 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
spin_unlock_irq(&epfile->ffs->eps_lock);
- data = kmalloc(data_len, GFP_KERNEL);
+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(data, data_len, &io_data->data) != data_len) {