nat journal

一些零散的问题,记录一下。

问题1:remove_nats_in_journal为什么需nm_i->available_nids--

f2fs_flush_nat_entries --> remove_nats_in_journal  --> __alloc_nat_entry分配一个nat entry并没有增加nm_i->available_nid计数,后面执行__flush_nat_entry_set -->

if (nat_get_blkaddr(ne) == NULL_ADDR) {
            add_free_nid(sbi, nid, false, true);
}会nm_i->available_nids++;

这会导致计数错误,所以在f2fs_flush_nat_entries --> remove_nats_in_journal :

if (!get_nat_flag(ne, IS_DIRTY) &&
                le32_to_cpu(raw_ne.block_addr) == NULL_ADDR) {
            spin_lock(&nm_i->nid_list_lock);
            nm_i->available_nids--;
            spin_unlock(&nm_i->nid_list_lock);
        }

注:IS_DIRTY是并发流程用到的

thread1:

remove_nats_in_journal  -->down_write(&curseg->journal_rwsem) -->  __set_nat_cache_dirty --> set_nat_flag(ne, IS_DIRTY, true) --> up_write(&curseg->journal_rwsem)
上面的if (!get_nat_flag(ne, IS_DIRTY)成立,计数减1

thread2:

remove_nats_in_journal  --> down_write(&curseg->journal_rwsem) 拿到锁执行后面的代码,由于thread1已经设置了IS_DIRTY,所以这个执行流if (!get_nat_flag(ne, IS_DIRTY)不成立,就不会减计数值了。

问题2:__set_nat_cache_dirty中的if条件中的红色部分怎么理解?

static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
                        struct nat_entry *ne)
{
    struct nat_entry_set *head;
    bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR;

    if (!new_ne)
        head = __grab_nat_entry_set(nm_i, ne);

    /*
     * update entry_cnt in below condition:
     * 1. update NEW_ADDR to valid block address;
     * 2. update old block address to new one;
     */
    if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) ||
                !get_nat_flag(ne, IS_DIRTY)
))
        head->entry_cnt++;

git log搜一下don't track new nat entry in nat set提交记录

理解如下:Nat entry set is used only in checkpoint(), and during checkpoint() we
    won't flush new nat entry with unallocated address, so we don't need to
    add new nat entry into nat set, then nat_entry_set::entry_cnt can
    indicate actual entry count we need to flush in checkpoint().

!new_ne表示不是“unallocated address”,所以需要将这个ne一到nat entry set中。并发执行时,第一个执行流定会执行红字(注意,因为new_ne是false,所以是清除IS_PREALLOC):

if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) ||
                !get_nat_flag(ne, IS_DIRTY)))
        head->entry_cnt++;

    set_nat_flag(ne, IS_PREALLOC, new_ne);

接着set_nat_flag(ne, IS_DIRTY, true);设置IS_DIRTY

第二个执行流执行时,get_nat_flag(ne, IS_PREALLOC)、 !get_nat_flag(ne, IS_DIRTY)都是不成立的就不会增加 head->entry_cnt。

问题3:nat set list中的struct nat_entry何时写入journal

__flush_nat_entry_set把nat set list中的struct nat_entry写入journal

if (to_journal) {
            offset = f2fs_lookup_journal_in_cursum(journal,
                            NAT_JOURNAL, nid, 1);
            f2fs_bug_on(sbi, offset < 0);
            raw_ne = &nat_in_journal(journal, offset);
            nid_in_journal(journal, offset) = cpu_to_le32(nid);
        } 

……

raw_nat_from_node_info(raw_ne, &ne->ni);
        nat_reset_flag(ne);
        __clear_nat_cache_dirty(NM_I(sbi), set, ne);

问题4:journal中的nat entry去了哪里

1)umount时:f2fs_flush_nat_entries ---> remove_nats_in_journal

2)curseg空间不足:f2fs_flush_nat_entries --->  if (cpc->reason & CP_UMOUNT ||
        !__has_cursum_space(journal,
            nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))
        remove_nats_in_journal(sbi);

 remove_nats_in_journal(sbi) --> __set_nat_cache_dirty  --> list_move_tail(&ne->list, &head->entry_list);写入nat set list

问题5:f2fs_flush_nat_entries为什么要排序

f2fs_flush_nat_entries --->

    for (idx = 0; idx < found; idx++)
            __adjust_nat_entry_set(setvec[idx], &sets,
                        MAX_NAT_JENTRIES(journal));

上面__adjust_nat_entry_set代码,根据struct nat_entry_set->entry_cnt排序,链表头小,链表尾大,为什么要这样做?

1)生成nat entry,记录在CURSEG_HOT_DATA curseg的journal中(这是内存中的数据结构)。

2)remove_nats_in_journal:

2.1)如果nat cache中没有(struct f2fs_nm_info->nat_root),__alloc_nat_entry新分配一个nat entry并初始化,__init_nat_entry将新分配的nat entry加入nat cache(struct f2fs_nm_info->nat_root)和clean链表中(struct f2fs_nm_info->nat_entries)。

2.2)__set_nat_cache_dirty将nat entry从clean链表中移至set list链表(struct f2fs_nm_info->entry_list)。

3)remove_nats_in_journal --> __set_nat_cache_dirty把非NEW_ADDR的nat entry加入到set list中(这是内存中的数据结构)。

注1:NEW_ADDR代表什么意思要通俗的写出来

注2:set list作用要写出来

4)f2fs_write_checkpoint --> f2fs_flush_nat_entries --> __flush_nat_entry_set将set list中的nat entry写入curseg journal(如果journal中空间足够),或者写入nat block(如果journal中空间不足)。

5)__flush_nat_entry_set最后代码说明,如果是NULL_ADDR,直接add_free_nid,与bitmap没有关系。freenid、bitmap的来龙去脉要搞清楚。还说明了,nat entry先是存在内存中的,然后刷入journal。

6)f2fs_get_node_info中描述了nat cache、journal、nat block一个简单的关系。

7)对于inline文件,f2fs_file_write_iter --> f2fs_file_write_iter --> f2fs_file_write_iter --> __get_node_page --> __get_node_page --> f2fs_get_node_info --> f2fs_get_meta_page读出nid所属的nat block,存放在page中。在page中找到disk nat entry(代码中用f2fs_nat_entry表示),接着通过cache_nat_entry --> __alloc_nat_entry分配一个新的mem nat entry(代码中用nat_entry表示),cache_nat_entry --> __init_nat_entry --> node_info_from_raw_nat将f2fs_nat_entry信息复制到nat_entry,在__init_nat_entry会将nat_entry加入到nat cache(代码中用struct f2fs_nm_info->nat_root管理)和nat clean list中(代码中用struct f2fs_nm_info->nat_entries管理)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值