Message ID | 20201124194749.4041176-1-123321artyom@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | exfat: Avoid allocating upcase table using kcalloc() | expand |
> The table for Unicode upcase conversion requires an order-5 allocation, > which may fail on a highly-fragmented system: > > pool-udisksd: page allocation failure: order:5, > mode:0x40dc0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), > nodemask=(null),cpuset=/,mems_allowed=0 > CPU: 4 PID: 3756880 Comm: pool-udisksd Tainted: G U 5.8.10- > 200.fc32.x86_64 #1 > Hardware name: Dell Inc. XPS 13 9360/0PVG6D, BIOS 2.13.0 11/14/2019 Call > Trace: > dump_stack+0x6b/0x88 > warn_alloc.cold+0x75/0xd9 > ? _cond_resched+0x16/0x40 > ? __alloc_pages_direct_compact+0x144/0x150 > __alloc_pages_slowpath.constprop.0+0xcfa/0xd30 > ? __schedule+0x28a/0x840 > ? __wait_on_bit_lock+0x92/0xa0 > __alloc_pages_nodemask+0x2df/0x320 > kmalloc_order+0x1b/0x80 > kmalloc_order_trace+0x1d/0xa0 > exfat_create_upcase_table+0x115/0x390 [exfat] > exfat_fill_super+0x3ef/0x7f0 [exfat] > ? sget_fc+0x1d0/0x240 > ? exfat_init_fs_context+0x120/0x120 [exfat] > get_tree_bdev+0x15c/0x250 > vfs_get_tree+0x25/0xb0 > do_mount+0x7c3/0xaf0 > ? copy_mount_options+0xab/0x180 > __x64_sys_mount+0x8e/0xd0 > do_syscall_64+0x4d/0x90 > entry_SYSCALL_64_after_hwframe+0x44/0xa9 > > Make the driver use vmalloc() to eliminate the issue. I have not yet received a report of the same issue. But I agree that this problem is likely to occur even if it is low probability. I think it would be more appropriate to use kvcalloc and kvfree instead. Could you send me v2 patch?
> I have not yet received a report of the same issue. > But I agree that this problem is likely to occur even if it is low > probability. Perhaps I should clarify my setup a little bit more. The issue can be reliably reproduced on my laptop. It has 8 GBs of RAM (pretty common amount nowadays) and runs an unmodified Fedora 32 kernel. Also, I use zswap, which seems to be contributing to fragmentation as well. > I think it would be more appropriate to use kvcalloc and kvfree instead. I do not think this is really needed. Upcase table allocation is relatively large (32 pages of 4KB size) and happens only once, when the drive is being mounted. Also, exfat driver does not rely on the fact that the table is physically contiguous. That said, vmalloc/vfree seems to be the best option, according to kernel's "Memory Allocation Guide". -- Artem
> > I have not yet received a report of the same issue. > > But I agree that this problem is likely to occur even if it is low > > probability. > > Perhaps I should clarify my setup a little bit more. > The issue can be reliably reproduced on my laptop. It has 8 GBs of RAM > (pretty common amount nowadays) and runs an unmodified Fedora 32 kernel. > Also, I use zswap, which seems to be contributing to fragmentation as well. > > > I think it would be more appropriate to use kvcalloc and kvfree instead. > > I do not think this is really needed. > Upcase table allocation is relatively large (32 pages of 4KB size) and > happens only once, when the drive is being mounted. Also, exfat driver > does not rely on the fact that the table is physically contiguous. > That said, vmalloc/vfree seems to be the best option, according to > kernel's "Memory Allocation Guide". The address range available for vmalloc() allocations is limited on 32-bit systems. If all kernel codes that need non-contiguous memory of the size order 1 or larger try to allocate it by only vmalloc(), the address range for vmalloc() could be insufficient. So, I think it would be better to give kmalloc() "one" chance. I know that kvmalloc() only tries kmalloc() once (noretry, nowarn) and if it fails, it immediately falls back to vmalloc(). Therefore, I think kvmalloc() and kvfree() are the best solution for solving the problem you are facing and the problem I mentioned above. Could you send me patch v3 that uses kvcalloc() and kvfree()? > > -- > Artem
diff --git a/fs/exfat/nls.c b/fs/exfat/nls.c index 675d0e7058c5..0582faf8de77 100644 --- a/fs/exfat/nls.c +++ b/fs/exfat/nls.c @@ -6,6 +6,7 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/buffer_head.h> +#include <linux/vmalloc.h> #include <asm/unaligned.h> #include "exfat_raw.h" @@ -659,7 +660,7 @@ static int exfat_load_upcase_table(struct super_block *sb, unsigned char skip = false; unsigned short *upcase_table; - upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); + upcase_table = vmalloc(UTBL_COUNT*sizeof(unsigned short)); if (!upcase_table) return -ENOMEM; @@ -715,7 +716,7 @@ static int exfat_load_default_upcase_table(struct super_block *sb) unsigned short uni = 0, *upcase_table; unsigned int index = 0; - upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL); + upcase_table = vmalloc(UTBL_COUNT*sizeof(unsigned short)); if (!upcase_table) return -ENOMEM; @@ -803,5 +804,5 @@ int exfat_create_upcase_table(struct super_block *sb) void exfat_free_upcase_table(struct exfat_sb_info *sbi) { - kfree(sbi->vol_utbl); + vfree(sbi->vol_utbl); }
The table for Unicode upcase conversion requires an order-5 allocation, which may fail on a highly-fragmented system: pool-udisksd: page allocation failure: order:5, mode:0x40dc0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), nodemask=(null),cpuset=/,mems_allowed=0 CPU: 4 PID: 3756880 Comm: pool-udisksd Tainted: G U 5.8.10-200.fc32.x86_64 #1 Hardware name: Dell Inc. XPS 13 9360/0PVG6D, BIOS 2.13.0 11/14/2019 Call Trace: dump_stack+0x6b/0x88 warn_alloc.cold+0x75/0xd9 ? _cond_resched+0x16/0x40 ? __alloc_pages_direct_compact+0x144/0x150 __alloc_pages_slowpath.constprop.0+0xcfa/0xd30 ? __schedule+0x28a/0x840 ? __wait_on_bit_lock+0x92/0xa0 __alloc_pages_nodemask+0x2df/0x320 kmalloc_order+0x1b/0x80 kmalloc_order_trace+0x1d/0xa0 exfat_create_upcase_table+0x115/0x390 [exfat] exfat_fill_super+0x3ef/0x7f0 [exfat] ? sget_fc+0x1d0/0x240 ? exfat_init_fs_context+0x120/0x120 [exfat] get_tree_bdev+0x15c/0x250 vfs_get_tree+0x25/0xb0 do_mount+0x7c3/0xaf0 ? copy_mount_options+0xab/0x180 __x64_sys_mount+0x8e/0xd0 do_syscall_64+0x4d/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Make the driver use vmalloc() to eliminate the issue. Cc: stable@vger.kernel.org # v5.7+ Signed-off-by: Artem Labazov <123321artyom@gmail.com> --- fs/exfat/nls.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)