WIP: Add partial shrinking support to f2fs
authorDaniel Rosenberg <drosen@google.com>
Wed, 9 May 2018 02:48:33 +0000 (19:48 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 21 Nov 2018 19:38:23 +0000 (11:38 -0800)
allow 'safe' resizing leaving the metadata nearly unchanged.

Will likely need to adjust growing for the case where a fs
had previously shrunk without altering data, and the newly grown
fs would be smaller than the original. Probably makes sense to
case it out into metadata size changes, instead of fs size changes

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
fsck/defrag.c
fsck/fsck.c
fsck/fsck.h
fsck/main.c
fsck/mount.c
fsck/resize.c
fsck/sload.c
include/f2fs_fs.h

index bea0293..fc6b7cf 100644 (file)
@@ -89,7 +89,7 @@ int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int lef
        }
 
        /* update curseg info; can update sit->types */
-       move_curseg_info(sbi, to);
+       move_curseg_info(sbi, to, left);
        zero_journal_entries(sbi);
        write_curseg_info(sbi);
 
index ca4e74e..e4b01d8 100644 (file)
@@ -2665,7 +2665,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
                        fix_nat_entries(sbi);
                        rewrite_sit_area_bitmap(sbi);
                        if (check_curseg_offset(sbi)) {
-                               move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
+                               move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
                                write_curseg_info(sbi);
                                flush_curseg_sit_entries(sbi);
                        }
index bbcf589..6042e68 100644 (file)
@@ -174,7 +174,7 @@ extern void f2fs_do_umount(struct f2fs_sb_info *);
 extern void flush_journal_entries(struct f2fs_sb_info *);
 extern void zero_journal_entries(struct f2fs_sb_info *);
 extern void flush_sit_entries(struct f2fs_sb_info *);
-extern void move_curseg_info(struct f2fs_sb_info *, u64);
+extern void move_curseg_info(struct f2fs_sb_info *, u64, int);
 extern void write_curseg_info(struct f2fs_sb_info *);
 extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int);
 extern void write_checkpoint(struct f2fs_sb_info *);
index 399397b..3364f2d 100644 (file)
@@ -102,6 +102,7 @@ void resize_usage()
        MSG(0, "\nUsage: resize.f2fs [options] device\n");
        MSG(0, "[options]:\n");
        MSG(0, "  -d debug level [default:0]\n");
+       MSG(0, "  -s safe resize (Does not resize metadata)");
        MSG(0, "  -t target sectors [default: device size]\n");
        MSG(0, "  -V print the version number and exit\n");
        exit(1);
@@ -424,7 +425,7 @@ void f2fs_parse_options(int argc, char *argv[])
                                break;
                }
        } else if (!strcmp("resize.f2fs", prog)) {
-               const char *option_string = "d:t:V";
+               const char *option_string = "d:st:V";
 
                c.func = RESIZE;
                while ((option = getopt(argc, argv, option_string)) != EOF) {
@@ -440,6 +441,9 @@ void f2fs_parse_options(int argc, char *argv[])
                                MSG(0, "Info: Debug level = %d\n",
                                                        c.dbg_lv);
                                break;
+                       case 's':
+                               c.safe_resize = 1;
+                               break;
                        case 't':
                                if (strncmp(optarg, "0x", 2))
                                        ret = sscanf(optarg, "%"PRIu64"",
@@ -706,8 +710,6 @@ out_range:
 
 static int do_resize(struct f2fs_sb_info *sbi)
 {
-       struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
-
        if (!c.target_sectors)
                c.target_sectors = c.total_sectors;
 
@@ -717,12 +719,6 @@ static int do_resize(struct f2fs_sb_info *sbi)
                return -1;
        }
 
-       /* may different sector size */
-       if ((c.target_sectors * c.sector_size >>
-                       get_sb(log_blocksize)) <= get_sb(block_count)) {
-               ASSERT_MSG("Nothing to resize, now only support resize to expand\n");
-               return -1;
-       }
        return f2fs_resize(sbi);
 }
 
index 21e1dc8..0230a2e 100644 (file)
@@ -2056,6 +2056,8 @@ int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
        u64 end_blkaddr = (get_sb(segment_count_main) <<
                        get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr);
 
+       if (*to > 0)
+               *to -= left;
        if (get_free_segments(sbi) <= SM_I(sbi)->reserved_segments + 1)
                not_enough = 1;
 
@@ -2100,7 +2102,7 @@ int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
        return -1;
 }
 
-void move_curseg_info(struct f2fs_sb_info *sbi, u64 from)
+void move_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left)
 {
        int i, ret;
 
@@ -2117,7 +2119,7 @@ void move_curseg_info(struct f2fs_sb_info *sbi, u64 from)
                ASSERT(ret >= 0);
 
                to = from;
-               ret = find_next_free_block(sbi, &to, 0, i);
+               ret = find_next_free_block(sbi, &to, left, i);
                ASSERT(ret == 0);
 
                old_segno = curseg->segno;
index c0a2641..e9612b3 100644 (file)
@@ -37,6 +37,9 @@ static int get_new_sb(struct f2fs_super_block *sb)
                                zone_align_start_offset) / segment_size_bytes /
                                c.segs_per_sec * c.segs_per_sec);
 
