Skip to content

Commit e1da787

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: introduce and spread verify_blkaddr
This patch introduces verify_blkaddr to check meta/data block address with valid range to detect bug earlier. In addition, once we encounter an invalid blkaddr, notice user to run fsck to fix, and let the kernel panic. Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 24b81df commit e1da787

File tree

9 files changed

+60
-29
lines changed

9 files changed

+60
-29
lines changed

fs/f2fs/checkpoint.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
120120
return __get_meta_page(sbi, index, false);
121121
}
122122

123-
bool f2fs_is_valid_meta_blkaddr(struct f2fs_sb_info *sbi,
123+
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
124124
block_t blkaddr, int type)
125125
{
126126
switch (type) {
@@ -141,10 +141,16 @@ bool f2fs_is_valid_meta_blkaddr(struct f2fs_sb_info *sbi,
141141
return false;
142142
break;
143143
case META_POR:
144+
case DATA_GENERIC:
144145
if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
145146
blkaddr < MAIN_BLKADDR(sbi)))
146147
return false;
147148
break;
149+
case META_GENERIC:
150+
if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
151+
blkaddr >= MAIN_BLKADDR(sbi)))
152+
return false;
153+
break;
148154
default:
149155
BUG();
150156
}
@@ -177,7 +183,7 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
177183
blk_start_plug(&plug);
178184
for (; nrpages-- > 0; blkno++) {
179185

180-
if (!f2fs_is_valid_meta_blkaddr(sbi, blkno, type))
186+
if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
181187
goto out;
182188

183189
switch (type) {

fs/f2fs/data.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
485485
spin_unlock(&io->io_lock);
486486
}
487487

488-
if (is_valid_blkaddr(fio->old_blkaddr))
488+
if (__is_valid_data_blkaddr(fio->old_blkaddr))
489489
verify_block_addr(fio, fio->old_blkaddr);
490490
verify_block_addr(fio, fio->new_blkaddr);
491491

@@ -1045,7 +1045,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
10451045
next_block:
10461046
blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
10471047

1048-
if (!is_valid_blkaddr(blkaddr)) {
1048+
if (!is_valid_data_blkaddr(sbi, blkaddr)) {
10491049
if (create) {
10501050
if (unlikely(f2fs_cp_error(sbi))) {
10511051
err = -EIO;
@@ -1700,7 +1700,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
17001700
f2fs_lookup_extent_cache(inode, page->index, &ei)) {
17011701
fio->old_blkaddr = ei.blk + page->index - ei.fofs;
17021702

1703-
if (is_valid_blkaddr(fio->old_blkaddr)) {
1703+
if (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr)) {
17041704
ipu_force = true;
17051705
fio->need_lock = LOCK_DONE;
17061706
goto got_it;
@@ -1727,7 +1727,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
17271727
* If current allocation needs SSR,
17281728
* it had better in-place writes for updated data.
17291729
*/
1730-
if (ipu_force || (is_valid_blkaddr(fio->old_blkaddr) &&
1730+
if (ipu_force || (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) &&
17311731
need_inplace_update(fio))) {
17321732
err = encrypt_one_page(fio);
17331733
if (err)

fs/f2fs/f2fs.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,16 @@ struct cp_control {
194194
};
195195

196196
/*
197-
* For CP/NAT/SIT/SSA readahead
197+
* indicate meta/data type
198198
*/
199199
enum {
200200
META_CP,
201201
META_NAT,
202202
META_SIT,
203203
META_SSA,
204204
META_POR,
205+
DATA_GENERIC,
206+
META_GENERIC,
205207
};
206208

207209
/* for the list of ino */
@@ -2666,13 +2668,36 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
26662668
spin_unlock(&sbi->iostat_lock);
26672669
}
26682670

2669-
static inline bool is_valid_blkaddr(block_t blkaddr)
2671+
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
2672+
block_t blkaddr, int type);
2673+
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
2674+
static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
2675+
block_t blkaddr, int type)
2676+
{
2677+
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
2678+
f2fs_msg(sbi->sb, KERN_ERR,
2679+
"invalid blkaddr: %u, type: %d, run fsck to fix.",
2680+
blkaddr, type);
2681+
f2fs_bug_on(sbi, 1);
2682+
}
2683+
}
2684+
2685+
static inline bool __is_valid_data_blkaddr(block_t blkaddr)
26702686
{
26712687
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
26722688
return false;
26732689
return true;
26742690
}
26752691

2692+
static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
2693+
block_t blkaddr)
2694+
{
2695+
if (!__is_valid_data_blkaddr(blkaddr))
2696+
return false;
2697+
verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
2698+
return true;
2699+
}
2700+
26762701
/*
26772702
* file.c
26782703
*/
@@ -2896,8 +2921,8 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
28962921
struct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
28972922
struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
28982923
struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
2899-
bool f2fs_is_valid_meta_blkaddr(struct f2fs_sb_info *sbi,
2900-
block_t blkaddr, int type);
2924+
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
2925+
block_t blkaddr, int type);
29012926
int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
29022927
int type, bool sync);
29032928
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);

