NAT区中两个segment为一组,互为备份(第一个记作segment A,第二个记作segment B),nid对应的f2fs_nat_entry既可能在A中,也可能在B中,如果nm_i->nat_bitmap中的bit置位,那么B中的entry是有效的,否则 A中的entry有效。
struct f2fs_nm_info->nat_blkaddr是NAT区域起始block号。
一个block中含有NAT_ENTRY_PER_BLOCK个entry(455个),根据nid可以算出nat entry在第N个block中(见NAT_BLOCK_OFFSET宏),由于2个segment一组进行备份,所以nat entry实际在第【N*2】个block上(如果nat entry位于segment B中),或者在第【N*2-segment B中nid所在block的偏移量】个block上(如果nat entry位于segment A中)。
static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
pgoff_t block_off;
pgoff_t block_addr;
/* 这段注释会误导人理解下面的代码,请忽略 */
/*
* block_off = segment_off * 512 + off_in_segment
* OLD = (segment_off * 512) * 2 + off_in_segment
* NEW = 2 * (segment_off * 512 + off_in_segment) - off_in_segment
*/
/*
* block_off表示从nat area起始block算,start应该在第几个block上(不考虑segment备份).
* 一个block中可以存放NAT_ENTRY_PER_BLOCK个nid.
*/
block_off = NAT_BLOCK_OFFSET(start);
/*
* NAT区中2个segment互为备份,第一个记作segment A,第二个记作segment B.
*
* block_off << 1 表示从nat起始block开始,考虑备份的情况下,nat entry位于第几个block上.
* nm_i->nat_blkaddr + (block_off << 1)表示nat entry位于segment B时,
* 从nat起始block开始,nat entry在第几个block上.
*
* block_off & (sbi->blocks_per_seg - 1)表示nat entry所属block在segment B中的偏移量.
*
* block_addr表示nat entry位于segment A时,从NAT起始block开始,entry位于第几个blcok上.
*/
block_addr = (pgoff_t)(nm_i->nat_blkaddr +
(block_off << 1) -
(block_off & (sbi->blocks_per_seg - 1)));
/*
* nid对应的nm_i->nat_bitmap置位,表示nat entry位于segment B,
* 将block_addr再加上一个segment中的block数,算出从NAT起始block开始,
* entry位于第几个blcok上.*/
if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
block_addr += sbi->blocks_per_seg;
return block_addr;
}