From bc9f6d1097e08bd6f35a1a3d4cd8d5860b37714b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 13 Mar 2016 17:38:42 -0400 Subject: [PATCH] add patch use-GFP_NOFAIL-in-ext4_free_blocks --- series | 1 + timestamps | 5 +- use-GFP_NOFAIL-in-ext4_free_blocks | 193 +++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 use-GFP_NOFAIL-in-ext4_free_blocks diff --git a/series b/series index 0a68cee1..7dc5fc70 100644 --- a/series +++ b/series @@ -42,6 +42,7 @@ drop-unneeded-BUFFER_TRACE-in-ext4_delete_inline_entry fix-NULL-pointer-dereference-in-ext4_mark_inode_dirty print-mountopt-data_err=abort-correctly fix-compile-error-while-opening-the-macros-DOUBLE_CHECK +use-GFP_NOFAIL-in-ext4_free_blocks ########################################## # unstable patches diff --git a/timestamps b/timestamps index 33a17cb6..2939e17c 100755 --- a/timestamps +++ b/timestamps @@ -64,6 +64,7 @@ touch -d @1457587197 stable-boundary touch -d @1457836832 fix-NULL-pointer-dereference-in-ext4_mark_inode_dirty touch -d @1457837750 print-mountopt-data_err=abort-correctly touch -d @1457903892 fix-compile-error-while-opening-the-macros-DOUBLE_CHECK -touch -d @1457903934 series -touch -d @1457903940 status +touch -d @1457904546 use-GFP_NOFAIL-in-ext4_free_blocks touch -d @1457904553 timestamps +touch -d @1457904577 series +touch -d @1457904580 status diff --git a/use-GFP_NOFAIL-in-ext4_free_blocks b/use-GFP_NOFAIL-in-ext4_free_blocks new file mode 100644 index 00000000..aa1300cf --- /dev/null +++ b/use-GFP_NOFAIL-in-ext4_free_blocks @@ -0,0 +1,193 @@ +ext4: use __GFP_NOFAIL in ext4_free_blocks() + +From: Konstantin Khlebnikov + +This might be unexpected but pages allocated for sbi->s_buddy_cache are +charged to current memory cgroup. So, GFP_NOFS allocation could fail if +current task has been killed by OOM or if current memory cgroup has no +free memory left. Block allocator cannot handle such failures here yet. + +Signed-off-by: Konstantin Khlebnikov +Signed-off-by: Theodore Ts'o +--- + fs/ext4/mballoc.c | 47 ++++++++++++++++++++++++++++------------------- + 1 file changed, 28 insertions(+), 19 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 4424b7bf8ac6..8b7e573eaf97 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -815,7 +815,7 @@ static void mb_regenerate_buddy(struct ext4_buddy *e4b) + * for this page; do not hold this lock when calling this routine! + */ + +-static int ext4_mb_init_cache(struct page *page, char *incore) ++static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp) + { + ext4_group_t ngroups; + int blocksize; +@@ -848,7 +848,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) + /* allocate buffer_heads to read bitmaps */ + if (groups_per_page > 1) { + i = sizeof(struct buffer_head *) * groups_per_page; +- bh = kzalloc(i, GFP_NOFS); ++ bh = kzalloc(i, gfp); + if (bh == NULL) { + err = -ENOMEM; + goto out; +@@ -983,7 +983,7 @@ out: + * are on the same page e4b->bd_buddy_page is NULL and return value is 0. + */ + static int ext4_mb_get_buddy_page_lock(struct super_block *sb, +- ext4_group_t group, struct ext4_buddy *e4b) ++ ext4_group_t group, struct ext4_buddy *e4b, gfp_t gfp) + { + struct inode *inode = EXT4_SB(sb)->s_buddy_cache; + int block, pnum, poff; +@@ -1002,7 +1002,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, + block = group * 2; + pnum = block / blocks_per_page; + poff = block % blocks_per_page; +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ page = find_or_create_page(inode->i_mapping, pnum, gfp); + if (!page) + return -ENOMEM; + BUG_ON(page->mapping != inode->i_mapping); +@@ -1016,7 +1016,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, + + block++; + pnum = block / blocks_per_page; +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ page = find_or_create_page(inode->i_mapping, pnum, gfp); + if (!page) + return -ENOMEM; + BUG_ON(page->mapping != inode->i_mapping); +@@ -1042,7 +1042,7 @@ static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b) + * calling this routine! + */ + static noinline_for_stack +-int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ++int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) + { + + struct ext4_group_info *this_grp; +@@ -1062,7 +1062,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) + * The call to ext4_mb_get_buddy_page_lock will mark the + * page accessed. + */ +- ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b); ++ ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b, gfp); + if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) { + /* + * somebody initialized the group +@@ -1072,7 +1072,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) + } + + page = e4b.bd_bitmap_page; +- ret = ext4_mb_init_cache(page, NULL); ++ ret = ext4_mb_init_cache(page, NULL, gfp); + if (ret) + goto err; + if (!PageUptodate(page)) { +@@ -1091,7 +1091,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) + } + /* init buddy cache */ + page = e4b.bd_buddy_page; +- ret = ext4_mb_init_cache(page, e4b.bd_bitmap); ++ ret = ext4_mb_init_cache(page, e4b.bd_bitmap, gfp); + if (ret) + goto err; + if (!PageUptodate(page)) { +@@ -1109,8 +1109,8 @@ err: + * calling this routine! + */ + static noinline_for_stack int +-ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, +- struct ext4_buddy *e4b) ++ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, ++ struct ext4_buddy *e4b, gfp_t gfp) + { + int blocks_per_page; + int block; +@@ -1140,7 +1140,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + * we need full data about the group + * to make a good selection + */ +- ret = ext4_mb_init_group(sb, group); ++ ret = ext4_mb_init_group(sb, group, gfp); + if (ret) + return ret; + } +@@ -1168,11 +1168,11 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + * wait for it to initialize. + */ + page_cache_release(page); +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ page = find_or_create_page(inode->i_mapping, pnum, gfp); + if (page) { + BUG_ON(page->mapping != inode->i_mapping); + if (!PageUptodate(page)) { +- ret = ext4_mb_init_cache(page, NULL); ++ ret = ext4_mb_init_cache(page, NULL, gfp); + if (ret) { + unlock_page(page); + goto err; +@@ -1204,11 +1204,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, + if (page == NULL || !PageUptodate(page)) { + if (page) + page_cache_release(page); +- page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS); ++ page = find_or_create_page(inode->i_mapping, pnum, gfp); + if (page) { + BUG_ON(page->mapping != inode->i_mapping); + if (!PageUptodate(page)) { +- ret = ext4_mb_init_cache(page, e4b->bd_bitmap); ++ ret = ext4_mb_init_cache(page, e4b->bd_bitmap, ++ gfp); + if (ret) { + unlock_page(page); + goto err; +@@ -1247,6 +1248,12 @@ err: + return ret; + } + ++static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ++ struct ext4_buddy *e4b) ++{ ++ return ext4_mb_load_buddy_gfp(sb, group, e4b, GFP_NOFS); ++} ++ + static void ext4_mb_unload_buddy(struct ext4_buddy *e4b) + { + if (e4b->bd_bitmap_page) +@@ -2045,7 +2052,7 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, + + /* We only do this if the grp has never been initialized */ + if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { +- int ret = ext4_mb_init_group(ac->ac_sb, group); ++ int ret = ext4_mb_init_group(ac->ac_sb, group, GFP_NOFS); + if (ret) + return ret; + } +@@ -4815,7 +4822,9 @@ do_more: + #endif + trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters); + +- err = ext4_mb_load_buddy(sb, block_group, &e4b); ++ /* __GFP_NOFAIL: retry infinitely, ignore TIF_MEMDIE and memcg limit. */ ++ err = ext4_mb_load_buddy_gfp(sb, block_group, &e4b, ++ GFP_NOFS|__GFP_NOFAIL); + if (err) + goto error_return; + +@@ -5217,7 +5226,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + grp = ext4_get_group_info(sb, group); + /* We only do this if the grp has never been initialized */ + if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { +- ret = ext4_mb_init_group(sb, group); ++ ret = ext4_mb_init_group(sb, group, GFP_NOFS); + if (ret) + break; + } + + -- 2.11.4.GIT