if (io_data->use_sg)
return ffs_build_sg_list(&io_data->sgt, data_len);
- return kmalloc(data_len, GFP_KERNEL);
+ return kmalloc(data_len, GFP_KERNEL | __GFP_NOWARN);
}
static inline void ffs_free_buffer(struct ffs_io_data *io_data)
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_unlock_irq(&epfile->ffs->eps_lock);
+retry_malloc:
data = ffs_alloc_buffer(io_data, data_len);
if (!data) {
- ret = -ENOMEM;
- goto error_mutex;
+ /* If usb gadget device using physically contiguous
+ * buffer 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
+ * 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.
+ * Otherwise, return error when scatter-gather list.
+ */
+ if (data_len <= PAGE_SIZE || io_data->use_sg) {
+ 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)) {