Skip to content

Commit

Permalink
f2fs: add new interfaces for extent tree
Browse files Browse the repository at this point in the history
Add a lookup and a insertion interface for extent tree.
The new lookup return the insert position and the prev/next
extents closest to the offset we lookup when find no match.
The new insertion uses above parameters to improve performance.

There are three possible insertions after the lookup in
f2fs_update_extent_tree, two of them insert parts of removed extent
back to tree, since no merge happens during this process, new insertion
skips the merge check in this scanario; the another insertion inserts a
new extent to tree, new insertion uses prev/next extent and insert
position to insert this extent directly, and save the time of searching
down the tree.

As long as tree remains unchanged between lookup and insertion, this
would work fine. And the new lookup would be useful when add
multi-blocks extent support for insertion interface.

Signed-off-by: Fan li <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
Fan Li authored and Jaegeuk Kim committed Aug 5, 2015
1 parent 86531d6 commit 0f825ee
Showing 1 changed file with 132 additions and 7 deletions.
139 changes: 132 additions & 7 deletions fs/f2fs/extent_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,136 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
return ret;
}


/*
* lookup extent at @fofs, if hit, return the extent
* if not, return NULL and
* @prev_ex: extent before fofs
* @next_ex: extent after fofs
* @insert_p: insert point for new extent at fofs
* in order to simpfy the insertion after.
* tree must stay unchanged between lookup and insertion.
*/
static struct extent_node *__lookup_extent_tree_ret(struct extent_tree *et,
unsigned int fofs, struct extent_node **prev_ex,
struct extent_node **next_ex,
struct rb_node ***insert_p,
struct rb_node **insert_parent)
{
struct rb_node **pnode = &et->root.rb_node;
struct rb_node *parent = NULL, *tmp_node;
struct extent_node *en;

if (et->cached_en) {
struct extent_info *cei = &et->cached_en->ei;

if (cei->fofs <= fofs && cei->fofs + cei->len > fofs)
return et->cached_en;
}

while (*pnode) {
parent = *pnode;
en = rb_entry(*pnode, struct extent_node, rb_node);

if (fofs < en->ei.fofs)
pnode = &(*pnode)->rb_left;
else if (fofs >= en->ei.fofs + en->ei.len)
pnode = &(*pnode)->rb_right;
else
return en;
}

*insert_p = pnode;
*insert_parent = parent;

en = rb_entry(parent, struct extent_node, rb_node);
tmp_node = parent;
if (parent && fofs > en->ei.fofs)
tmp_node = rb_next(parent);
*next_ex = tmp_node ?
rb_entry(tmp_node, struct extent_node, rb_node) : NULL;

tmp_node = parent;
if (parent && fofs < en->ei.fofs)
tmp_node = rb_prev(parent);
*prev_ex = tmp_node ?
rb_entry(tmp_node, struct extent_node, rb_node) : NULL;

return NULL;
}

static struct extent_node *__insert_extent_tree_ret(struct f2fs_sb_info *sbi,
struct extent_tree *et, struct extent_info *ei,
struct extent_node **den,
struct extent_node *prev_ex,
struct extent_node *next_ex,
struct rb_node **insert_p,
struct rb_node *insert_parent)
{
struct rb_node **p = &et->root.rb_node;
struct rb_node *parent = NULL;
struct extent_node *en = NULL;
int merged = 0;

if (prev_ex && __is_back_mergeable(ei, &prev_ex->ei)) {
f2fs_bug_on(sbi, !den);
merged = 1;
prev_ex->ei.len += ei->len;
ei = &prev_ex->ei;
en = prev_ex;
}
if (next_ex && __is_front_mergeable(ei, &next_ex->ei)) {
f2fs_bug_on(sbi, !den);
if (merged++) {
__detach_extent_node(sbi, et, prev_ex);
*den = prev_ex;
}
next_ex->ei.fofs = ei->fofs;
next_ex->ei.blk = ei->blk;
next_ex->ei.len += ei->len;
en = next_ex;
}
if (merged)
goto update_out;

if (insert_p && insert_parent) {
parent = insert_parent;
p = insert_p;
goto do_insert;
}

while (*p) {
parent = *p;
en = rb_entry(parent, struct extent_node, rb_node);

if (ei->fofs < en->ei.fofs)
p = &(*p)->rb_left;
else if (ei->fofs >= en->ei.fofs + en->ei.len)
p = &(*p)->rb_right;
else
f2fs_bug_on(sbi, 1);
}
do_insert:
en = __attach_extent_node(sbi, et, ei, parent, p);
if (!en)
return NULL;
update_out:
if (en->ei.len > et->largest.len)
et->largest = en->ei;
et->cached_en = en;
return en;
}

/* return true, if on-disk extent should be updated */
static bool f2fs_update_extent_tree(struct inode *inode, pgoff_t fofs,
block_t blkaddr)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et = F2FS_I(inode)->extent_tree;
struct extent_node *en = NULL, *en1 = NULL, *en2 = NULL, *en3 = NULL;
struct extent_node *den = NULL;
struct extent_node *den = NULL, *prev_ex = NULL, *next_ex = NULL;
struct extent_info ei, dei, prev;
struct rb_node **insert_p = NULL, *insert_parent = NULL;
unsigned int endofs;

if (!et)
Expand All @@ -332,36 +453,40 @@ static bool f2fs_update_extent_tree(struct inode *inode, pgoff_t fofs,
f2fs_drop_largest_extent(inode, fofs);

/* 1. lookup and remove existing extent info in cache */
en = __lookup_extent_tree(et, fofs);
en = __lookup_extent_tree_ret(et, fofs, &prev_ex, &next_ex,
&insert_p, &insert_parent);
if (!en)
goto update_extent;

dei = en->ei;
__detach_extent_node(sbi, et, en);

/* 2. if extent can be split more, split and insert the left part */
/* 2. if extent can be split, try to split it */
if (dei.len > F2FS_MIN_EXTENT_LEN) {
/* insert left part of split extent into cache */
if (fofs - dei.fofs >= F2FS_MIN_EXTENT_LEN) {
set_extent_info(&ei, dei.fofs, dei.blk,
fofs - dei.fofs);
en1 = __insert_extent_tree(sbi, et, &ei, NULL);
fofs - dei.fofs);
en1 = __insert_extent_tree_ret(sbi, et, &ei, NULL,
NULL, NULL, NULL, NULL);
}

/* insert right part of split extent into cache */
endofs = dei.fofs + dei.len - 1;
if (endofs - fofs >= F2FS_MIN_EXTENT_LEN) {
set_extent_info(&ei, fofs + 1,
fofs - dei.fofs + dei.blk + 1, endofs - fofs);
en2 = __insert_extent_tree(sbi, et, &ei, NULL);
en2 = __insert_extent_tree_ret(sbi, et, &ei, NULL,
NULL, NULL, NULL, NULL);
}
}

update_extent:
/* 3. update extent in extent cache */
if (blkaddr) {
set_extent_info(&ei, fofs, blkaddr, 1);
en3 = __insert_extent_tree(sbi, et, &ei, &den);
en3 = __insert_extent_tree_ret(sbi, et, &ei, &den,
prev_ex, next_ex, insert_p, insert_parent);

/* give up extent_cache, if split and small updates happen */
if (dei.len >= 1 &&
Expand Down

0 comments on commit 0f825ee

Please sign in to comment.