Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 704956ec authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim
Browse files

f2fs: support inode checksum



This patch adds to support inode checksum in f2fs.

Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: fix verification flow]
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 4f31d26b
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ struct f2fs_mount_info {
#define F2FS_FEATURE_ATOMIC_WRITE	0x0004
#define F2FS_FEATURE_EXTRA_ATTR		0x0008
#define F2FS_FEATURE_PRJQUOTA		0x0010
#define F2FS_FEATURE_INODE_CHKSUM	0x0020

#define F2FS_HAS_FEATURE(sb, mask)					\
	((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -1085,6 +1086,9 @@ struct f2fs_sb_info {
	/* Reference to checksum algorithm driver via cryptoapi */
	struct crypto_shash *s_chksum_driver;

	/* Precomputed FS UUID checksum for seeding other checksums */
	__u32 s_chksum_seed;

	/* For fault injection */
#ifdef CONFIG_F2FS_FAULT_INJECTION
	struct f2fs_fault_info fault_info;
@@ -1176,6 +1180,27 @@ static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
	return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
}

static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
			      const void *address, unsigned int length)
{
	struct {
		struct shash_desc shash;
		char ctx[4];
	} desc;
	int err;

	BUG_ON(crypto_shash_descsize(sbi->s_chksum_driver) != sizeof(desc.ctx));

	desc.shash.tfm = sbi->s_chksum_driver;
	desc.shash.flags = 0;
	*(u32 *)desc.ctx = crc;

	err = crypto_shash_update(&desc.shash, address, length);
	BUG_ON(err);

	return *(u32 *)desc.ctx;
}

static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
{
	return container_of(inode, struct f2fs_inode_info, vfs_inode);
@@ -2285,6 +2310,8 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 * inode.c
 */
void f2fs_set_inode_flags(struct inode *inode);
bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
@@ -2869,6 +2896,11 @@ static inline int f2fs_sb_has_project_quota(struct super_block *sb)
	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
}

static inline int f2fs_sb_has_inode_chksum(struct super_block *sb)
{
	return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM);
}

#ifdef CONFIG_BLK_DEV_ZONED
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
			struct block_device *bdev, block_t blkaddr)
+70 −0
Original line number Diff line number Diff line
@@ -108,6 +108,76 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
	return;
}

static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
{
	struct f2fs_inode *ri = &F2FS_NODE(page)->i;
	int extra_isize = le32_to_cpu(ri->i_extra_isize);

	if (!f2fs_sb_has_inode_chksum(sbi->sb))
		return false;

	if (!RAW_IS_INODE(F2FS_NODE(page)) || !(ri->i_inline & F2FS_EXTRA_ATTR))
		return false;

	if (!F2FS_FITS_IN_INODE(ri, extra_isize, i_inode_checksum))
		return false;

	return true;
}

static __u32 f2fs_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
{
	struct f2fs_node *node = F2FS_NODE(page);
	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_chksum(sbi, sbi->s_chksum_seed, (__u8 *)&ino,
							sizeof(ino));
	chksum_seed = f2fs_chksum(sbi, chksum, (__u8 *)&gen, sizeof(gen));

	chksum = f2fs_chksum(sbi, chksum_seed, (__u8 *)ri, offset);
	chksum = f2fs_chksum(sbi, chksum, (__u8 *)&dummy_cs, cs_size);
	offset += cs_size;
	chksum = f2fs_chksum(sbi, chksum, (__u8 *)ri + offset,
						F2FS_BLKSIZE - offset);
	return chksum;
}

bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
{
	struct f2fs_inode *ri;
	__u32 provided, calculated;

	if (!f2fs_enable_inode_chksum(sbi, page))
		return true;

	ri = &F2FS_NODE(page)->i;
	provided = le32_to_cpu(ri->i_inode_checksum);
	calculated = f2fs_inode_chksum(sbi, page);

	if (provided != calculated)
		f2fs_msg(sbi->sb, KERN_WARNING,
			"checksum invalid, ino = %x, %x vs. %x",
			ino_of_node(page), provided, calculated);

	return provided == calculated;
}

void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
{
	struct f2fs_inode *ri = &F2FS_NODE(page)->i;

	if (!f2fs_enable_inode_chksum(sbi, page))
		return;

	ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
}

static int do_read_inode(struct inode *inode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+7 −0
Original line number Diff line number Diff line
@@ -1171,6 +1171,11 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
		err = -EIO;
		goto out_err;
	}

	if (!f2fs_inode_chksum_verify(sbi, page)) {
		err = -EBADMSG;
		goto out_err;
	}
page_hit:
	if(unlikely(nid != nid_of_node(page))) {
		f2fs_msg(sbi->sb, KERN_WARNING, "inconsistent node block, "
@@ -2275,6 +2280,8 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
			F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
								i_projid))
			dst->i_projid = src->i_projid;

		f2fs_inode_chksum_set(sbi, ipage);
	}

	new_ni = old_ni;
+4 −1
Original line number Diff line number Diff line
@@ -2214,9 +2214,12 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,

	mutex_unlock(&sit_i->sentry_lock);

	if (page && IS_NODESEG(type))
	if (page && IS_NODESEG(type)) {
		fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));

		f2fs_inode_chksum_set(sbi, page);
	}

	if (add_list) {
		struct f2fs_bio_info *io;

+5 −0
Original line number Diff line number Diff line
@@ -1993,6 +1993,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
	sb->s_fs_info = sbi;
	sbi->raw_super = raw_super;

	/* precompute checksum seed for metadata */
	if (f2fs_sb_has_inode_chksum(sb))
		sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
						sizeof(raw_super->uuid));

	/*
	 * The BLKZONED feature indicates that the drive was formatted with
	 * zone alignment optimization. This is optional for host-aware
Loading