Skip to content

Commit

Permalink
f2fs: introduce get_next_page_offset to speed up SEEK_DATA
Browse files Browse the repository at this point in the history
When seeking data in ->llseek, if we encounter a big hole which covers
several dnode pages, we will try to seek data from index of page which
is the first page of next dnode page, at most we could skip searching
(ADDRS_PER_BLOCK - 1) pages.

However it's still not efficient, because if our indirect/double-indirect
pointer are NULL, there are no dnode page locate in the tree indirect/
double-indirect pointer point to, it's not necessary to search the whole
region.

This patch introduces get_next_page_offset to calculate next page offset
based on current searching level and max searching level returned from
get_dnode_of_data, with this, we could skip searching the entire area
indirect or double-indirect node block is not exist.

Signed-off-by: Chao Yu <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
chaseyu authored and Jaegeuk Kim committed Feb 23, 2016
1 parent 81ca735 commit 3cf4574
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
3 changes: 3 additions & 0 deletions fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ struct dnode_of_data {
unsigned int ofs_in_node; /* data offset in the node page */
bool inode_page_locked; /* inode page is locked or not */
bool node_changed; /* is node block changed */
char cur_level; /* level of hole node page */
char max_level; /* level of current page located */
block_t data_blkaddr; /* block address of the node block */
};

Expand Down Expand Up @@ -1793,6 +1795,7 @@ int need_dentry_mark(struct f2fs_sb_info *, nid_t);
bool is_checkpointed_node(struct f2fs_sb_info *, nid_t);
bool need_inode_block_update(struct f2fs_sb_info *, nid_t);
void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
pgoff_t get_next_page_offset(struct dnode_of_data *, pgoff_t);
int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
int truncate_inode_blocks(struct inode *, pgoff_t);
int truncate_xattr_node(struct inode *, struct page *);
Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
} else if (err == -ENOENT) {
/* direct node does not exists */
if (whence == SEEK_DATA) {
pgofs = PGOFS_OF_NEXT_DNODE(pgofs, inode);
pgofs = get_next_page_offset(&dn, pgofs);
continue;
} else {
goto found;
Expand Down
37 changes: 36 additions & 1 deletion fs/f2fs/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,37 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
up_write(&nm_i->nat_tree_lock);
}

pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
{
const long direct_index = ADDRS_PER_INODE(dn->inode);
const long direct_blks = ADDRS_PER_BLOCK;
const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
unsigned int skipped_unit = ADDRS_PER_BLOCK;
int cur_level = dn->cur_level;
int max_level = dn->max_level;
pgoff_t base = 0;

if (!dn->max_level)
return pgofs + 1;

while (max_level-- > cur_level)
skipped_unit *= NIDS_PER_BLOCK;

switch (dn->max_level) {
case 3:
base += 2 * indirect_blks;
case 2:
base += 2 * direct_blks;
case 1:
base += direct_index;
break;
default:
f2fs_bug_on(F2FS_I_SB(dn->inode), 1);
}

return ((pgofs - base) / skipped_unit + 1) * skipped_unit + base;
}

/*
* The maximum depth is four.
* Offset[0] will have raw inode offset.
Expand Down Expand Up @@ -495,7 +526,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
int offset[4];
unsigned int noffset[4];
nid_t nids[4];
int level, i;
int level, i = 0;
int err = 0;

level = get_node_path(dn->inode, index, offset, noffset);
Expand Down Expand Up @@ -585,6 +616,10 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
release_out:
dn->inode_page = NULL;
dn->node_page = NULL;
if (err == -ENOENT) {
dn->cur_level = i;
dn->max_level = level;
}
return err;
}

Expand Down

0 comments on commit 3cf4574

Please sign in to comment.