summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChao Yu <chao2.yu@samsung.com>2016-01-26 02:40:44 -0500
committerJaegeuk Kim <jaegeuk@kernel.org>2016-02-22 19:07:23 -0500
commit3cf4574705b4e1a1a0aeaae0332e8c2c8b56cc8f (patch)
tree1080b5e5735ded164cf46b4d1e73d44b26528de2 /fs
parent81ca7350ce5ed438547ea769b0c33cb0abbd74ba (diff)
f2fs: introduce get_next_page_offset to speed up SEEK_DATA
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 <chao2.yu@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/f2fs/f2fs.h3
-rw-r--r--fs/f2fs/file.c2
-rw-r--r--fs/f2fs/node.c37
3 files changed, 40 insertions, 2 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 00bb83fc35e6..d86b52169d6e 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -551,6 +551,8 @@ struct dnode_of_data {
551 unsigned int ofs_in_node; /* data offset in the node page */ 551 unsigned int ofs_in_node; /* data offset in the node page */
552 bool inode_page_locked; /* inode page is locked or not */ 552 bool inode_page_locked; /* inode page is locked or not */
553 bool node_changed; /* is node block changed */ 553 bool node_changed; /* is node block changed */
554 char cur_level; /* level of hole node page */
555 char max_level; /* level of current page located */
554 block_t data_blkaddr; /* block address of the node block */ 556 block_t data_blkaddr; /* block address of the node block */
555}; 557};
556 558
@@ -1793,6 +1795,7 @@ int need_dentry_mark(struct f2fs_sb_info *, nid_t);
1793bool is_checkpointed_node(struct f2fs_sb_info *, nid_t); 1795bool is_checkpointed_node(struct f2fs_sb_info *, nid_t);
1794bool need_inode_block_update(struct f2fs_sb_info *, nid_t); 1796bool need_inode_block_update(struct f2fs_sb_info *, nid_t);
1795void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); 1797void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
1798pgoff_t get_next_page_offset(struct dnode_of_data *, pgoff_t);
1796int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); 1799int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
1797int truncate_inode_blocks(struct inode *, pgoff_t); 1800int truncate_inode_blocks(struct inode *, pgoff_t);
1798int truncate_xattr_node(struct inode *, struct page *); 1801int truncate_xattr_node(struct inode *, struct page *);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index e52af2d08864..8c51fc7d9396 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -358,7 +358,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
358 } else if (err == -ENOENT) { 358 } else if (err == -ENOENT) {
359 /* direct node does not exists */ 359 /* direct node does not exists */
360 if (whence == SEEK_DATA) { 360 if (whence == SEEK_DATA) {
361 pgofs = PGOFS_OF_NEXT_DNODE(pgofs, inode); 361 pgofs = get_next_page_offset(&dn, pgofs);
362 continue; 362 continue;
363 } else { 363 } else {
364 goto found; 364 goto found;
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 5e381b2772f2..eae8977a7277 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -403,6 +403,37 @@ cache:
403 up_write(&nm_i->nat_tree_lock); 403 up_write(&nm_i->nat_tree_lock);
404} 404}
405 405
406pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
407{
408 const long direct_index = ADDRS_PER_INODE(dn->inode);
409 const long direct_blks = ADDRS_PER_BLOCK;
410 const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
411 unsigned int skipped_unit = ADDRS_PER_BLOCK;
412 int cur_level = dn->cur_level;
413 int max_level = dn->max_level;
414 pgoff_t base = 0;
415
416 if (!dn->max_level)
417 return pgofs + 1;
418
419 while (max_level-- > cur_level)
420 skipped_unit *= NIDS_PER_BLOCK;
421
422 switch (dn->max_level) {
423 case 3:
424 base += 2 * indirect_blks;
425 case 2:
426 base += 2 * direct_blks;
427 case 1:
428 base += direct_index;
429 break;
430 default:
431 f2fs_bug_on(F2FS_I_SB(dn->inode), 1);
432 }
433
434 return ((pgofs - base) / skipped_unit + 1) * skipped_unit + base;
435}
436
406/* 437/*
407 * The maximum depth is four. 438 * The maximum depth is four.
408 * Offset[0] will have raw inode offset. 439 * Offset[0] will have raw inode offset.
@@ -495,7 +526,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
495 int offset[4]; 526 int offset[4];
496 unsigned int noffset[4]; 527 unsigned int noffset[4];
497 nid_t nids[4]; 528 nid_t nids[4];
498 int level, i; 529 int level, i = 0;
499 int err = 0; 530 int err = 0;
500 531
501 level = get_node_path(dn->inode, index, offset, noffset); 532 level = get_node_path(dn->inode, index, offset, noffset);
@@ -585,6 +616,10 @@ release_pages:
585release_out: 616release_out:
586 dn->inode_page = NULL; 617 dn->inode_page = NULL;
587 dn->node_page = NULL; 618 dn->node_page = NULL;
619 if (err == -ENOENT) {
620 dn->cur_level = i;
621 dn->max_level = level;
622 }
588 return err; 623 return err;
589} 624}
590 625