diff options
Diffstat (limited to 'fs/ext4/mballoc.c')
-rw-r--r-- | fs/ext4/mballoc.c | 16 |
1 files changed, 13 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; |