diff options
Diffstat (limited to 'fs/f2fs/gc.c')
-rw-r--r-- | fs/f2fs/gc.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 61c5f9d26018..01effd3fcb6c 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -59,7 +59,7 @@ static int gc_thread_func(void *data) if (gc_th->gc_wake) gc_th->gc_wake = false; - if (try_to_freeze()) { + if (try_to_freeze() || f2fs_readonly(sbi->sb)) { stat_other_skip_bggc_count(sbi); continue; } @@ -1797,7 +1797,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control) { int gc_type = gc_control->init_gc_type; unsigned int segno = gc_control->victim_segno; - int sec_freed = 0, seg_freed = 0, total_freed = 0; + int sec_freed = 0, seg_freed = 0, total_freed = 0, total_sec_freed = 0; int ret = 0; struct cp_control cpc; struct gc_inode_list gc_list = { @@ -1842,6 +1842,8 @@ gc_more: ret = f2fs_write_checkpoint(sbi, &cpc); if (ret) goto stop; + /* Reset due to checkpoint */ + sec_freed = 0; } } @@ -1866,15 +1868,17 @@ retry: gc_control->should_migrate_blocks); total_freed += seg_freed; - if (seg_freed == f2fs_usable_segs_in_sec(sbi, segno)) + if (seg_freed == f2fs_usable_segs_in_sec(sbi, segno)) { sec_freed++; + total_sec_freed++; + } if (gc_type == FG_GC) { sbi->cur_victim_sec = NULL_SEGNO; if (has_enough_free_secs(sbi, sec_freed, 0)) { if (!gc_control->no_bg_gc && - sec_freed < gc_control->nr_free_secs) + total_sec_freed < gc_control->nr_free_secs) goto go_gc_more; goto stop; } @@ -1901,6 +1905,8 @@ retry: ret = f2fs_write_checkpoint(sbi, &cpc); if (ret) goto stop; + /* Reset due to checkpoint */ + sec_freed = 0; } go_gc_more: segno = NULL_SEGNO; @@ -1913,7 +1919,7 @@ stop: if (gc_type == FG_GC) f2fs_unpin_all_sections(sbi, true); - trace_f2fs_gc_end(sbi->sb, ret, total_freed, sec_freed, + trace_f2fs_gc_end(sbi->sb, ret, total_freed, total_sec_freed, get_pages(sbi, F2FS_DIRTY_NODES), get_pages(sbi, F2FS_DIRTY_DENTS), get_pages(sbi, F2FS_DIRTY_IMETA), @@ -1927,7 +1933,7 @@ stop: put_gc_inode(&gc_list); if (gc_control->err_gc_skipped && !ret) - ret = sec_freed ? 0 : -EAGAIN; + ret = total_sec_freed ? 0 : -EAGAIN; return ret; } @@ -2099,8 +2105,9 @@ static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs) } } -int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count) +int f2fs_resize_fs(struct file *filp, __u64 block_count) { + struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp)); __u64 old_block_count, shrunk_blocks; struct cp_control cpc = { CP_RESIZE, 0, 0, 0 }; unsigned int secs; @@ -2138,12 +2145,18 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count) return -EINVAL; } + err = mnt_want_write_file(filp); + if (err) + return err; + shrunk_blocks = old_block_count - block_count; secs = div_u64(shrunk_blocks, BLKS_PER_SEC(sbi)); /* stop other GC */ - if (!f2fs_down_write_trylock(&sbi->gc_lock)) - return -EAGAIN; + if (!f2fs_down_write_trylock(&sbi->gc_lock)) { + err = -EAGAIN; + goto out_drop_write; + } /* stop CP to protect MAIN_SEC in free_segment_range */ f2fs_lock_op(sbi); @@ -2163,10 +2176,20 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count) out_unlock: f2fs_unlock_op(sbi); f2fs_up_write(&sbi->gc_lock); +out_drop_write: + mnt_drop_write_file(filp); if (err) return err; - freeze_super(sbi->sb); + err = freeze_super(sbi->sb); + if (err) + return err; + + if (f2fs_readonly(sbi->sb)) { + thaw_super(sbi->sb); + return -EROFS; + } + f2fs_down_write(&sbi->gc_lock); f2fs_down_write(&sbi->cp_global_sem); |