这篇文章讲f2fs文件系统的截断,在调用这个函数之前会设置inode的i_size,这个函数完成在文件中i_size之后的数据的删除。其起始的函数是f2fs_truncate。
f2fs_truncate:检查inode的mode,如果不是REG或者是目录或者是LNK,那么直接返回。然后再调用f2fs_may_inline_data检查文件是否可以以内联的形式存放,如果不行,调用f2fs_convert_inline_inode来将内联的数据转换成正常索引的形式(目前还不知道这个地方有什么用)。接着调用truncate_blocks来进行真正的截断。最后修改inode的修改时间i_mtime,然后将inode设置为dirty。
int f2fs_truncate(struct inode *inode)
{
int err;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
return 0;
trace_f2fs_truncate(inode);
if (!f2fs_may_inline_data(inode)) {
err = f2fs_convert_inline_inode(inode);
if (err)
return err;
}
err = truncate_blocks(inode, i_size_read(inode), true);
if (err)
return err;
inode->i_mtime = inode->i_ctime = current_time(inode);
f2fs_mark_inode_dirty_sync(inode);
return 0;
}
truncate_blocks:完成真正的所有的截断。首先计算截断位置下一个block的块索引free_from,然后调用get_node_page读取inode对应的f2fs_inode。f2fs_has_inline_data检查是否存放的是内联数据,如果是就调用truncate_inline对内联数据进行truncate操作,然后马上将修改后的f2fs_inode进行set_dirty操作。如果没有内联数据就按照正常索引的形式进行截断:首先通过set_new_dnode和get_dnode_of_data来获取free_from所在的dnode,通过计算得到dnode中大于等于free_from的块地址的个数count。如果dnode中的ofs或者是当前的dnode是f2fs_inode,那么就调用函数truncate_data_blocks_range把当前dnode(这里拥有923个块地址的f2fs_inode姑且也算一个dnode)中索引大于等于free_from的块地址全部删除,上述操作是为了删除部分的块地址来消除dnode中的零头,后面的删除可以以dnode为单位进行删除了。接下来的截断就由truncate_inode_blcoks来完成剩余的block的删除,最后调用truncate_partial_data_page对from所在的block中剩余的部分进行块内的截断。
int truncate_blocks(struct inode *inode, u64 from, bool lock)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
unsigned int blocksize = inode->i_sb->s_blocksize;
struct dnode_of_data dn;
pgoff_t free_from;
int count = 0, err = 0;
struct page *ipage;
bool truncate_page = false;
trace_f2fs_truncate_blocks_enter(inode, from);
free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1);
if (free_from >= sbi->max_file_blocks)
goto free_partial;
if (lock)
f2fs_lock_op(sbi);
ipage = get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto out;
}
if (f2fs_has_inline_data(inode)) {
if (truncate_inline_inode(ipage, from))
set_page_dirty(ipage);
f2fs_put_page(ipage, 1);
truncate_page = true;
goto out;
}
set_new_dnode(&dn, inode, ipage, NULL, 0);
err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
if (err) {
if (err == -ENOENT)
goto free_next;
goto out;
}
count = ADDRS_PER_PAGE(dn.node_page, inode);
count -= dn.ofs_in_node;
f2fs_bug_on(sbi, count < 0);
if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
truncate_data_blocks_range(&dn, count);
free_from += count;
}
f2fs_put_dnode(&dn);
free_next:
err = truncate_inode_blocks(inode, free_from);
out:
if (lock)
f2fs_unlock_op(sbi);
free_partial:
if (!err)
err = truncate_partial_data_page(inode, from, truncate_page);
trace_f2fs_truncate_blocks_exit(inode, err);
return err;
}
truncate_inline_inode首先检查截断的位置from是否大于MAX_INLINE_DATA,这是最大的内联字节数。如果大于这个就直接返回。否则计算f2fs_inode中的内