Commit 8556e8f3 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Theodore Ts'o

ext4: Don't allow new groups to be added during block allocation

After we mark the blocks in the buddy cache as allocated,
we need to ensure that we don't reinit the buddy cache until
the block bitmap is updated.  This commit achieves this by holding
the group_info alloc_semaphore till ext4_mb_release_context
Signed-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
Cc: stable@kernel.org
parent 648f5879
...@@ -1052,6 +1052,7 @@ static void ext4_mb_release_desc(struct ext4_buddy *e4b) ...@@ -1052,6 +1052,7 @@ static void ext4_mb_release_desc(struct ext4_buddy *e4b)
if (e4b->bd_buddy_page) if (e4b->bd_buddy_page)
page_cache_release(e4b->bd_buddy_page); page_cache_release(e4b->bd_buddy_page);
/* Done with the buddy cache */ /* Done with the buddy cache */
if (e4b->alloc_semp)
up_read(e4b->alloc_semp); up_read(e4b->alloc_semp);
} }
...@@ -1371,7 +1372,9 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac, ...@@ -1371,7 +1372,9 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
get_page(ac->ac_bitmap_page); get_page(ac->ac_bitmap_page);
ac->ac_buddy_page = e4b->bd_buddy_page; ac->ac_buddy_page = e4b->bd_buddy_page;
get_page(ac->ac_buddy_page); get_page(ac->ac_buddy_page);
/* on allocation we use ac to track the held semaphore */
ac->alloc_semp = e4b->alloc_semp;
e4b->alloc_semp = NULL;
/* store last allocated for subsequent stream allocation */ /* store last allocated for subsequent stream allocation */
if ((ac->ac_flags & EXT4_MB_HINT_DATA)) { if ((ac->ac_flags & EXT4_MB_HINT_DATA)) {
spin_lock(&sbi->s_md_lock); spin_lock(&sbi->s_md_lock);
...@@ -4289,6 +4292,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, ...@@ -4289,6 +4292,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
ac->ac_pa = NULL; ac->ac_pa = NULL;
ac->ac_bitmap_page = NULL; ac->ac_bitmap_page = NULL;
ac->ac_buddy_page = NULL; ac->ac_buddy_page = NULL;
ac->alloc_semp = NULL;
ac->ac_lg = NULL; ac->ac_lg = NULL;
/* we have to define context: we'll we work with a file or /* we have to define context: we'll we work with a file or
...@@ -4469,6 +4473,8 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac) ...@@ -4469,6 +4473,8 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
} }
ext4_mb_put_pa(ac, ac->ac_sb, pa); ext4_mb_put_pa(ac, ac->ac_sb, pa);
} }
if (ac->alloc_semp)
up_read(ac->alloc_semp);
if (ac->ac_bitmap_page) if (ac->ac_bitmap_page)
page_cache_release(ac->ac_bitmap_page); page_cache_release(ac->ac_bitmap_page);
if (ac->ac_buddy_page) if (ac->ac_buddy_page)
...@@ -4569,10 +4575,14 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ...@@ -4569,10 +4575,14 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len)
ext4_mb_new_preallocation(ac); ext4_mb_new_preallocation(ac);
} }
if (likely(ac->ac_status == AC_STATUS_FOUND)) { if (likely(ac->ac_status == AC_STATUS_FOUND)) {
*errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks); *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
if (*errp == -EAGAIN) { if (*errp == -EAGAIN) {
/*
* drop the reference that we took
* in ext4_mb_use_best_found
*/
ext4_mb_release_context(ac);
ac->ac_b_ex.fe_group = 0; ac->ac_b_ex.fe_group = 0;
ac->ac_b_ex.fe_start = 0; ac->ac_b_ex.fe_start = 0;
ac->ac_b_ex.fe_len = 0; ac->ac_b_ex.fe_len = 0;
......
...@@ -195,6 +195,11 @@ struct ext4_allocation_context { ...@@ -195,6 +195,11 @@ struct ext4_allocation_context {
__u8 ac_op; /* operation, for history only */ __u8 ac_op; /* operation, for history only */
struct page *ac_bitmap_page; struct page *ac_bitmap_page;
struct page *ac_buddy_page; struct page *ac_buddy_page;
/*
* pointer to the held semaphore upon successful
* block allocation
*/
struct rw_semaphore *alloc_semp;
struct ext4_prealloc_space *ac_pa; struct ext4_prealloc_space *ac_pa;
struct ext4_locality_group *ac_lg; struct ext4_locality_group *ac_lg;
}; };
......
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