/*
* Caller should call f2fs_put_dnode(dn).
* Also, it should grab and release a rwsem by calling f2fs_lock_op() and
* f2fs_unlock_op() only if ro is not set RDONLY_NODE.
* In the case of RDONLY_NODE, we don't need to care about mutex.
*/
int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
struct page *npage[4];
struct page *parent = NULL;
int offset[4];
unsigned int noffset[4];
nid_t nids[4];
int level, i;
int err = 0;
level = get_node_path(F2FS_I(dn->inode), index, offset, noffset);
nids[0] = dn->inode->i_ino; //nids[0],代表inode,其nid与i_ino是相等的
npage[0] = dn->inode_page; //npage[0], inode 对应的inode_page
if (!npage[0]) {
npage[0] = get_node_page(sbi, nids[0]);//如果indoe_page为空,则重新获取indoe page
//从sbi node_inode -> i_mapping里面读取
if (IS_ERR(npage[0]))
return PTR_ERR(npage[0]);
}
/* if inline_data is set, should not report any block indices */
if (f2fs_has_inline_data(dn->inode) && index) {
err = -ENOENT;
f2fs_put_page(npage[0], 1);
goto release_out;
}
parent = npage[0]; //将parent首先设置为inode
if (level != 0)
nids[1] = get_nid(parent, offset[0], true);//如果level为0,说明inode中包含地址,后面会
//直接设置dn的信息:
//dn->inode_page = npage[0]
//dn->nid = nids[0], 为inode的nid
//dn->ofs_in_node = offset[0], 为inode中的offset
//dn->node_page = npage[0], 为inode_page,
//dn->data_blkaddr,根据inode_page与ofs_in_node,计算data block地址
dn->inode_page = npage[0];
dn->inode_page_locked = true;
/* get indirect or direct nodes */
/*
* 如果 level != 0, 则根据返回的level, noffset, offset信息
* 计算nid, node_page,最后在dn里面填充相应的信息
*/
for (i = 1; i <= level; i++) {
bool done = false;
if (!nids[i] && mode == ALLOC_NODE) {
/* alloc new node,如果不存在,则申请一个新的nid */
if (!alloc_nid(sbi, &(nids[i]))) {
err = -ENOSPC;
goto release_pages;
}
dn->nid = nids[i];
/*
* 如果nid为新申请的nid,得到此nid对应的node_page
*/
npage[i] = new_node_page(dn, noffset[i], NULL);
if (IS_ERR(npage[i])) {
alloc_nid_failed(sbi, nids[i]);
err = PTR_ERR(npage[i]);
goto release_pages;
}
/*
* 若i == 1, nids[1] = 为新申请的nid, 则将此nid与inode联系起来,
* 即,inode_page -> i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
* 若 i != 1, 则,说明此时i > 1, 此nid已为indirect node,
* 则设置rn->in.nid[off] = cpu_to_le32(nid);
*/
set_nid(parent, offset[i - 1], nids[i], i == 1);
alloc_nid_done(sbi, nids[i]);
done = true;
} else if (mode == LOOKUP_NODE_RA && i == level && level > 1) {
npage[i] = get_node_page_ra(parent, offset[i - 1]);
if (IS_ERR(npage[i])) {
err = PTR_ERR(npage[i]);
goto release_pages;
}
done = true;
}
if (i == 1) {
dn->inode_page_locked = false;
unlock_page(parent);
} else {
f2fs_put_page(parent, 1);
}
if (!done) {
npage[i] = get_node_page(sbi, nids[i]);
if (IS_ERR(npage[i])) {
err = PTR_ERR(npage[i]);
f2fs_put_page(npage[0], 0);
goto release_out;
}
}
if (i < level) {
parent = npage[i];
nids[i + 1] = get_nid(parent, offset[i], false);
}
}
/*
* 最终赋值相应的信息给dn,
* 即,node_page 对应的nid
* ofs_in_node, node_page中的偏移量
* node_page, node_page
* data_blkaddr: 根据node_page中的偏移,得到最终的block addr
*/
dn->nid = nids[level];
dn->ofs_in_node = offset[level];
dn->node_page = npage[level];
dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
return 0;
release_pages:
f2fs_put_page(parent, 1);
if (i > 1)
f2fs_put_page(npage[0], 0);
release_out:
dn->inode_page = NULL;
dn->node_page = NULL;
return err;
}