[Devel] [PATCH rh7 1/2] mm: fix division by zero in dcache_is_low()
Andrey Ryabinin
aryabinin at virtuozzo.com
Tue Jul 25 14:28:35 MSK 2017
At first we check if sysctl_vfs_cache_min_ratio <= 0 and
if it's not we use it as denominator. If sysctl_vfs_cache_min_ratio
set to zero after the check but before division it would cause
division by zero, hence the kernel crash:
divide error: 0000 [#1] SMP
RIP: 0010:[<ffffffff81206fb5>] [<ffffffff81206fb5>] mem_cgroup_dcache_is_low+0x55/0x80
Call Trace:
super_cache_count+0xf4/0x180
shrink_slab+0x166/0x410
shrink_zone+0x11a/0x2d0
do_try_to_free_pages+0x1a0/0x570
try_to_free_mem_cgroup_pages+0xc6/0x160
mem_cgroup_reclaim+0x6b/0x180 [kpatch_cumulative_26_1_r1]
try_charge+0x18d/0x4e0 [kpatch_cumulative_26_1_r1]
mem_cgroup_try_charge+0x78/0x130
add_to_page_cache_locked+0x97/0x300
alloc_pages_current+0xaa/0x170
add_to_page_cache_lru+0x37/0xb0
grab_cache_page_write_begin+0x89/0xd0
ext4_da_write_begin+0xad/0x3a0 [ext4]
generic_file_buffered_write_iter+0x107/0x280
generic_file_write_iter+0x183/0x3c0
generic_file_aio_write+0x8b/0xb0
generic_file_aio_write+0x59/0xa0
ext4_file_write+0xdb/0x470 [ext4]
set_fd_set+0x21/0x30
core_sys_select+0x245/0x300
do_sync_write+0x90/0xe0
vfs_write+0xbd/0x1e0
SyS_write+0x7f/0xe0
system_call_fastpath+0x16/0x1b
Use READ_ONCE to cache sysctl_vfs_cache_min_ratio value into the
local variable, so we could use the cached value and not worry
about racy sysctl_vfs_cache_min_ratio updates.
https://jira.sw.ru/browse/PSBM-69018
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
fs/super.c | 5 +++--
mm/memcontrol.c | 6 +++++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/fs/super.c b/fs/super.c
index 7470621cbf4..9915a9bcd3a 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -51,8 +51,9 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = {
static bool dcache_is_low(struct mem_cgroup *memcg)
{
unsigned long anon, file, dcache;
+ int vfs_cache_min_ratio = READ_ONCE(sysctl_vfs_cache_min_ratio);
- if (sysctl_vfs_cache_min_ratio <= 0)
+ if (vfs_cache_min_ratio <= 0)
return false;
if (memcg)
@@ -62,7 +63,7 @@ static bool dcache_is_low(struct mem_cgroup *memcg)
file = global_page_state(NR_FILE_PAGES);
dcache = global_page_state(NR_SLAB_RECLAIMABLE);
- return dcache / sysctl_vfs_cache_min_ratio <
+ return dcache / vfs_cache_min_ratio <
(anon + file + dcache) / 100;
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index b1bc0924f6d..9678957bf22 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1588,12 +1588,16 @@ int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec)
bool mem_cgroup_dcache_is_low(struct mem_cgroup *memcg)
{
unsigned long anon, file, dcache;
+ int vfs_cache_min_ratio = READ_ONCE(sysctl_vfs_cache_min_ratio);
+
+ if (vfs_cache_min_ratio <= 0)
+ return false;
anon = mem_cgroup_read_stat(memcg, MEM_CGROUP_STAT_RSS);
file = mem_cgroup_read_stat(memcg, MEM_CGROUP_STAT_CACHE);
dcache = mem_cgroup_read_stat(memcg, MEM_CGROUP_STAT_SLAB_RECLAIMABLE);
- return dcache / sysctl_vfs_cache_min_ratio <
+ return dcache / vfs_cache_min_ratio <
(anon + file + dcache) / 100;
}
--
2.13.0
More information about the Devel
mailing list