f2fs: check return value of freeze_super()
[linux-2.6-microblaze.git] / fs / f2fs / gc.c
index 61c5f9d..01effd3 100644 (file)
@@ -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);