diff options
author | Jaegeuk Kim <jaegeuk@google.com> | 2021-06-03 09:28:09 -0700 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@google.com> | 2021-06-03 12:39:21 -0700 |
commit | a3965e992fdfb90af0bdd079a40551196bbc3b39 (patch) | |
tree | 1908951ac5c6d879e06132ab33fdae3e86cf96ee | |
parent | f7d3db3bab3979ed135f4e811ca9c856362a55bc (diff) | |
download | f2fs-tools-android12-dev.tar.gz |
Merge remote-tracking branch 'aosp/upstream-master' into aospandroid12-dev
* aosp/upstream-master:
sload.f2fs: use F2FS_COMPRESS_RELEASED instead of IMMUTABLE bit
f2fs-tools: support small RO partition
fsck.f2fs: add "-l" to show the layout information
f2fs_io: add to show immutable bit
tools: Introduce f2fslabel
f2fs-tools: correct get kernel version logic
dump.f2fs: fix memory leak caused by dump_node_blk()
fsck.f2fs: fix memory leak caused by fsck_chk_orphan_node()
mkfs.f2fs: fix memory leak in not enough segments error path
resize.f2fs: fix memory leak caused by migrate_nat()
f2fs_io: split definition check for crypto ioctl
fsck.f2fs: update kernel version in superblock on forced check
Bug: 188928405
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: I492edc2449286c7cd7f1121456f5a1821eb7a6c7
Merged-In: I492edc2449286c7cd7f1121456f5a1821eb7a6c7
-rw-r--r-- | METADATA | 4 | ||||
-rw-r--r-- | fsck/Makefile.am | 1 | ||||
-rw-r--r-- | fsck/dump.c | 3 | ||||
-rw-r--r-- | fsck/fsck.c | 28 | ||||
-rw-r--r-- | fsck/main.c | 90 | ||||
-rw-r--r-- | fsck/mount.c | 76 | ||||
-rw-r--r-- | fsck/node.c | 5 | ||||
-rw-r--r-- | fsck/resize.c | 1 | ||||
-rw-r--r-- | fsck/segment.c | 11 | ||||
-rw-r--r-- | include/f2fs_fs.h | 39 | ||||
-rw-r--r-- | lib/libf2fs.c | 2 | ||||
-rw-r--r-- | lib/libf2fs_io.c | 9 | ||||
-rw-r--r-- | man/Makefile.am | 2 | ||||
-rw-r--r-- | man/f2fslabel.8 | 33 | ||||
-rw-r--r-- | mkfs/f2fs_format.c | 119 | ||||
-rw-r--r-- | tools/f2fs_io/f2fs_io.c | 14 | ||||
-rw-r--r-- | tools/f2fs_io/f2fs_io.h | 8 |
17 files changed, 364 insertions, 81 deletions
@@ -12,7 +12,7 @@ third_party { license_type: RESTRICTED last_upgrade_date { year: 2021 - month: 4 - day: 24 + month: 6 + day: 3 } } diff --git a/fsck/Makefile.am b/fsck/Makefile.am index e7d599c..e31d416 100644 --- a/fsck/Makefile.am +++ b/fsck/Makefile.am @@ -18,3 +18,4 @@ install-data-hook: ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/defrag.f2fs ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/resize.f2fs ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/sload.f2fs + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/f2fslabel diff --git a/fsck/dump.c b/fsck/dump.c index 055ce09..042a2e5 100644 --- a/fsck/dump.c +++ b/fsck/dump.c @@ -278,7 +278,7 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype, if (nid == 0) { *ofs += skip; - return; + goto out; } for (i = 0; i < idx; i++, (*ofs)++) { @@ -297,6 +297,7 @@ static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype, break; } } +out: free(node_blk); } diff --git a/fsck/fsck.c b/fsck/fsck.c index e526720..80a6d8e 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -144,6 +144,7 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid) static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, u32 blk_addr) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_summary_block *sum_blk; struct f2fs_summary *sum_entry; struct seg_entry * se; @@ -151,6 +152,9 @@ static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, int need_fix = 0, ret = 0; int type; + if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) + return 0; + segno = GET_SEGNO(sbi, blk_addr); offset = OFFSET_IN_SEG(sbi, blk_addr); @@ -261,6 +265,7 @@ out: static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, u32 parent_nid, u16 idx_in_node, u8 version) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_summary_block *sum_blk; struct f2fs_summary *sum_entry; struct seg_entry * se; @@ -268,6 +273,9 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, int need_fix = 0, ret = 0; int type; + if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) + return 0; + segno = GET_SEGNO(sbi, blk_addr); offset = OFFSET_IN_SEG(sbi, blk_addr); @@ -1780,8 +1788,11 @@ int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { get_node_info(sbi, ino, &ni); if (!IS_VALID_NID(sbi, ino) || - !IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) + !IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) { + free(orphan_blk); + free(new_blk); return -EINVAL; + } continue; } @@ -2369,10 +2380,15 @@ static int check_curseg_write_pointer(struct f2fs_sb_info *UNUSED(sbi), int check_curseg_offset(struct f2fs_sb_info *sbi, int type) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct curseg_info *curseg = CURSEG_I(sbi, type); struct seg_entry *se; int j, nblocks; + if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO) && + type != CURSEG_HOT_DATA && type != CURSEG_HOT_NODE) + return 0; + if ((curseg->next_blkoff >> 3) >= SIT_VBLOCK_MAP_SIZE) { ASSERT_MSG("Next block offset:%u is invalid, type:%d", curseg->next_blkoff, type); @@ -2955,6 +2971,7 @@ void fsck_chk_and_fix_write_pointers(struct f2fs_sb_info *sbi) int fsck_chk_curseg_info(struct f2fs_sb_info *sbi) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct curseg_info *curseg; struct seg_entry *se; struct f2fs_summary_block *sum_blk; @@ -2965,6 +2982,10 @@ int fsck_chk_curseg_info(struct f2fs_sb_info *sbi) se = get_seg_entry(sbi, curseg->segno); sum_blk = curseg->sum_blk; + if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)) + continue; + if (se->type != i) { ASSERT_MSG("Incorrect curseg [%d]: segno [0x%x] " "type(SIT) [%d]", i, curseg->segno, @@ -3047,7 +3068,10 @@ int fsck_verify(struct f2fs_sb_info *sbi) } c.bug_on = 1; } - + printf("[FSCK] Max image size: %"PRIu64" MB, Free space: %u MB\n", + c.max_size >> 20, + (sbi->user_block_count - sbi->total_valid_block_count) >> + (20 - F2FS_BLKSIZE_BITS)); printf("[FSCK] Unreachable nat entries "); if (nr_unref_nid == 0x0) { printf(" [Ok..] [0x%x]\n", nr_unref_nid); diff --git a/fsck/main.c b/fsck/main.c index 64efa87..c07be1e 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -71,6 +71,7 @@ void fsck_usage() MSG(0, " -d debug level [default:0]\n"); MSG(0, " -f check/fix entire partition\n"); MSG(0, " -g add default options\n"); + MSG(0, " -l show superblock/checkpoint\n"); MSG(0, " -O feature1[feature2,feature3,...] e.g. \"encrypt\"\n"); MSG(0, " -p preen mode [default:0 the same as -a [0|1]]\n"); MSG(0, " -S sparse_mode\n"); @@ -155,6 +156,14 @@ void sload_usage() exit(1); } +void label_usage() +{ + MSG(0, "\nUsage: f2fslabel [options] device [volume-label]\n"); + MSG(0, "[options]:\n"); + MSG(0, " -V print the version number and exit\n"); + exit(1); +} + static int is_digits(char *optarg) { unsigned int i; @@ -177,6 +186,8 @@ static void error_out(char *prog) resize_usage(); else if (!strcmp("sload.f2fs", prog)) sload_usage(); + else if (!strcmp("f2fslabel", prog)) + label_usage(); else MSG(0, "\nWrong program.\n"); } @@ -216,7 +227,7 @@ void f2fs_parse_options(int argc, char *argv[]) } if (!strcmp("fsck.f2fs", prog)) { - const char *option_string = ":aC:c:m:d:fg:O:p:q:StyV"; + const char *option_string = ":aC:c:m:d:fg:lO:p:q:StyV"; int opt = 0, val; char *token; struct option long_opt[] = { @@ -263,6 +274,9 @@ void f2fs_parse_options(int argc, char *argv[]) if (!strcmp(optarg, "android")) c.defset = CONF_ANDROID; break; + case 'l': + c.layout = 1; + break; case 'O': if (parse_feature(feature_table, optarg)) fsck_usage(); @@ -722,6 +736,39 @@ void f2fs_parse_options(int argc, char *argv[]) } } #endif /* WITH_SLOAD */ + } else if (!strcmp("f2fslabel", prog)) { +#ifdef WITH_LABEL + const char *option_string = "V"; + + c.func = LABEL; + while ((option = getopt(argc, argv, option_string)) != EOF) { + switch (option) { + case 'V': + show_version(prog); + exit(0); + default: + err = EUNKNOWN_OPT; + break; + } + if (err != NOERROR) + break; + } + + if (argc > (optind + 2)) { /* unknown argument(s) is(are) passed */ + optind += 2; + err = EUNKNOWN_ARG; + } else if (argc == (optind + 2)) { /* change label */ + c.vol_label = argv[optind + 1]; + argc--; + } else { /* print label */ + /* + * Since vol_label was initialized as "", in order to + * distinguish between clear label and print, set + * vol_label as NULL for print case + */ + c.vol_label = NULL; + } +#endif /* WITH_LABEL */ } if (err == NOERROR) { @@ -868,6 +915,11 @@ static int do_defrag(struct f2fs_sb_info *sbi) { struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) { + MSG(0, "Not support on readonly image.\n"); + return -1; + } + if (c.defrag_start > get_sb(block_count)) goto out_range; if (c.defrag_start < SM_I(sbi)->main_blkaddr) @@ -971,6 +1023,36 @@ static int do_sload(struct f2fs_sb_info *sbi) } #endif +#ifdef WITH_LABEL +static int do_label(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + if (!c.vol_label) { + char label[MAX_VOLUME_NAME]; + + utf16_to_utf8(label, sb->volume_name, + MAX_VOLUME_NAME, MAX_VOLUME_NAME); + MSG(0, "Info: volume label = %s\n", label); + return 0; + } + + if (strlen(c.vol_label) > MAX_VOLUME_NAME) { + ERR_MSG("Label should not exceed %d characters\n", MAX_VOLUME_NAME); + return -1; + } + + utf8_to_utf16(sb->volume_name, (const char *)c.vol_label, + MAX_VOLUME_NAME, strlen(c.vol_label)); + + update_superblock(sb, SB_MASK_ALL); + + MSG(0, "Info: volume label is changed to %s\n", c.vol_label); + + return 0; +} +#endif + #if defined(__APPLE__) static u64 get_boottime_ns() { @@ -1085,6 +1167,12 @@ fsck_again: c.fix_on = 1; goto fsck_again; #endif +#ifdef WITH_LABEL + case LABEL: + if (do_label(sbi)) + goto out_err; + break; +#endif default: ERR_MSG("Wrong program name\n"); ASSERT(0); diff --git a/fsck/mount.c b/fsck/mount.c index 6b2f17e..de692b6 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -369,11 +369,16 @@ static void DISP_label(u_int16_t *name) char buffer[MAX_VOLUME_NAME]; utf16_to_utf8(buffer, name, MAX_VOLUME_NAME, MAX_VOLUME_NAME); - printf("%-30s" "\t\t[%s]\n", "volum_name", buffer); + if (c.layout) + printf("%-30s %s\n", "Filesystem volume name:", buffer); + else + printf("%-30s" "\t\t[%s]\n", "volum_name", buffer); } void print_raw_sb_info(struct f2fs_super_block *sb) { + if (c.layout) + goto printout; if (!c.dbg_lv) return; @@ -381,7 +386,7 @@ void print_raw_sb_info(struct f2fs_super_block *sb) printf("+--------------------------------------------------------+\n"); printf("| Super block |\n"); printf("+--------------------------------------------------------+\n"); - +printout: DISP_u32(sb, magic); DISP_u32(sb, major_ver); @@ -427,6 +432,8 @@ void print_ckpt_info(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + if (c.layout) + goto printout; if (!c.dbg_lv) return; @@ -434,7 +441,7 @@ void print_ckpt_info(struct f2fs_sb_info *sbi) printf("+--------------------------------------------------------+\n"); printf("| Checkpoint |\n"); printf("+--------------------------------------------------------+\n"); - +printout: DISP_u64(cp, checkpoint_ver); DISP_u64(cp, user_block_count); DISP_u64(cp, valid_block_count); @@ -561,6 +568,9 @@ void print_sb_state(struct f2fs_super_block *sb) if (f & cpu_to_le32(F2FS_FEATURE_COMPRESSION)) { MSG(0, "%s", " compression"); } + if (f & cpu_to_le32(F2FS_FEATURE_RO)) { + MSG(0, "%s", " ro"); + } MSG(0, "\n"); MSG(0, "Info: superblock encrypt level = %d, salt = ", sb->encryption_level); @@ -856,9 +866,10 @@ int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr) return -1; } - if (total_sections > segment_count || + if (!(get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + (total_sections > segment_count || total_sections < F2FS_MIN_SEGMENTS || - segs_per_sec > segment_count || !segs_per_sec) { + segs_per_sec > segment_count || !segs_per_sec)) { MSG(0, "\tInvalid segment/section count (%u, %u x %u)\n", segment_count, total_sections, segs_per_sec); return 1; @@ -967,12 +978,13 @@ int validate_super_block(struct f2fs_sb_info *sbi, enum SB_ADDR sb_addr) c.sb_version, c.version); if (!c.no_kernel_check && memcmp(c.sb_version, c.version, VERSION_LEN)) { + c.auto_fix = 0; + c.fix_on = 1; + } + if (c.fix_on) { memcpy(sbi->raw_super->version, c.version, VERSION_LEN); update_superblock(sbi->raw_super, SB_MASK(sb_addr)); - - c.auto_fix = 0; - c.fix_on = 1; } print_sb_state(sbi->raw_super); return 0; @@ -1254,14 +1266,16 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi) ovp_segments = get_cp(overprov_segment_count); reserved_segments = get_cp(rsvd_segment_count); - if (fsmeta < F2FS_MIN_SEGMENT || ovp_segments == 0 || - reserved_segments == 0) { + if (!(get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + (fsmeta < F2FS_MIN_SEGMENT || ovp_segments == 0 || + reserved_segments == 0)) { MSG(0, "\tWrong layout: check mkfs.f2fs version\n"); return 1; } user_block_count = get_cp(user_block_count); - segment_count_main = get_sb(segment_count_main); + segment_count_main = get_sb(segment_count_main) + + (cpu_to_le32(F2FS_FEATURE_RO) ? 1 : 0); log_blocks_per_seg = get_sb(log_blocks_per_seg); if (!user_block_count || user_block_count >= segment_count_main << log_blocks_per_seg) { @@ -1884,11 +1898,15 @@ static void read_normal_summaries(struct f2fs_sb_info *sbi, int type) void update_sum_entry(struct f2fs_sb_info *sbi, block_t blk_addr, struct f2fs_summary *sum) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_summary_block *sum_blk; u32 segno, offset; int type, ret; struct seg_entry *se; + if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) + return; + segno = GET_SEGNO(sbi, blk_addr); offset = OFFSET_IN_SEG(sbi, blk_addr); @@ -2723,18 +2741,17 @@ int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, bitmap = get_seg_bitmap(sbi, se); type = get_seg_type(sbi, se); - if (vblocks == sbi->blocks_per_seg || - IS_CUR_SEGNO(sbi, segno)) { - *to = left ? START_BLOCK(sbi, segno) - 1: - START_BLOCK(sbi, segno + 1); - continue; - } - - if (vblocks == 0 && not_enough) { + if (vblocks == sbi->blocks_per_seg) { +next_segment: *to = left ? START_BLOCK(sbi, segno) - 1: START_BLOCK(sbi, segno + 1); continue; } + if (!(get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + IS_CUR_SEGNO(sbi, segno)) + goto next_segment; + if (vblocks == 0 && not_enough) + goto next_segment; if (vblocks == 0 && !(segno % sbi->segs_per_sec)) { struct seg_entry *se2; @@ -2765,17 +2782,24 @@ int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, static void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left, int i) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct curseg_info *curseg = CURSEG_I(sbi, i); struct f2fs_summary_block buf; u32 old_segno; u64 ssa_blk, to; int ret; + if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO))) { + if (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE) + return; + goto bypass_ssa; + } + /* update original SSA too */ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); ret = dev_write_block(curseg->sum_blk, ssa_blk); ASSERT(ret >= 0); - +bypass_ssa: to = from; ret = find_next_free_block(sbi, &to, left, i, c.zoned_model == F2FS_ZONED_HM); @@ -3014,10 +3038,12 @@ void write_checkpoint(struct f2fs_sb_info *sbi) ret = dev_write_block(curseg->sum_blk, cp_blk_no++); ASSERT(ret >= 0); - /* update original SSA too */ - ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); - ret = dev_write_block(curseg->sum_blk, ssa_blk); - ASSERT(ret >= 0); + if (!(get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO))) { + /* update original SSA too */ + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_write_block(curseg->sum_blk, ssa_blk); + ASSERT(ret >= 0); + } } /* Write nat bits */ @@ -3534,6 +3560,8 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi) if (get_cp(ckpt_flags) & CP_QUOTA_NEED_FSCK_FLAG) c.fix_on = 1; } + if (c.layout) + return 1; if (tune_sb_features(sbi)) return -1; diff --git a/fsck/node.c b/fsck/node.c index 1d291ca..c7988cb 100644 --- a/fsck/node.c +++ b/fsck/node.c @@ -61,6 +61,7 @@ void set_data_blkaddr(struct dnode_of_data *dn) block_t new_node_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, unsigned int ofs) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_node *f2fs_inode; struct f2fs_node *node_blk; struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -89,6 +90,10 @@ block_t new_node_block(struct f2fs_sb_info *sbi, type = CURSEG_WARM_NODE; } + if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + type != CURSEG_HOT_NODE) + type = CURSEG_HOT_NODE; + get_node_info(sbi, dn->nid, &ni); set_summary(&sum, dn->nid, 0, ni.version); ret = reserve_new_block(sbi, &blkaddr, &sum, type, !ofs); diff --git a/fsck/resize.c b/fsck/resize.c index b043cd9..78d578e 100644 --- a/fsck/resize.c +++ b/fsck/resize.c @@ -383,6 +383,7 @@ static void migrate_nat(struct f2fs_sb_info *sbi, ASSERT(ret >= 0); DBG(3, "Write NAT: %lx\n", block_addr); } + free(nat_block); DBG(0, "Info: Done to migrate NAT blocks: nat_blkaddr = 0x%x -> 0x%x\n", old_nat_blkaddr, new_nat_blkaddr); } diff --git a/fsck/segment.c b/fsck/segment.c index 365c7f8..0156690 100644 --- a/fsck/segment.c +++ b/fsck/segment.c @@ -104,11 +104,16 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to, int new_data_block(struct f2fs_sb_info *sbi, void *block, struct dnode_of_data *dn, int type) { + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_summary sum; struct node_info ni; unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node); int ret; + if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && + type != CURSEG_HOT_DATA) + type = CURSEG_HOT_DATA; + ASSERT(dn->node_blk); memset(block, 0, BLOCK_SZ); @@ -516,9 +521,9 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de) node_blk->i.i_compress_algrithm = c.compress.alg; node_blk->i.i_log_cluster_size = c.compress.cc.log_cluster_size; - node_blk->i.i_flags = cpu_to_le32( - F2FS_COMPR_FL | - (c.compress.readonly ? FS_IMMUTABLE_FL : 0)); + node_blk->i.i_flags = cpu_to_le32(F2FS_COMPR_FL); + if (c.compress.readonly) + node_blk->i.i_inline |= F2FS_COMPRESS_RELEASED; ASSERT(write_inode(node_blk, ni.blk_addr) >= 0); while (!eof && (n = bulkread(fd, rbuf, c.compress.cc.rlen, diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index cdcce2c..8969ae2 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -35,6 +35,7 @@ #define WITH_DEFRAG #define WITH_RESIZE #define WITH_SLOAD +#define WITH_LABEL #endif #include <inttypes.h> @@ -239,14 +240,14 @@ static inline uint64_t bswap_64(uint64_t val) #define MSG(n, fmt, ...) \ do { \ - if (c.dbg_lv >= n) { \ + if (c.dbg_lv >= n && !c.layout) { \ printf(fmt, ##__VA_ARGS__); \ } \ } while (0) #define DBG(n, fmt, ...) \ do { \ - if (c.dbg_lv >= n) { \ + if (c.dbg_lv >= n && !c.layout) { \ printf("[%s:%4d] " fmt, \ __func__, __LINE__, ##__VA_ARGS__); \ } \ @@ -261,7 +262,11 @@ static inline uint64_t bswap_64(uint64_t val) #define DISP_u16(ptr, member) \ do { \ assert(sizeof((ptr)->member) == 2); \ - printf("%-30s" "\t\t[0x%8x : %u]\n", \ + if (c.layout) \ + printf("%-30s %u\n", \ + #member":", le16_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8x : %u]\n", \ #member, le16_to_cpu(((ptr)->member)), \ le16_to_cpu(((ptr)->member))); \ } while (0) @@ -269,7 +274,11 @@ static inline uint64_t bswap_64(uint64_t val) #define DISP_u32(ptr, member) \ do { \ assert(sizeof((ptr)->member) <= 4); \ - printf("%-30s" "\t\t[0x%8x : %u]\n", \ + if (c.layout) \ + printf("%-30s %u\n", \ + #member":", le32_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8x : %u]\n", \ #member, le32_to_cpu(((ptr)->member)), \ le32_to_cpu(((ptr)->member))); \ } while (0) @@ -277,14 +286,23 @@ static inline uint64_t bswap_64(uint64_t val) #define DISP_u64(ptr, member) \ do { \ assert(sizeof((ptr)->member) == 8); \ - printf("%-30s" "\t\t[0x%8llx : %llu]\n", \ + if (c.layout) \ + printf("%-30s %llu\n", \ + #member":", le64_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8llx : %llu]\n", \ #member, le64_to_cpu(((ptr)->member)), \ le64_to_cpu(((ptr)->member))); \ } while (0) #define DISP_utf(ptr, member) \ do { \ - printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member)); \ + if (c.layout) \ + printf("%-30s %s\n", #member":", \ + ((ptr)->member)); \ + else \ + printf("%-30s" "\t\t[%s]\n", #member, \ + ((ptr)->member)); \ } while (0) /* Display to buffer */ @@ -343,6 +361,7 @@ enum f2fs_config_func { DEFRAG, RESIZE, SLOAD, + LABEL, }; enum default_set { @@ -439,6 +458,7 @@ struct f2fs_configuration { u_int64_t wanted_total_sectors; u_int64_t wanted_sector_size; u_int64_t target_sectors; + u_int64_t max_size; u_int32_t sectors_per_blk; u_int32_t blks_per_seg; __u8 init_version[VERSION_LEN + 1]; @@ -470,6 +490,7 @@ struct f2fs_configuration { int bug_nat_bits; int alloc_failed; int auto_fix; + int layout; int quota_fix; int preen_mode; int ro; @@ -696,7 +717,8 @@ enum { #define F2FS_FEATURE_VERITY 0x0400 /* reserved */ #define F2FS_FEATURE_SB_CHKSUM 0x0800 #define F2FS_FEATURE_CASEFOLD 0x1000 - #define F2FS_FEATURE_COMPRESSION 0x2000 +#define F2FS_FEATURE_COMPRESSION 0x2000 +#define F2FS_FEATURE_RO 0x4000 #define MAX_VOLUME_NAME 512 @@ -867,6 +889,8 @@ struct f2fs_extent { #define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */ #define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ #define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */ +#define F2FS_PIN_FILE 0x40 /* file should not be gced */ +#define F2FS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */ #if !defined(offsetof) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) @@ -1546,6 +1570,7 @@ struct feature feature_table[] = { \ { "sb_checksum", F2FS_FEATURE_SB_CHKSUM }, \ { "casefold", F2FS_FEATURE_CASEFOLD }, \ { "compression", F2FS_FEATURE_COMPRESSION }, \ + { "ro", F2FS_FEATURE_RO}, \ { NULL, 0x0}, \ }; diff --git a/lib/libf2fs.c b/lib/libf2fs.c index 85107ee..0add901 100644 --- a/lib/libf2fs.c +++ b/lib/libf2fs.c @@ -835,7 +835,7 @@ void get_kernel_uname_version(__u8 *version) if (uname(&buf)) return; -#if !defined(WITH_KERNEL_VERSION) +#if defined(WITH_KERNEL_VERSION) snprintf((char *)version, VERSION_LEN, "%s %s", buf.release, buf.version); #else diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c index dcedc17..320ee6c 100644 --- a/lib/libf2fs_io.c +++ b/lib/libf2fs_io.c @@ -507,6 +507,9 @@ int dev_read(void *buf, __u64 offset, size_t len) int fd; int err; + if (c.max_size < (offset + len)) + c.max_size = offset + len; + if (c.sparse_mode) return sparse_read_blk(offset / F2FS_BLKSIZE, len / F2FS_BLKSIZE, buf); @@ -548,6 +551,9 @@ int dev_write(void *buf, __u64 offset, size_t len) { int fd; + if (c.max_size < (offset + len)) + c.max_size = offset + len; + if (c.dry_run) return 0; @@ -590,6 +596,9 @@ int dev_fill(void *buf, __u64 offset, size_t len) { int fd; + if (c.max_size < (offset + len)) + c.max_size = offset + len; + if (c.sparse_mode) return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE, len / F2FS_BLKSIZE); diff --git a/man/Makefile.am b/man/Makefile.am index 1d16c6f..9363b82 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1,3 +1,3 @@ ## Makefile.am -dist_man_MANS = mkfs.f2fs.8 fsck.f2fs.8 dump.f2fs.8 defrag.f2fs.8 resize.f2fs.8 sload.f2fs.8 f2fs_io.8 +dist_man_MANS = mkfs.f2fs.8 fsck.f2fs.8 dump.f2fs.8 defrag.f2fs.8 resize.f2fs.8 sload.f2fs.8 f2fs_io.8 f2fslabel.8 diff --git a/man/f2fslabel.8 b/man/f2fslabel.8 new file mode 100644 index 0000000..848ed3b --- /dev/null +++ b/man/f2fslabel.8 @@ -0,0 +1,33 @@ +.\" Copyright (c) 2021 Samsung Electronics Co., Ltd. +.\" +.TH F2FSLABEL 8 +.SH NAME +f2fslabel \- Change the label on an f2fs volume +.SH SYNOPSIS +.B f2fslabel +.I device +[ +.I volume-label +] +.SH DESCRIPTION +.B f2fslabel +will display or change the volume label on the f2fs located on +.I device. +.PP +If the optional argument +.I volume-label +is present, then +.B f2fslabel +will set the volume label to be +.IR volume-label . +.PP +Otherwise, +.B f2fslabel +will simply show the current label. +.PP +.SH AUTHOR +.B f2fslabel +was written by Dongwoo Lee (dwoo08.lee@samsung.com). +.SH AVAILABILITY +.B f2fslabel +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c index 3f1fa32..3565bd3 100644 --- a/mkfs/f2fs_format.c +++ b/mkfs/f2fs_format.c @@ -212,7 +212,7 @@ static int f2fs_prepare_super_block(void) u_int64_t total_meta_zones, total_meta_segments; u_int32_t sit_bitmap_size, max_sit_bitmap_size; u_int32_t max_nat_bitmap_size, max_nat_segments; - u_int32_t total_zones; + u_int32_t total_zones, avail_zones; enum quota_type qtype; int i; @@ -250,6 +250,9 @@ static int f2fs_prepare_super_block(void) zone_size_bytes * zone_size_bytes - (u_int64_t) c.start_sector * DEFAULT_SECTOR_SIZE; + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) + zone_align_start_offset = 8192; + if (c.start_sector % DEFAULT_SECTORS_PER_BLOCK) { MSG(1, "\t%s: Align start sector number to the page unit\n", c.zoned_mode ? "FAIL" : "WARN"); @@ -400,7 +403,10 @@ static int f2fs_prepare_super_block(void) get_sb(segment_count_nat))) * c.blks_per_seg; - blocks_for_ssa = total_valid_blks_available / + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) + blocks_for_ssa = 0; + else + blocks_for_ssa = total_valid_blks_available / c.blks_per_seg + 1; set_sb(segment_count_ssa, SEG_ALIGN(blocks_for_ssa)); @@ -457,7 +463,13 @@ static int f2fs_prepare_super_block(void) (2 * (100 / c.overprovision + 1) + NR_CURSEG_TYPE) * round_up(f2fs_get_usable_segments(sb), get_sb(section_count)); - if (c.overprovision == 0 || c.total_segments < F2FS_MIN_SEGMENTS || + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { + c.overprovision = 0; + c.reserved_segments = 0; + } + if ((!(c.feature & cpu_to_le32(F2FS_FEATURE_RO)) && + c.overprovision == 0) || + c.total_segments < F2FS_MIN_SEGMENTS || (c.devices[0].total_sectors * c.sector_size < zone_align_start_offset) || (get_sb(segment_count_main) - NR_CURSEG_TYPE) < @@ -503,13 +515,25 @@ static int f2fs_prepare_super_block(void) if (c.feature & cpu_to_le32(F2FS_FEATURE_LOST_FOUND)) c.lpf_ino = c.next_free_nid++; - if (total_zones <= 6) { + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) + avail_zones = 2; + else + avail_zones = 6; + + if (total_zones <= avail_zones) { MSG(1, "\tError: %d zones: Need more zones " "by shrinking zone size\n", total_zones); return -1; } - if (c.heap) { + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { + c.cur_seg[CURSEG_HOT_NODE] = 0; + c.cur_seg[CURSEG_WARM_NODE] = 0; + c.cur_seg[CURSEG_COLD_NODE] = 0; + c.cur_seg[CURSEG_HOT_DATA] = 1; + c.cur_seg[CURSEG_COLD_DATA] = 0; + c.cur_seg[CURSEG_WARM_DATA] = 0; + } else if (c.heap) { c.cur_seg[CURSEG_HOT_NODE] = last_section(last_zone(total_zones)); c.cur_seg[CURSEG_WARM_NODE] = prev_zone(CURSEG_HOT_NODE); @@ -538,7 +562,8 @@ static int f2fs_prepare_super_block(void) } /* if there is redundancy, reassign it */ - verify_cur_segs(); + if (!(c.feature & cpu_to_le32(F2FS_FEATURE_RO))) + verify_cur_segs(); cure_extension_list(); @@ -723,7 +748,7 @@ static int f2fs_write_check_point_pack(void) if (f2fs_get_usable_segments(sb) <= get_cp(overprov_segment_count)) { MSG(0, "\tError: Not enough segments to create F2FS Volume\n"); - goto free_nat_bits; + goto free_cp_payload; } MSG(0, "Info: Overprovision ratio = %.3lf%%\n", c.overprovision); MSG(0, "Info: Overprovision segments = %u (GC reserved = %u)\n", @@ -731,9 +756,15 @@ static int f2fs_write_check_point_pack(void) c.reserved_segments); /* main segments - reserved segments - (node + data segments) */ - set_cp(free_segment_count, f2fs_get_usable_segments(sb) - 6); - set_cp(user_block_count, ((get_cp(free_segment_count) + 6 - + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { + set_cp(free_segment_count, f2fs_get_usable_segments(sb) - 2); + set_cp(user_block_count, ((get_cp(free_segment_count) + 2 - get_cp(overprov_segment_count)) * c.blks_per_seg)); + } else { + set_cp(free_segment_count, f2fs_get_usable_segments(sb) - 6); + set_cp(user_block_count, ((get_cp(free_segment_count) + 6 - + get_cp(overprov_segment_count)) * c.blks_per_seg)); + } /* cp page (2), data summaries (1), node summaries (3) */ set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload)); flags = CP_UMOUNT_FLAG | CP_COMPACT_SUM_FLAG; @@ -847,8 +878,13 @@ static int f2fs_write_check_point_pack(void) sum_compact_p += SUM_JOURNAL_SIZE; memset(sum, 0, sizeof(struct f2fs_summary_block)); + /* inode sit for root */ - journal->n_sits = cpu_to_le16(6); + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) + journal->n_sits = cpu_to_le16(2); + else + journal->n_sits = cpu_to_le16(6); + journal->sit_j.entries[0].segno = cp->cur_node_segno[0]; journal->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | @@ -859,30 +895,43 @@ static int f2fs_write_check_point_pack(void) if (c.lpf_inum) f2fs_set_bit(i, (char *)journal->sit_j.entries[0].se.valid_map); - journal->sit_j.entries[1].segno = cp->cur_node_segno[1]; - journal->sit_j.entries[1].se.vblocks = - cpu_to_le16((CURSEG_WARM_NODE << 10)); - journal->sit_j.entries[2].segno = cp->cur_node_segno[2]; - journal->sit_j.entries[2].se.vblocks = - cpu_to_le16((CURSEG_COLD_NODE << 10)); - - /* data sit for root */ - journal->sit_j.entries[3].segno = cp->cur_data_segno[0]; - journal->sit_j.entries[3].se.vblocks = - cpu_to_le16((CURSEG_HOT_DATA << 10) | - (1 + c.quota_dnum + c.lpf_dnum)); - f2fs_set_bit(0, (char *)journal->sit_j.entries[3].se.valid_map); - for (i = 1; i <= c.quota_dnum; i++) - f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map); - if (c.lpf_dnum) - f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map); - - journal->sit_j.entries[4].segno = cp->cur_data_segno[1]; - journal->sit_j.entries[4].se.vblocks = - cpu_to_le16((CURSEG_WARM_DATA << 10)); - journal->sit_j.entries[5].segno = cp->cur_data_segno[2]; - journal->sit_j.entries[5].se.vblocks = - cpu_to_le16((CURSEG_COLD_DATA << 10)); + if (c.feature & cpu_to_le32(F2FS_FEATURE_RO)) { + /* data sit for root */ + journal->sit_j.entries[1].segno = cp->cur_data_segno[0]; + journal->sit_j.entries[1].se.vblocks = + cpu_to_le16((CURSEG_HOT_DATA << 10) | + (1 + c.quota_dnum + c.lpf_dnum)); + f2fs_set_bit(0, (char *)journal->sit_j.entries[1].se.valid_map); + for (i = 1; i <= c.quota_dnum; i++) + f2fs_set_bit(i, (char *)journal->sit_j.entries[1].se.valid_map); + if (c.lpf_dnum) + f2fs_set_bit(i, (char *)journal->sit_j.entries[1].se.valid_map); + } else { + journal->sit_j.entries[1].segno = cp->cur_node_segno[1]; + journal->sit_j.entries[1].se.vblocks = + cpu_to_le16((CURSEG_WARM_NODE << 10)); + journal->sit_j.entries[2].segno = cp->cur_node_segno[2]; + journal->sit_j.entries[2].se.vblocks = + cpu_to_le16((CURSEG_COLD_NODE << 10)); + + /* data sit for root */ + journal->sit_j.entries[3].segno = cp->cur_data_segno[0]; + journal->sit_j.entries[3].se.vblocks = + cpu_to_le16((CURSEG_HOT_DATA << 10) | + (1 + c.quota_dnum + c.lpf_dnum)); + f2fs_set_bit(0, (char *)journal->sit_j.entries[3].se.valid_map); + for (i = 1; i <= c.quota_dnum; i++) + f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map); + if (c.lpf_dnum) + f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map); + + journal->sit_j.entries[4].segno = cp->cur_data_segno[1]; + journal->sit_j.entries[4].se.vblocks = + cpu_to_le16((CURSEG_WARM_DATA << 10)); + journal->sit_j.entries[5].segno = cp->cur_data_segno[2]; + journal->sit_j.entries[5].se.vblocks = + cpu_to_le16((CURSEG_COLD_DATA << 10)); + } memcpy(sum_compact_p, &journal->n_sits, SUM_JOURNAL_SIZE); sum_compact_p += SUM_JOURNAL_SIZE; @@ -1090,7 +1139,7 @@ static int f2fs_discard_obsolete_dnode(void) u_int64_t start_inode_pos = get_sb(main_blkaddr); u_int64_t last_inode_pos; - if (c.zoned_mode) + if (c.zoned_mode || c.feature & cpu_to_le32(F2FS_FEATURE_RO)) return 0; raw_node = calloc(sizeof(struct f2fs_node), 1); diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c index fa7d3f5..aa1a7e4 100644 --- a/tools/f2fs_io/f2fs_io.c +++ b/tools/f2fs_io/f2fs_io.c @@ -213,7 +213,8 @@ static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd) " verity\n" \ " casefold\n" \ " compression\n" \ -" nocompression\n" +" nocompression\n" \ +" immutable\n" static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd) { @@ -271,6 +272,12 @@ static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd) printf("nocow(pinned)"); exist = 1; } + if (flag & FS_IMMUTABLE_FL) { + if (exist) + printf(","); + printf("immutable"); + exist = 1; + } if (!exist) printf("none"); printf("\n"); @@ -284,7 +291,8 @@ static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd) "flag can be\n" \ " casefold\n" \ " compression\n" \ -" nocompression\n" +" nocompression\n" \ +" noimmutable\n" static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd) { @@ -310,6 +318,8 @@ static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd) flag |= FS_COMPR_FL; else if (!strcmp(argv[1], "nocompression")) flag |= FS_NOCOMP_FL; + else if (!strcmp(argv[1], "noimmutable")) + flag &= ~FS_IMMUTABLE_FL; ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag); printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]); diff --git a/tools/f2fs_io/f2fs_io.h b/tools/f2fs_io/f2fs_io.h index 3a0278f..cdaf00f 100644 --- a/tools/f2fs_io/f2fs_io.h +++ b/tools/f2fs_io/f2fs_io.h @@ -91,7 +91,7 @@ typedef u32 __be32; #define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23) #define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24) -#ifndef FS_IOC_GET_ENCRYPTION_POLICY +#ifndef FSCRYPT_POLICY_V1 #define FSCRYPT_POLICY_V1 0 #define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 struct fscrypt_policy_v1 { @@ -101,10 +101,12 @@ struct fscrypt_policy_v1 { __u8 flags; __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; }; +#endif +#ifndef FS_IOC_GET_ENCRYPTION_POLICY #define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy_v1) #endif -#ifndef FS_IOC_GET_ENCRYPTION_POLICY_EX +#ifndef FSCRYPT_POLICY_V2 #define FSCRYPT_POLICY_V2 2 #define FSCRYPT_KEY_IDENTIFIER_SIZE 16 struct fscrypt_policy_v2 { @@ -124,6 +126,8 @@ struct fscrypt_get_policy_ex_arg { struct fscrypt_policy_v2 v2; } policy; /* output */ }; +#endif +#ifndef FS_IOC_GET_ENCRYPTION_POLICY_EX #define FS_IOC_GET_ENCRYPTION_POLICY_EX _IOWR('f', 22, __u8[9]) /* size + version */ #endif |