f2fs: support inode checksum
This patch adds to support inode checksum in f2fs. Signed-off-by: Chao Yu <yuchao0@huawei.com> [Jaegeuk Kim: fix verification flow] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
4f31d26b0c
commit
704956ecf5
|
@ -116,6 +116,7 @@ struct f2fs_mount_info {
|
||||||
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
|
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
|
||||||
#define F2FS_FEATURE_EXTRA_ATTR 0x0008
|
#define F2FS_FEATURE_EXTRA_ATTR 0x0008
|
||||||
#define F2FS_FEATURE_PRJQUOTA 0x0010
|
#define F2FS_FEATURE_PRJQUOTA 0x0010
|
||||||
|
#define F2FS_FEATURE_INODE_CHKSUM 0x0020
|
||||||
|
|
||||||
#define F2FS_HAS_FEATURE(sb, mask) \
|
#define F2FS_HAS_FEATURE(sb, mask) \
|
||||||
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
|
((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 */
|
/* Reference to checksum algorithm driver via cryptoapi */
|
||||||
struct crypto_shash *s_chksum_driver;
|
struct crypto_shash *s_chksum_driver;
|
||||||
|
|
||||||
|
/* Precomputed FS UUID checksum for seeding other checksums */
|
||||||
|
__u32 s_chksum_seed;
|
||||||
|
|
||||||
/* For fault injection */
|
/* For fault injection */
|
||||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||||
struct f2fs_fault_info fault_info;
|
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;
|
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)
|
static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
|
||||||
{
|
{
|
||||||
return container_of(inode, struct f2fs_inode_info, vfs_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
|
* inode.c
|
||||||
*/
|
*/
|
||||||
void f2fs_set_inode_flags(struct inode *inode);
|
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(struct super_block *sb, unsigned long ino);
|
||||||
struct inode *f2fs_iget_retry(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);
|
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);
|
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
|
#ifdef CONFIG_BLK_DEV_ZONED
|
||||||
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
|
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
|
||||||
struct block_device *bdev, block_t blkaddr)
|
struct block_device *bdev, block_t blkaddr)
|
||||||
|
|
|
@ -108,6 +108,76 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
|
||||||
return;
|
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)
|
static int do_read_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
|
|
|
@ -1171,6 +1171,11 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!f2fs_inode_chksum_verify(sbi, page)) {
|
||||||
|
err = -EBADMSG;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
page_hit:
|
page_hit:
|
||||||
if(unlikely(nid != nid_of_node(page))) {
|
if(unlikely(nid != nid_of_node(page))) {
|
||||||
f2fs_msg(sbi->sb, KERN_WARNING, "inconsistent node block, "
|
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),
|
F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
|
||||||
i_projid))
|
i_projid))
|
||||||
dst->i_projid = src->i_projid;
|
dst->i_projid = src->i_projid;
|
||||||
|
|
||||||
|
f2fs_inode_chksum_set(sbi, ipage);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_ni = old_ni;
|
new_ni = old_ni;
|
||||||
|
|
|
@ -2214,9 +2214,12 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||||
|
|
||||||
mutex_unlock(&sit_i->sentry_lock);
|
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));
|
fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
|
||||||
|
|
||||||
|
f2fs_inode_chksum_set(sbi, page);
|
||||||
|
}
|
||||||
|
|
||||||
if (add_list) {
|
if (add_list) {
|
||||||
struct f2fs_bio_info *io;
|
struct f2fs_bio_info *io;
|
||||||
|
|
||||||
|
|
|
@ -1993,6 +1993,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
sb->s_fs_info = sbi;
|
sb->s_fs_info = sbi;
|
||||||
sbi->raw_super = raw_super;
|
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
|
* The BLKZONED feature indicates that the drive was formatted with
|
||||||
* zone alignment optimization. This is optional for host-aware
|
* zone alignment optimization. This is optional for host-aware
|
||||||
|
|
|
@ -240,6 +240,7 @@ struct f2fs_inode {
|
||||||
__le16 i_extra_isize; /* extra inode attribute size */
|
__le16 i_extra_isize; /* extra inode attribute size */
|
||||||
__le16 i_padding; /* padding */
|
__le16 i_padding; /* padding */
|
||||||
__le32 i_projid; /* project id */
|
__le32 i_projid; /* project id */
|
||||||
|
__le32 i_inode_checksum;/* inode meta checksum */
|
||||||
__le32 i_extra_end[0]; /* for attribute size calculation */
|
__le32 i_extra_end[0]; /* for attribute size calculation */
|
||||||
};
|
};
|
||||||
__le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
|
__le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */
|
||||||
|
|
Loading…
Reference in New Issue