+       if (c.safe_resize)
+               goto safe_resize;
+
        blocks_for_sit = SIZE_ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK);
        sit_segments = SEG_ALIGN(blocks_for_sit);
        set_sb(segment_count_sit, sit_segments * 2);
@@ -129,6 +132,7 @@ static int get_new_sb(struct f2fs_super_block *sb)
        set_sb(main_blkaddr, get_sb(ssa_blkaddr) + get_sb(segment_count_ssa) *
                         blks_per_seg);
 
+safe_resize:
        set_sb(segment_count_main, get_sb(segment_count) -
                        (get_sb(segment_count_ckpt) +
                         get_sb(segment_count_sit) +
@@ -573,7 +577,23 @@ static void rebuild_checkpoint(struct f2fs_sb_info *sbi,
        DBG(0, "Info: Done to rebuild checkpoint blocks\n");
 }
 
-int f2fs_resize(struct f2fs_sb_info *sbi)
+static void rebuild_superblock(struct f2fs_super_block *new_sb)
+{
+       int index, ret;
+       u_int8_t *buf;
+
+       buf = calloc(BLOCK_SZ, 1);
+
+       memcpy(buf + F2FS_SUPER_OFFSET, new_sb, sizeof(*new_sb));
+       for (index = 0; index < 2; index++) {
+               ret = dev_write_block(buf, index);
+               ASSERT(ret >= 0);
+       }
+       free(buf);
+       DBG(0, "Info: Done to rebuild superblock\n");
+}
+
+static int f2fs_resize_grow(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
        struct f2fs_super_block new_sb_raw;
@@ -627,3 +647,86 @@ int f2fs_resize(struct f2fs_sb_info *sbi)
        write_superblock(new_sb);
        return 0;
 }
+
+static int f2fs_resize_shrink(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
+       struct f2fs_super_block new_sb_raw;
+       struct f2fs_super_block *new_sb = &new_sb_raw;
+       block_t old_end_blkaddr, old_main_blkaddr;
+       block_t new_end_blkaddr, new_main_blkaddr, tmp_end_blkaddr;
+       unsigned int offset;
+       int err = -1;
+
+       /* flush NAT/SIT journal entries */
+       flush_journal_entries(sbi);
+
+       memcpy(new_sb, F2FS_RAW_SUPER(sbi), sizeof(*new_sb));
+       if (get_new_sb(new_sb))
+               return -1;
+
+       /* check nat availability */
+       if (get_sb(segment_count_nat) > get_newsb(segment_count_nat)) {
+               err = shrink_nats(sbi, new_sb);
+               if (err) {
+                       MSG(0, "\tError: Failed to shrink NATs\n");
+                       return err;
+               }
+       }
+
+       print_raw_sb_info(sb);
+       print_raw_sb_info(new_sb);
+
+       old_main_blkaddr = get_sb(main_blkaddr);
+       new_main_blkaddr = get_newsb(main_blkaddr);
+       offset = old_main_blkaddr - new_main_blkaddr;
+       old_end_blkaddr = (get_sb(segment_count_main) <<
+                       get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr);
+       new_end_blkaddr = (get_newsb(segment_count_main) <<
+                       get_newsb(log_blocks_per_seg)) + get_newsb(main_blkaddr);
+
+       tmp_end_blkaddr = new_end_blkaddr + offset;
+       err = f2fs_defragment(sbi, tmp_end_blkaddr,
+                               old_end_blkaddr - tmp_end_blkaddr,
+                               tmp_end_blkaddr, 1);
+       MSG(0, "Try to do defragement: %s\n", err ? "Insufficient Space": "Done");
+
+       if (err) {
+               return -ENOSPC;
+       }
+
+       rebuild_superblock(new_sb);
+       rebuild_checkpoint(sbi, new_sb, 0);
+       /*if (!c.safe_resize) {
+               migrate_sit(sbi, new_sb, offset_seg);
+               migrate_nat(sbi, new_sb);
+               migrate_ssa(sbi, new_sb, offset_seg);
+       }*/
+
+       /* move whole data region */
+       //if (err)
+       //      migrate_main(sbi, offset);
+       return 0;
+}
+
+int f2fs_resize(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
+
+       /* may different sector size */
+       if ((c.target_sectors * c.sector_size >>
+                       get_sb(log_blocksize)) < get_sb(block_count))
+               if (!c.safe_resize) {
+                       ASSERT_MSG("Nothing to resize, now only supports resizing with safe resize flag\n");
+                       return -1;
+               } else {
+                       return f2fs_resize_shrink(sbi);
+               }
+       else if ((c.target_sectors * c.sector_size >>
+                       get_sb(log_blocksize)) > get_sb(block_count))
+               return f2fs_resize_grow(sbi);
+       else {
+               MSG(0, "Nothing to resize.\n");
+               return 0;
+       }
+}
index e9b12e3..f5a4651 100644 (file)
@@ -318,7 +318,7 @@ int f2fs_sload(struct f2fs_sb_info *sbi)
        }
 
        /* update curseg info; can update sit->types */
-       move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
+       move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
        zero_journal_entries(sbi);
        write_curseg_info(sbi);
 
index e3b4529..e2a5767 100644 (file)
@@ -404,6 +404,9 @@ struct f2fs_configuration {
        int nr_opt;
 #endif
 
+       /* resize parameters */
+       int safe_resize;
+
        /* precomputed fs UUID checksum for seeding other checksums */
        u_int32_t chksum_seed;
 };