f 2 fsシリーズの4:書き込み操作に関する流れ


背景
ファイルシステムのデータlayoutに慣れてから、メインのIOパス(特に書き込み操作)を理解すると、ファイルシステムを把握するためには必ず噛まなければならない骨です.F 2 FSも同様に、IO関連の主要な段階は、書き込み提出を含む.チェックポイントGC
提出する
IO関連データ構造
最も主要な二つのデータ構造は以下の通りである.
 struct f2fs_io_info {
        struct f2fs_sb_info *sbi;       /* f2fs_sb_info pointer */
        nid_t ino;              /* inode number */
        enum page_type type;    /* contains DATA/NODE/META/META_FLUSH */
        enum temp_type temp;    /* contains HOT/WARM/COLD */
        int op;                 /* contains REQ_OP_ */
        int op_flags;           /* req_flag_bits */
        block_t new_blkaddr;    /* new block address to be written */
        block_t old_blkaddr;    /* old block address before Cow */
        struct page *page;      /* page to be written */
        struct page *encrypted_page;    /* encrypted page */
        struct list_head list;          /* serialize IOs */
        bool submitted;         /* indicate IO submission */
        int need_lock;          /* indicate we need to lock cp_rwsem */
        bool in_list;           /* indicate fio is in io_list */
        bool is_meta;           /* indicate borrow meta inode mapping or not */
        bool retry;             /* need to reallocate block address */
        enum iostat_type io_type;       /* io type */
        struct writeback_control *io_wbc; /* writeback control */
        unsigned char version;          /* version of the node */
};

#define is_read_io(rw) ((rw) == READ)
struct f2fs_bio_info {
        struct f2fs_sb_info *sbi;       /* f2fs superblock */
        struct bio *bio;                /* bios to merge */
        sector_t last_block_in_bio;     /* last block number */
        struct f2fs_io_info fio;        /* store buffered io info. */
        struct rw_semaphore io_rwsem;   /* blocking op for bio */
        spinlock_t io_lock;             /* serialize DATA/NODE IOs */
        struct list_head io_list;       /* track fios */
};
page cacheとのインタラクション
主なコードはf 2 fs_です.file_operationsで実現され、ヘッダファイルはf 2 fs.hにあります.
fs/f 2 fs/f 2 fs.hには、ディレクトリ、ファイル、inodeなどの主要なデータ構造などが記載されています.以下の通りです
extern const struct file_operations f2fs_dir_operations;
extern const struct file_operations f2fs_file_operations;
extern const struct inode_operations f2fs_file_inode_operations;
extern const struct address_space_operations f2fs_dblock_aops;
extern const struct address_space_operations f2fs_node_aops;
extern const struct address_space_operations f2fs_meta_aops;
extern const struct inode_operations f2fs_dir_inode_operations;
extern const struct inode_operations f2fs_symlink_inode_operations;
extern const struct inode_operations f2fs_encrypted_symlink_inode_operations;
extern const struct inode_operations f2fs_special_inode_operations;
このうち、上記のファイルに関する操作はf 2 fs_である.file_operationsは、write、read、seek、openなどの標準操作をサポートします.具体的なコードは参照できます.fs/f 2 fs/file.c:
const struct file_operations f2fs_file_operations = {
        .llseek         = f2fs_llseek,
        .read_iter      = generic_file_read_iter,
        .write_iter     = f2fs_file_write_iter,
        .open           = f2fs_file_open,
        .release        = f2fs_release_file,
        .mmap           = f2fs_file_mmap,
        .flush          = f2fs_file_flush,
        .fsync          = f2fs_sync_file,
        .fallocate      = f2fs_fallocate,
        .unlocked_ioctl = f2fs_ioctl,
#ifdef CONFIG_COMPAT
        .compat_ioctl   = f2fs_compat_ioctl,
#endif
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
};
その中の上のf 2 fs_file_write_iterはケネルのpage cache機構を通ります.file_write_iter->ジェネリックfile_write_iter->ジェネリックfile_ディレクト.write->filemap_write_and_waitrange->filemap_fdatawriteランゲ->ドドwritepages->generic_writepages->write_cachepages->>_uwritepage
最後にf 2 fsを呼び出してパージcacheに登録する_u uwritepage関数f 2 fs_write_meta_page/f 2 fs_write_node_page/f 2 fs_write_data_pageはそれぞれSSA/node/dataタイプのデータエリアを書きます.
ヽoo://workspace/linux-41.110/fs/f 2 fs$grep'.writepage'*-rchocpoint.c:writepage=f 2 fs_write_meta_page,checkpoint.c:.writepages=f 2 fs_write_meta_pages、data.c:.writepage=f 2 fs_write_data_page,data.c:.writepages=f 2 fs_write_data_pages、node.c:.writepage=f 2 fs_write_node_page,node.c:.writepages=f 2 fs_write_node_pages、
ここで、f 2 fsはmeta/node/data領域の読み書きモードに対して異なるので、以下の注釈を参照してください.
/*
 * The below are the page types of bios used in submit_bio().
 * The available types are:
 * DATA                 User data pages. It operates as async mode.
 * NODE                 Node pages. It operates as async mode.
 * META                 FS metadata pages such as SIT, NAT, CP.
 * NR_PAGE_TYPE         The number of page types.
 * META_FLUSH           Make sure the previous pages are written
 *                      with waiting the bio's completion
 * ...                  Only can be used with META.
 */
