aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/mballoc.c16
-rw-r--r--fs/ext4/mballoc.h5
2 files changed, 18 insertions, 3 deletions
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 7d7f6f91d555..0c7e247f714c 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -1052,7 +1052,8 @@ static void ext4_mb_release_desc(struct ext4_buddy *e4b)
1052 if (e4b->bd_buddy_page) 1052 if (e4b->bd_buddy_page)
1053 page_cache_release(e4b->bd_buddy_page); 1053 page_cache_release(e4b->bd_buddy_page);
1054 /* Done with the buddy cache */ 1054 /* Done with the buddy cache */
1055 up_read(e4b->alloc_semp); 1055 if (e4b->alloc_semp)
1056 up_read(e4b->alloc_semp);
1056} 1057}
1057 1058
1058 1059
@@ -1371,7 +1372,9 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
1371 get_page(ac->ac_bitmap_page); 1372 get_page(ac->ac_bitmap_page);
1372 ac->ac_buddy_page = e4b->bd_buddy_page; 1373 ac->ac_buddy_page = e4b->bd_buddy_page;
1373 get_page(ac->ac_buddy_page); 1374 get_page(ac->ac_buddy_page);
1374 1375 /* on allocation we use ac to track the held semaphore */
1376 ac->alloc_semp = e4b->alloc_semp;
1377 e4b->alloc_semp = NULL;
1375 /* store last allocated for subsequent stream allocation */ 1378 /* store last allocated for subsequent stream allocation */
1376 if ((ac->ac_flags & EXT4_MB_HINT_DATA)) { 1379 if ((ac->ac_flags & EXT4_MB_HINT_DATA)) {
1377 spin_lock(&sbi->s_md_lock); 1380 spin_lock(&sbi->s_md_lock);
@@ -4289,6 +4292,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
4289 ac->ac_pa = NULL; 4292 ac->ac_pa = NULL;
4290 ac->ac_bitmap_page = NULL; 4293 ac->ac_bitmap_page = NULL;
4291 ac->ac_buddy_page = NULL; 4294 ac->ac_buddy_page = NULL;
4295 ac->alloc_semp = NULL;
4292 ac->ac_lg = NULL; 4296 ac->ac_lg = NULL;
4293 4297
4294 /* we have to define context: we'll we work with a file or 4298 /* 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 } 4473 }
4470 ext4_mb_put_pa(ac, ac->ac_sb, pa); 4474 ext4_mb_put_pa(ac, ac->ac_sb, pa);
4471 } 4475 }
4476 if (ac->alloc_semp)
4477 up_read(ac->alloc_semp);
4472 if (ac->ac_bitmap_page) 4478 if (ac->ac_bitmap_page)
4473 page_cache_release(ac->ac_bitmap_page); 4479 page_cache_release(ac->ac_bitmap_page);
4474 if (ac->ac_buddy_page) 4480 if (ac->ac_buddy_page)
@@ -4569,10 +4575,14 @@ repeat:
4569 ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) 4575 ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len)
4570 ext4_mb_new_preallocation(ac); 4576 ext4_mb_new_preallocation(ac);
4571 } 4577 }
4572
4573 if (likely(ac->ac_status == AC_STATUS_FOUND)) { 4578 if (likely(ac->ac_status == AC_STATUS_FOUND)) {
4574 *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks); 4579 *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_blks);
4575 if (*errp == -EAGAIN) { 4580 if (*errp == -EAGAIN) {
4581 /*
4582 * drop the reference that we took
4583 * in ext4_mb_use_best_found
4584 */
4585 ext4_mb_release_context(ac);
4576 ac->ac_b_ex.fe_group = 0; 4586 ac->ac_b_ex.fe_group = 0;
4577 ac->ac_b_ex.fe_start = 0; 4587 ac->ac_b_ex.fe_start = 0;
4578 ac->ac_b_ex.fe_len = 0; 4588 ac->ac_b_ex.fe_len = 0;
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index 95d4c7f29a8a..10a2921baf14 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -195,6 +195,11 @@ struct ext4_allocation_context {
195 __u8 ac_op; /* operation, for history only */ 195 __u8 ac_op; /* operation, for history only */
196 struct page *ac_bitmap_page; 196 struct page *ac_bitmap_page;
197 struct page *ac_buddy_page; 197 struct page *ac_buddy_page;
198 /*
199 * pointer to the held semaphore upon successful
200 * block allocation
201 */
202 struct rw_semaphore *alloc_semp;
198 struct ext4_prealloc_space *ac_pa; 203 struct ext4_prealloc_space *ac_pa;
199 struct ext4_locality_group *ac_lg; 204 struct ext4_locality_group *ac_lg;
200}; 205};