fs/f2fs/file.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,13 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,
350350
return pgofs;
351351
}
352352

353-
static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
354-
int whence)
353+
static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
354+
pgoff_t dirty, pgoff_t pgofs, int whence)
355355
{
356356
switch (whence) {
357357
case SEEK_DATA:
358358
if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
359-
is_valid_blkaddr(blkaddr))
359+
is_valid_data_blkaddr(sbi, blkaddr))
360360
return true;
361361
break;
362362
case SEEK_HOLE:
@@ -420,7 +420,8 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
420420
blkaddr = datablock_addr(dn.inode,
421421
dn.node_page, dn.ofs_in_node);
422422

423-
if (__found_offset(blkaddr, dirty, pgofs, whence)) {
423+
if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
424+
pgofs, whence)) {
424425
f2fs_put_dnode(&dn);
425426
goto found;
426427
}

fs/f2fs/inode.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
6868
}
6969
}
7070

71-
static bool __written_first_block(struct f2fs_inode *ri)
71+
static bool __written_first_block(struct f2fs_sb_info *sbi,
72+
struct f2fs_inode *ri)
7273
{
7374
block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
7475

75-
if (is_valid_blkaddr(addr))
76+
if (is_valid_data_blkaddr(sbi, addr))
7677
return true;
7778
return false;
7879
}
@@ -282,7 +283,7 @@ static int do_read_inode(struct inode *inode)
282283
/* get rdev by using inline_info */
283284
__get_inode_rdev(inode, ri);
284285

285-
if (__written_first_block(ri))
286+
if (__written_first_block(sbi, ri))
286287
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
287288

288289
if (!f2fs_need_inode_block_update(sbi, inode->i_ino))

fs/f2fs/node.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
371371
new_blkaddr == NULL_ADDR);
372372
f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
373373
new_blkaddr == NEW_ADDR);
374-
f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) &&
374+
f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
375375
new_blkaddr == NEW_ADDR);
376376

377377
/* increment version no as node is removed */
@@ -382,7 +382,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
382382

383383
/* change address */
384384
nat_set_blkaddr(e, new_blkaddr);
385-
if (!is_valid_blkaddr(new_blkaddr))
385+
if (!is_valid_data_blkaddr(sbi, new_blkaddr))
386386
set_nat_flag(e, IS_CHECKPOINTED, false);
387387
__set_nat_cache_dirty(nm_i, e);
388388

fs/f2fs/recovery.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
252252
while (1) {
253253
struct fsync_inode_entry *entry;
254254

255-
if (!f2fs_is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
255+
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
256256
return 0;
257257

258258
page = f2fs_get_tmp_page(sbi, blkaddr);
@@ -507,7 +507,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
507507
}
508508

509509
/* dest is valid block, try to recover from src to dest */
510-
if (f2fs_is_valid_meta_blkaddr(sbi, dest, META_POR)) {
510+
if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
511511

512512
if (src == NULL_ADDR) {
513513
err = f2fs_reserve_new_block(&dn);
@@ -568,7 +568,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
568568
while (1) {
569569
struct fsync_inode_entry *entry;
570570

571-
if (!f2fs_is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
571+
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
572572
break;
573573

574574
f2fs_ra_meta_pages_cond(sbi, blkaddr);

fs/f2fs/segment.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,7 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
19191919
struct seg_entry *se;
19201920
bool is_cp = false;
19211921

1922-
if (!is_valid_blkaddr(blkaddr))
1922+
if (!is_valid_data_blkaddr(sbi, blkaddr))
19231923
return true;
19241924

19251925
down_read(&sit_i->sentry_lock);
@@ -2993,7 +2993,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
29932993
{
29942994
struct page *cpage;
29952995

2996-
if (!is_valid_blkaddr(blkaddr))
2996+
if (!is_valid_data_blkaddr(sbi, blkaddr))
29972997
return;
29982998

29992999
cpage = find_lock_page(META_MAPPING(sbi), blkaddr);

fs/f2fs/segment.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
8686

8787
#define GET_SEGNO(sbi, blk_addr) \
88-
((!is_valid_blkaddr(blk_addr)) ? \
88+
((!is_valid_data_blkaddr(sbi, blk_addr)) ? \
8989
NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \
9090
GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
9191
#define BLKS_PER_SEC(sbi) \
@@ -647,11 +647,9 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
647647

648648
if (PAGE_TYPE_OF_BIO(fio->type) == META &&
649649
(!is_read_io(fio->op) || fio->is_meta))
650-
BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
651-
blk_addr >= MAIN_BLKADDR(sbi));
650+
verify_blkaddr(sbi, blk_addr, META_GENERIC);
652651
else
653-
BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
654-
blk_addr >= MAX_BLKADDR(sbi));
652+
verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
655653
}
656654

657655
/*

0 commit comments

Comments
 (0)