#define PAGE_TYPE_OF_BIO(type)  ((type) > META ? META : (type))
enum page_type {
        DATA,
        NODE,
        META,
        NR_PAGE_TYPE,
        META_FLUSH,
        INMEM,          /* the below types are used by tracepoints only. */
        INMEM_DROP,
        INMEM_INVALIDATE,
        INMEM_REVOKE,
        IPU,
        OPU,
};
次は三つのタイプの書き込みとパスカットのやりとりを見ます.
write_meta_page
まずwriteを見ますmeta_page:f 2 fs_write_meta_page->f 2 fs_write_meta_page->f 2 fs_ドドドドwrite_meta_page()->f 2 fs_submit_page_write()->構造fio,submit_mergedビオ()->>_submit_ビオ()
上のf 2 fs_write_meta_pageの主な流れは以下の通りです.
void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
                                        enum iostat_type io_type)
{
        struct f2fs_io_info fio = {
                .sbi = sbi,
                .type = META,
                .temp = HOT,
                .op = REQ_OP_WRITE,
                .op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
                .old_blkaddr = page->index,
                .new_blkaddr = page->index,
                .page = page,
                .encrypted_page = NULL,
                .in_list = false,
        };

        if (unlikely(page->index >= MAIN_BLKADDR(sbi)))
                fio.op_flags &= ~REQ_META;

        set_page_writeback(page);
        ClearPageError(page);
        f2fs_submit_page_write(&fio);

        f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE);
}
最終的にsubmit_を通過しましたmergedビオはIO要求を汎用ブロック層に落として、上の呼び出しが完了した後、metaデータは実際に既にwrite backをディスクに書き込みました.
write_node_page
f 2 fs_write_node_pageは___を呼びますwrite_node_page()は、後者が先にnodeタイプのf 2 fs_を作ります.オウinfo、汚いページを設定し、書き込み関数を直接呼び出します.
  .............
  set_page_writeback(page);
        ClearPageError(page);

        if (f2fs_in_warm_node_list(sbi, page)) {
                seq = f2fs_add_fsync_node_entry(sbi, page);
                if (seq_id)
                        *seq_id = seq;
        }

        fio.old_blkaddr = ni.blk_addr;
        f2fs_do_write_node_page(nid, &fio);
        set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
        dec_page_count(sbi, F2FS_DIRTY_NODES);
        up_read(&sbi->node_write);
nodeタイプのデータが見えます.上に戻ったら、データを落とします.
write_data_page
data関連の操作は主にfs/f 2 fs/data.cにあります.
const struct address_space_operations f2fs_dblock_aops = {
        .readpage       = f2fs_read_data_page,
        .readpages      = f2fs_read_data_pages,
        .writepage      = f2fs_write_data_page,
        .writepages     = f2fs_write_data_pages,
        .write_begin    = f2fs_write_begin, //     
        .write_end      = f2fs_write_end, // set_page_dirty
        .set_page_dirty = f2fs_set_data_page_dirty,
        .invalidatepage = f2fs_invalidate_page,
        .releasepage    = f2fs_release_page,
        .direct_IO      = f2fs_direct_IO,
        .bmap           = f2fs_bmap,
#ifdef CONFIG_MIGRATION
        .migratepage    = f2fs_migrate_page,
#endif
};
f 2 fs_write_data_pageは___を呼びますwrite_data_page().同じくdataタイプのf 2 fs_を構築します.オウinfo、そしてdrop page cacheは、inodeに対応するdirty page cacheをカウントダウンして、ケネルのバックグラウンドでpage cacheのスレッドを使ってデータをディスクにこすります.
        if (f2fs_is_drop_cache(inode))
                goto out;
                ........
              inode_dec_dirty_pages(inode);
        if (err)
                ClearPageUptodate(page);

        if (wbc->for_reclaim) {
                f2fs_submit_merged_write_cond(sbi, inode, 0, page->index, DATA);
                clear_inode_flag(inode, FI_HOT_DATA);
                f2fs_remove_dirty_inode(inode);
                submitted = NULL;
        }
                ......
チェックポイント
Main araはdataとnodeのjurnalが書いたエリアと考えられます.SSA(share segment ara)はNAT/SITのjurnalエリアと考えられます.check pointの場合、これらをSSAに書きますが、NAT/SITに落ちていないデータはそれぞれのエリアに書きます.
f 2 fsのlogs-structure特性のため、データブロックを書くたびに、direct node,NAT,SITをそれぞれ変更する必要があります.特にNATとSIT領域は、一つのentry数バイトの情報だけを修正する必要があるかもしれません.全体のpageを書き換えることによって、ファイルシステムの性能とSSDの寿命が大幅に低下します.f 2 fsは、jurnalの機構を使用して、NATとSITの書き込み回数を減少させる.jurnalとは、NATとSITの変更をf 2 fs_に書くことです.summary_blockの中で、checkpointを書く時、dirtyのSITとNAT領域を書き込みます.
GC
上でチェックポイントをしたら、SSAエリアから放出されるNAT/SITのデータはリリースされます.これはGCに任せてもいいです.
セレクションを単位とした二種類のvictim戦略:最も有効なblockの数を持つセレクション:foreground cleaning processは、最も古いblocks平均ageのsection:background cleaning processを持っています.