Commit adb7ef60 authored by Konstantin Khlebnikov's avatar Konstantin Khlebnikov Committed by Theodore Ts'o

ext4: use __GFP_NOFAIL in ext4_free_blocks()

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: default avatarKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent a2821e34
...@@ -815,7 +815,7 @@ static void mb_regenerate_buddy(struct ext4_buddy *e4b) ...@@ -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! * 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; ext4_group_t ngroups;
int blocksize; int blocksize;
...@@ -848,7 +848,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) ...@@ -848,7 +848,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
/* allocate buffer_heads to read bitmaps */ /* allocate buffer_heads to read bitmaps */
if (groups_per_page > 1) { if (groups_per_page > 1) {
i = sizeof(struct buffer_head *) * groups_per_page; i = sizeof(struct buffer_head *) * groups_per_page;
bh = kzalloc(i, GFP_NOFS); bh = kzalloc(i, gfp);
if (bh == NULL) { if (bh == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -983,7 +983,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) ...@@ -983,7 +983,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
* are on the same page e4b->bd_buddy_page is NULL and return value is 0. * 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, 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; struct inode *inode = EXT4_SB(sb)->s_buddy_cache;
int block, pnum, poff; int block, pnum, poff;
...@@ -1002,7 +1002,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, ...@@ -1002,7 +1002,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
block = group * 2; block = group * 2;
pnum = block / blocks_per_page; pnum = block / blocks_per_page;
poff = 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) if (!page)
return -ENOMEM; return -ENOMEM;
BUG_ON(page->mapping != inode->i_mapping); BUG_ON(page->mapping != inode->i_mapping);
...@@ -1016,7 +1016,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb, ...@@ -1016,7 +1016,7 @@ static int ext4_mb_get_buddy_page_lock(struct super_block *sb,
block++; block++;
pnum = block / blocks_per_page; 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) if (!page)
return -ENOMEM; return -ENOMEM;
BUG_ON(page->mapping != inode->i_mapping); BUG_ON(page->mapping != inode->i_mapping);
...@@ -1042,7 +1042,7 @@ static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b) ...@@ -1042,7 +1042,7 @@ static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b)
* calling this routine! * calling this routine!
*/ */
static noinline_for_stack 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; struct ext4_group_info *this_grp;
...@@ -1062,7 +1062,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ...@@ -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 * The call to ext4_mb_get_buddy_page_lock will mark the
* page accessed. * 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)) { if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) {
/* /*
* somebody initialized the group * somebody initialized the group
...@@ -1072,7 +1072,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ...@@ -1072,7 +1072,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
} }
page = e4b.bd_bitmap_page; page = e4b.bd_bitmap_page;
ret = ext4_mb_init_cache(page, NULL); ret = ext4_mb_init_cache(page, NULL, gfp);
if (ret) if (ret)
goto err; goto err;
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
...@@ -1091,7 +1091,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ...@@ -1091,7 +1091,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
} }
/* init buddy cache */ /* init buddy cache */
page = e4b.bd_buddy_page; 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) if (ret)
goto err; goto err;
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
...@@ -1109,8 +1109,8 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) ...@@ -1109,8 +1109,8 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
* calling this routine! * calling this routine!
*/ */
static noinline_for_stack int static noinline_for_stack int
ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group,
struct ext4_buddy *e4b) struct ext4_buddy *e4b, gfp_t gfp)
{ {
int blocks_per_page; int blocks_per_page;
int block; int block;
...@@ -1140,7 +1140,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ...@@ -1140,7 +1140,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
* we need full data about the group * we need full data about the group
* to make a good selection * to make a good selection
*/ */
ret = ext4_mb_init_group(sb, group); ret = ext4_mb_init_group(sb, group, gfp);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1168,11 +1168,11 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ...@@ -1168,11 +1168,11 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
* wait for it to initialize. * wait for it to initialize.
*/ */
page_cache_release(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) { if (page) {
BUG_ON(page->mapping != inode->i_mapping); BUG_ON(page->mapping != inode->i_mapping);
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
ret = ext4_mb_init_cache(page, NULL); ret = ext4_mb_init_cache(page, NULL, gfp);
if (ret) { if (ret) {
unlock_page(page); unlock_page(page);
goto err; goto err;
...@@ -1204,11 +1204,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ...@@ -1204,11 +1204,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
if (page == NULL || !PageUptodate(page)) { if (page == NULL || !PageUptodate(page)) {
if (page) if (page)
page_cache_release(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) { if (page) {
BUG_ON(page->mapping != inode->i_mapping); BUG_ON(page->mapping != inode->i_mapping);
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
ret = ext4_mb_init_cache(page, e4b->bd_bitmap); ret = ext4_mb_init_cache(page, e4b->bd_bitmap,
gfp);
if (ret) { if (ret) {
unlock_page(page); unlock_page(page);
goto err; goto err;
...@@ -1247,6 +1248,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, ...@@ -1247,6 +1248,12 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
return ret; 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) static void ext4_mb_unload_buddy(struct ext4_buddy *e4b)
{ {
if (e4b->bd_bitmap_page) if (e4b->bd_bitmap_page)
...@@ -2045,7 +2052,7 @@ static int ext4_mb_good_group(struct ext4_allocation_context *ac, ...@@ -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 */ /* We only do this if the grp has never been initialized */
if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { 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) if (ret)
return ret; return ret;
} }
...@@ -4804,7 +4811,9 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4804,7 +4811,9 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
#endif #endif
trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters); 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) if (err)
goto error_return; goto error_return;
...@@ -5211,7 +5220,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) ...@@ -5211,7 +5220,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range)
grp = ext4_get_group_info(sb, group); grp = ext4_get_group_info(sb, group);
/* We only do this if the grp has never been initialized */ /* We only do this if the grp has never been initialized */
if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { 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) if (ret)
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment