Skip to content

Commit 704956e

Browse files
chaseyuJaegeuk Kim
authored andcommitted
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>
1 parent 4f31d26 commit 704956e

File tree

6 files changed

+119
-1
lines changed

6 files changed

+119
-1
lines changed

fs/f2fs/f2fs.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct f2fs_mount_info {
116116
#define F2FS_FEATURE_ATOMIC_WRITE0x0004
117117
#define F2FS_FEATURE_EXTRA_ATTR0x0008
118118
#define F2FS_FEATURE_PRJQUOTA0x0010
119+
#define F2FS_FEATURE_INODE_CHKSUM0x0020
119120

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

1089+
/* Precomputed FS UUID checksum for seeding other checksums */
1090+
__u32 s_chksum_seed;
1091+
10881092
/* For fault injection */
10891093
#ifdef CONFIG_F2FS_FAULT_INJECTION
10901094
struct f2fs_fault_info fault_info;
@@ -1176,6 +1180,27 @@ static inline bool f2fs_crc_valid(struct f2fs_sb_info *sbi, __u32 blk_crc,
11761180
return f2fs_crc32(sbi, buf, buf_size) == blk_crc;
11771181
}
11781182

1183+
static inline u32 f2fs_chksum(struct f2fs_sb_info *sbi, u32 crc,
1184+
const void *address, unsigned int length)
1185+
{
1186+
struct {
1187+
struct shash_desc shash;
1188+
char ctx[4];
1189+
} desc;
1190+
int err;
1191+
1192+
BUG_ON(crypto_shash_descsize(sbi->s_chksum_driver) != sizeof(desc.ctx));
1193+
1194+
desc.shash.tfm = sbi->s_chksum_driver;
1195+
desc.shash.flags = 0;
1196+
*(u32 *)desc.ctx = crc;
1197+
1198+
err = crypto_shash_update(&desc.shash, address, length);
1199+
BUG_ON(err);
1200+
1201+
return *(u32 *)desc.ctx;
1202+
}
1203+
11791204
static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
11801205
{
11811206
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);
22852310
* inode.c
22862311
*/
22872312
void f2fs_set_inode_flags(struct inode *inode);
2313+
bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
2314+
void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
22882315
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
22892316
struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
22902317
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)
28692896
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
28702897
}
28712898

2899+
static inline int f2fs_sb_has_inode_chksum(struct super_block *sb)
2900+
{
2901+
return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM);
2902+
}
2903+
28722904
#ifdef CONFIG_BLK_DEV_ZONED
28732905
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
28742906
struct block_device *bdev, block_t blkaddr)

fs/f2fs/inode.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,76 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
108108
return;
109109
}
110110

111+
static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
112+
{
113+
struct f2fs_inode *ri = &F2FS_NODE(page)->i;
114+
int extra_isize = le32_to_cpu(ri->i_extra_isize);
115+
116+
if (!f2fs_sb_has_inode_chksum(sbi->sb))
117+
return false;
118+
119+
if (!RAW_IS_INODE(F2FS_NODE(page)) || !(ri->i_inline & F2FS_EXTRA_ATTR))
120+
return false;
121+
122+
if (!F2FS_FITS_IN_INODE(ri, extra_isize, i_inode_checksum))
123+
return false;
124+
125+
return true;
126+
}
127+
128+
static __u32 f2fs_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
129+
{
130+
struct f2fs_node *node = F2FS_NODE(page);
131+
struct f2fs_inode *ri = &node->i;
132+
__le32 ino = node->footer.ino;
133+
__le32 gen = ri->i_generation;
134+
__u32 chksum, chksum_seed;
135+
__u32 dummy_cs = 0;
136+
unsigned int offset = offsetof(struct f2fs_inode, i_inode_checksum);
137+
unsigned int cs_size = sizeof(dummy_cs);
138+
139+
chksum = f2fs_chksum(sbi, sbi->s_chksum_seed, (__u8 *)&ino,
140+
sizeof(ino));
141+
chksum_seed = f2fs_chksum(sbi, chksum, (__u8 *)&gen, sizeof(gen));
142+
143+
chksum = f2fs_chksum(sbi, chksum_seed, (__u8 *)ri, offset);
144+
chksum = f2fs_chksum(sbi, chksum, (__u8 *)&dummy_cs, cs_size);
145+
offset += cs_size;
146+
chksum = f2fs_chksum(sbi, chksum, (__u8 *)ri + offset,
147+
F2FS_BLKSIZE - offset);
148+
return chksum;
149+
}
150+
151+
bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
152+
{
153+
struct f2fs_inode *ri;
154+
__u32 provided, calculated;
155+
156+
if (!f2fs_enable_inode_chksum(sbi, page))
157+
return true;
158+
159+
ri = &F2FS_NODE(page)->i;
160+
provided = le32_to_cpu(ri->i_inode_checksum);
161+
calculated = f2fs_inode_chksum(sbi, page);
162+
163+
if (provided != calculated)
164+
f2fs_msg(sbi->sb, KERN_WARNING,
165+
"checksum invalid, ino = %x, %x vs. %x",
166+
ino_of_node(page), provided, calculated);
167+
168+
return provided == calculated;
169+
}
170+
171+
void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
172+
{
173+
struct f2fs_inode *ri = &F2FS_NODE(page)->i;
174+
175+
if (!f2fs_enable_inode_chksum(sbi, page))
176+
return;
177+
178+
ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
179+
}
180+
111181
static int do_read_inode(struct inode *inode)
112182
{
113183
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);

fs/f2fs/node.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,11 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
11711171
err = -EIO;
11721172
goto out_err;
11731173
}
1174+
1175+
if (!f2fs_inode_chksum_verify(sbi, page)) {
1176+
err = -EBADMSG;
1177+
goto out_err;
1178+
}
11741179
page_hit:
11751180
if(unlikely(nid != nid_of_node(page))) {
11761181
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)
22752280
F2FS_FITS_IN_INODE(src, le16_to_cpu(src->i_extra_isize),
22762281
i_projid))
22772282
dst->i_projid = src->i_projid;
2283+
2284+
f2fs_inode_chksum_set(sbi, ipage);
22782285
}
22792286

22802287
new_ni = old_ni;

fs/f2fs/segment.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2214,9 +2214,12 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
22142214

22152215
mutex_unlock(&sit_i->sentry_lock);
22162216

2217-
if (page && IS_NODESEG(type))
2217+
if (page && IS_NODESEG(type)) {
22182218
fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
22192219

2220+
f2fs_inode_chksum_set(sbi, page);
2221+
}
2222+
22202223
if (add_list) {
22212224
struct f2fs_bio_info *io;
22222225

fs/f2fs/super.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
19931993
sb->s_fs_info = sbi;
19941994
sbi->raw_super = raw_super;
19951995

1996+
/* precompute checksum seed for metadata */
1997+
if (f2fs_sb_has_inode_chksum(sb))
1998+
sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
1999+
sizeof(raw_super->uuid));
2000+
19962001
/*
19972002
* The BLKZONED feature indicates that the drive was formatted with
19982003
* zone alignment optimization. This is optional for host-aware

include/linux/f2fs_fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ struct f2fs_inode {
240240
__le16 i_extra_isize;/* extra inode attribute size */
241241
__le16 i_padding;/* padding */
242242
__le32 i_projid;/* project id */
243+
__le32 i_inode_checksum;/* inode meta checksum */
243244
__le32 i_extra_end[0];/* for attribute size calculation */
244245
};
245246
__le32 i_addr[DEF_ADDRS_PER_INODE];/* Pointers to data blocks */

0 commit comments

Comments
 (0)