mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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: Konstantin Khlebnikov <khlebnikov@yandex-team.ru> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
a2821e34df
commit
adb7ef600c
@ -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)
|
|||||||
/* 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 @@ out:
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
|
|
||||||
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)
|
|||||||
* 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)
|
|||||||
* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
/* 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 @@ err:
|
|||||||
* 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,
|
|||||||
* 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,
|
|||||||
* 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,
|
|||||||
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 @@ err:
|
|||||||
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,
|
|||||||
|
|
||||||
/* 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 @@ do_more:
|
|||||||
#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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user