make_empty_dir(sbi, node_blk);
else if (S_ISLNK(mode))
page_symlink(sbi, node_blk, de->link, size);
+
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ node_blk->i.i_inode_checksum =
+ cpu_to_le32(f2fs_inode_chksum(node_blk));
}
int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
nid, i_links);
}
}
- if (need_fix && !c.ro) {
- /* drop extent information to avoid potential wrong access */
+
+ /* drop extent information to avoid potential wrong access */
+ if (need_fix && !c.ro)
node_blk->i.i_ext.len = 0;
+
+ if ((c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) &&
+ f2fs_has_extra_isize(&node_blk->i)) {
+ __u32 provided, calculated;
+
+ provided = le32_to_cpu(node_blk->i.i_inode_checksum);
+ calculated = f2fs_inode_chksum(node_blk);
+
+ if (provided != calculated) {
+ ASSERT_MSG("ino: 0x%x chksum:0x%x, but calculated one is: 0x%x",
+ nid, provided, calculated);
+ if (c.fix_on) {
+ node_blk->i.i_inode_checksum =
+ cpu_to_le32(calculated);
+ need_fix = 1;
+ FIX_MSG("ino: 0x%x recover, i_inode_checksum= 0x%x -> 0x%x",
+ nid, provided, calculated);
+ }
+ }
+ }
+
+ if (need_fix && !c.ro) {
ret = dev_write_block(node_blk, ni->blk_addr);
ASSERT(ret >= 0);
}
DISP_u16(inode, i_extra_isize);
DISP_u16(inode, i_padding);
DISP_u32(inode, i_projid);
+ DISP_u32(inode, i_inode_checksum);
DISP_u32(inode, i_addr[ofs]); /* Pointers to data blocks */
DISP_u32(inode, i_addr[ofs + 1]); /* Pointers to data blocks */
if (f & cpu_to_le32(F2FS_FEATURE_PRJQUOTA)) {
MSG(0, "%s", " project quota");
}
+ if (f & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) {
+ MSG(0, "%s", " inode checksum");
+ }
MSG(0, "\n");
MSG(0, "Info: superblock encrypt level = %d, salt = ",
sb->encryption_level);
}
c.bug_on = 0;
+ c.feature = sb->feature;
+
+ /* precompute checksum seed for metadata */
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ c.chksum_seed = f2fs_cal_crc32(~0, sb->uuid, sizeof(sb->uuid));
sbi->total_valid_node_count = get_cp(valid_node_count);
sbi->total_valid_inode_count = get_cp(valid_inode_count);
node_blk->i.i_size = cpu_to_le64(de->size);
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ node_blk->i.i_inode_checksum =
+ cpu_to_le32(f2fs_inode_chksum(node_blk));
+
ret = dev_write_block(node_blk, ni.blk_addr);
ASSERT(ret >= 0);
free(node_blk);
/* sload parameters */
char *from_dir;
char *mount_point;
+
+ /* precomputed fs UUID checksum for seeding other checksums */
+ u_int32_t chksum_seed;
};
#ifdef CONFIG_64BIT
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
#define F2FS_FEATURE_EXTRA_ATTR 0x0008
#define F2FS_FEATURE_PRJQUOTA 0x0010
+#define F2FS_FEATURE_INODE_CHKSUM 0x0020
#define MAX_VOLUME_NAME 512
__le16 i_extra_isize; /* extra inode attribute size */
__le16 i_padding; /* padding */
__le32 i_projid; /* project id */
+ __le32 i_inode_checksum;/* inode meta checksum */
__le32 i_extra_end[0]; /* for attribute size calculation */
};
__le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
extern int utf16_to_utf8(char *, const u_int16_t *, size_t, size_t);
extern int log_base_2(u_int32_t);
extern unsigned int addrs_per_inode(struct f2fs_inode *);
+extern __u32 f2fs_inode_chksum(struct f2fs_node *);
extern int get_bits_in_byte(unsigned char n);
extern int test_and_set_bit_le(u32, u8 *);
return 0;
}
+__u32 f2fs_inode_chksum(struct f2fs_node *node)
+{
+ struct f2fs_inode *ri = &node->i;
+ __le32 ino = node->footer.ino;
+ __le32 gen = ri->i_generation;
+ __u32 chksum, chksum_seed;
+ __u32 dummy_cs = 0;
+ unsigned int offset = offsetof(struct f2fs_inode, i_inode_checksum);
+ unsigned int cs_size = sizeof(dummy_cs);
+
+ chksum = f2fs_cal_crc32(c.chksum_seed, (__u8 *)&ino,
+ sizeof(ino));
+ chksum_seed = f2fs_cal_crc32(chksum, (__u8 *)&gen, sizeof(gen));
+
+ chksum = f2fs_cal_crc32(chksum_seed, (__u8 *)ri, offset);
+ chksum = f2fs_cal_crc32(chksum, (__u8 *)&dummy_cs, cs_size);
+ offset += cs_size;
+ chksum = f2fs_cal_crc32(chksum, (__u8 *)ri + offset,
+ F2FS_BLKSIZE - offset);
+ return chksum;
+}
+
/*
* try to identify the root device
*/
uuid_generate(sb->uuid);
+ /* precompute checksum seed for metadata */
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ c.chksum_seed = f2fs_cal_crc32(~0, sb->uuid, sizeof(sb->uuid));
+
utf8_to_utf16(sb->volume_name, (const char *)c.vol_label,
MAX_VOLUME_NAME, strlen(c.vol_label));
set_sb(node_ino, 1);
raw_node->i.i_ext.blk_addr = 0;
raw_node->i.i_ext.len = 0;
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ raw_node->i.i_inode_checksum =
+ cpu_to_le32(f2fs_inode_chksum(raw_node));
+
main_area_node_seg_blk_offset = get_sb(main_blkaddr);
main_area_node_seg_blk_offset += c.cur_seg[CURSEG_HOT_NODE] *
c.blks_per_seg;
c.feature |= cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR);
} else if (!strcmp(features, "project_quota")) {
c.feature |= cpu_to_le32(F2FS_FEATURE_PRJQUOTA);
+ } else if (!strcmp(features, "inode_checksum")) {
+ c.feature |= cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM);
} else {
MSG(0, "Error: Wrong features\n");
mkfs_usage();
"enabled with extra attr feature\n");
exit(1);
}
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) {
+ MSG(0, "\tInfo: inode checksum feature should always been"
+ "enabled with extra attr feature\n");
+ exit(1);
+ }
}
if (optind >= argc) {