1.前言
本文主要介绍f2fs写入流程. 写入流程主要分为meta, data, node的写入,本文主要介绍data的写入流程。
2.总体流程
sys_write
fdget
file_pos_read
vfs_write
file_pos_write
-
fdget是从当前进程的文件描述符表获取一个fd;
-
file_pos_read获取文件描述符当前的读写位置
-
vfs_write执行文件写入操作
-
file_pos_write更新文件的写入位置
3.vfs_write
vfs_write
rw_verify_area
file->f_op->write (do_sync_write)
generic_file_aio_write
__generic_file_aio_write
generic_segment_checks
generic_write_checks
generic_file_direct_write或generic_file_buffered_write
-
sys_write系统调用会调用到vfs_write,进而调用到file->f_op->write,这个write回调是在创建文件时初始化为inode->i_fops->write, 对于f2fs就是do_sync_write,它会进一步调用generic_file_aio_write->__generic_file_aio_write
-
__generic_file_aio_write通过generic_segment_checks来检查segment的数目和要写入数据的数目进行必要的检查,最终确定写入文件的位置和数据的数目;之后通过generic_write_checks进一步对写入文件的位置和数目进行检查
3.1 generic_file_direct_write
generic_file_direct_write
filemap_write_and_wait_range(mapping, pos, pos + write_len - 1)
do_writepages(mapping, &wbc)
mapping->a_ops->writepages(mapping, wbc)
generic_writepages(mapping, wbc)
write_cache_pages(mapping, wbc, __writepage, mapping)
对于直写的情况将执行generic_file_direct_write,它调用writepages回调,对于f2fs为f2fs_write_data_pages,进而它会执行generic_writepages,对于每一page都将调用 __writepage,实际上调用了mapping->a_ops->writepage(page, wbc)回调,对于f2fs即为f2fs_write_data_page
3.1.1 f2fs_write_data_page
f2fs_write_data_page
do_write_data_page(page)
get_dnode_of_data(&dn, page->index, RDONLY_NODE)
write_data_page(inode, page, &dn,old_blk_addr, &new_blk_addr);
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version)
do_write_page(sbi, page, old_blkaddr,new_blkaddr, &sum, DATA)
__add_sum_entry(sbi, type, sum, curseg->next_blkoff)
__refresh_next_blkoff(sbi, curseg)
refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr)
submit_write_page(sbi, page, *new_blkaddr, p_type)
do_submit_bio(sbi, type, false)
get_dnode_of_data:通过page->index查找dnode(直接node)中对应的block地址,保存在dn->data_blkaddr中
write_data_page:old_blk_addr为当前要写入的block的地址,new_blk_addr为下一个要写入的block地址
set_summary:由于要写入数据,需要更新current segment的summary, 此处是构造新的segment summary entry.
do_write_page: 执行page写入操作。
__add_sum_entry:更新current segment中要写入block的summary entry
__refresh_next_blkoff: 更新current sgement的下一个block offset, 根据SSR(thread mode)和LFS模式有所不同;
refresh_sit_entry:
submit_write_page:通过调用do_submit_bio->submit_bio提交给block层
3.2 .generic_file_buffered_write
generic_file_buffered_write
generic_perform_write(file, &i, pos)
a_ops->write_begin
iov_iter_copy_from_user_atomic
a_ops->write_end
f2fs_set_data_page_dirty
对于非直写的情况将调用generic_file_buffered_write。它将调用generic_perform_write(file, &i, pos)执行写入操作
f2fs_write_begin:a_ops->write_begin对应f2fs就是f2fs_write_begin。通过f2fs_write_begin确定了要写入的page对应的磁盘block地址。
iov_iter_copy_from_user_atomic:将用户空间数据拷贝到page;
a_ops->write_end->generic_write_end:当用户空间数据拷贝到page后,用作善后处理,标记页面为最新且是脏页,这样在sync时就会将这些页面写入磁盘
f2fs_set_data_page_dirty:在address space 中标记page为dirty