aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@google.com>2021-06-03 09:28:09 -0700
committerJaegeuk Kim <jaegeuk@google.com>2021-06-03 12:39:21 -0700
commita3965e992fdfb90af0bdd079a40551196bbc3b39 (patch)
tree1908951ac5c6d879e06132ab33fdae3e86cf96ee
parentf7d3db3bab3979ed135f4e811ca9c856362a55bc (diff)
downloadf2fs-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--METADATA4
-rw-r--r--fsck/Makefile.am1
-rw-r--r--fsck/dump.c3
-rw-r--r--fsck/fsck.c28
-rw-r--r--fsck/main.c90
-rw-r--r--fsck/mount.c76
-rw-r--r--fsck/node.c5
-rw-r--r--fsck/resize.c1
-rw-r--r--fsck/segment.c11
-rw-r--r--include/f2fs_fs.h39
-rw-r--r--lib/libf2fs.c2
-rw-r--r--lib/libf2fs_io.c9
-rw-r--r--man/Makefile.am2
-rw-r--r--man/f2fslabel.833
-rw-r--r--mkfs/f2fs_format.c119
-rw-r--r--tools/f2fs_io/f2fs_io.c14
-rw-r--r--tools/f2fs_io/f2fs_io.h8
17 files changed, 364 insertions, 81 deletions
diff --git a/METADATA b/METADATA
index 15545a8..0120fd9 100644
--- a/METADATA
+++ b/METADATA
@@ -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