aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2014-04-14 22:19:28 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-05-06 21:21:54 -0400
commited57c27f736f6d8a51e442610c800ee0c3d83977 (patch)
treef1d453fae0ba5b9d5ca938fb0d57aedd762a5c58
parent15c6e3aae68d6167cba063387a59968f811c8268 (diff)
f2fs: remove costly dirty_dir_inode operations
This patch removes list opeations in handling dirty dir inodes. Previously, F2FS traverses whole the list of dirty dir inodes to check whether there is an existing inode or not, resulting in heavy CPU overheads. So this patch removes such the traverse operations by adding FI_DIRTY_DIR to indicate the inode lies on the list or not. Through this simple flag, we can remove redundant operations gracefully. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
-rw-r--r--fs/f2fs/checkpoint.c52
-rw-r--r--fs/f2fs/f2fs.h3
-rw-r--r--fs/f2fs/recovery.c18
3 files changed, 25 insertions, 48 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 2902f7d50770..744c68be2e15 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -552,14 +552,13 @@ fail_no_cp:
552static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) 552static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
553{ 553{
554 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 554 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
555 struct list_head *head = &sbi->dir_inode_list;
556 struct dir_inode_entry *entry;
557 555
558 list_for_each_entry(entry, head, list) 556 if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
559 if (unlikely(entry->inode == inode)) 557 return -EEXIST;
560 return -EEXIST;
561 558
562 list_add_tail(&new->list, head); 559 set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
560 F2FS_I(inode)->dirty_dir = new;
561 list_add_tail(&new->list, &sbi->dir_inode_list);
563 stat_inc_dirty_dir(sbi); 562 stat_inc_dirty_dir(sbi);
564 return 0; 563 return 0;
565} 564}
@@ -608,31 +607,26 @@ void add_dirty_dir_inode(struct inode *inode)
608void remove_dirty_dir_inode(struct inode *inode) 607void remove_dirty_dir_inode(struct inode *inode)
609{ 608{
610 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 609 struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
611 struct list_head *head;
612 struct dir_inode_entry *entry; 610 struct dir_inode_entry *entry;
613 611
614 if (!S_ISDIR(inode->i_mode)) 612 if (!S_ISDIR(inode->i_mode))
615 return; 613 return;
616 614
617 spin_lock(&sbi->dir_inode_lock); 615 spin_lock(&sbi->dir_inode_lock);
618 if (get_dirty_dents(inode)) { 616 if (get_dirty_dents(inode) ||
617 !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
619 spin_unlock(&sbi->dir_inode_lock); 618 spin_unlock(&sbi->dir_inode_lock);
620 return; 619 return;
621 } 620 }
622 621
623 head = &sbi->dir_inode_list; 622 entry = F2FS_I(inode)->dirty_dir;
624 list_for_each_entry(entry, head, list) { 623 list_del(&entry->list);
625 if (entry->inode == inode) { 624 F2FS_I(inode)->dirty_dir = NULL;
626 list_del(&entry->list); 625 clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
627 stat_dec_dirty_dir(sbi); 626 stat_dec_dirty_dir(sbi);
628 spin_unlock(&sbi->dir_inode_lock);
629 kmem_cache_free(inode_entry_slab, entry);
630 goto done;
631 }
632 }
633 spin_unlock(&sbi->dir_inode_lock); 627 spin_unlock(&sbi->dir_inode_lock);
628 kmem_cache_free(inode_entry_slab, entry);
634 629
635done:
636 /* Only from the recovery routine */ 630 /* Only from the recovery routine */
637 if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) { 631 if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
638 clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT); 632 clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
@@ -640,26 +634,6 @@ done:
640 } 634 }
641} 635}
642 636
643struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
644{
645
646 struct list_head *head;
647 struct inode *inode = NULL;
648 struct dir_inode_entry *entry;
649
650 spin_lock(&sbi->dir_inode_lock);
651
652 head = &sbi->dir_inode_list;
653 list_for_each_entry(entry, head, list) {
654 if (entry->inode->i_ino == ino) {
655 inode = entry->inode;
656 break;
657 }
658 }
659 spin_unlock(&sbi->dir_inode_lock);
660 return inode;
661}
662
663void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) 637void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
664{ 638{
665 struct list_head *head; 639 struct list_head *head;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 2c5a5dadae65..d3180f8c0f97 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -218,6 +218,7 @@ struct f2fs_inode_info {
218 nid_t i_xattr_nid; /* node id that contains xattrs */ 218 nid_t i_xattr_nid; /* node id that contains xattrs */
219 unsigned long long xattr_ver; /* cp version of xattr modification */ 219 unsigned long long xattr_ver; /* cp version of xattr modification */
220 struct extent_info ext; /* in-memory extent cache entry */ 220 struct extent_info ext; /* in-memory extent cache entry */
221 struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
221}; 222};
222 223
223static inline void get_extent_info(struct extent_info *ext, 224static inline void get_extent_info(struct extent_info *ext,
@@ -958,6 +959,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr)
958enum { 959enum {
959 FI_NEW_INODE, /* indicate newly allocated inode */ 960 FI_NEW_INODE, /* indicate newly allocated inode */
960 FI_DIRTY_INODE, /* indicate inode is dirty or not */ 961 FI_DIRTY_INODE, /* indicate inode is dirty or not */
962 FI_DIRTY_DIR, /* indicate directory has dirty pages */
961 FI_INC_LINK, /* need to increment i_nlink */ 963 FI_INC_LINK, /* need to increment i_nlink */
962 FI_ACL_MODE, /* indicate acl mode */ 964 FI_ACL_MODE, /* indicate acl mode */
963 FI_NO_ALLOC, /* should not allocate any blocks */ 965 FI_NO_ALLOC, /* should not allocate any blocks */
@@ -1222,7 +1224,6 @@ int get_valid_checkpoint(struct f2fs_sb_info *);
1222void set_dirty_dir_page(struct inode *, struct page *); 1224void set_dirty_dir_page(struct inode *, struct page *);
1223void add_dirty_dir_inode(struct inode *); 1225void add_dirty_dir_inode(struct inode *);
1224void remove_dirty_dir_inode(struct inode *); 1226void remove_dirty_dir_inode(struct inode *);
1225struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t);
1226void sync_dirty_dir_inodes(struct f2fs_sb_info *); 1227void sync_dirty_dir_inodes(struct f2fs_sb_info *);
1227void write_checkpoint(struct f2fs_sb_info *, bool); 1228void write_checkpoint(struct f2fs_sb_info *, bool);
1228void init_orphan_info(struct f2fs_sb_info *); 1229void init_orphan_info(struct f2fs_sb_info *);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index b1ae89f0f44e..9eb6487f383d 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -46,15 +46,17 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
46 struct inode *dir, *einode; 46 struct inode *dir, *einode;
47 int err = 0; 47 int err = 0;
48 48
49 dir = check_dirty_dir_inode(F2FS_SB(inode->i_sb), pino); 49 dir = f2fs_iget(inode->i_sb, pino);
50 if (!dir) { 50 if (IS_ERR(dir)) {
51 dir = f2fs_iget(inode->i_sb, pino); 51 err = PTR_ERR(dir);
52 if (IS_ERR(dir)) { 52 goto out;
53 err = PTR_ERR(dir); 53 }
54 goto out; 54
55 } 55 if (is_inode_flag_set(F2FS_I(dir), FI_DIRTY_DIR)) {
56 set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); 56 iput(dir);
57 } else {
57 add_dirty_dir_inode(dir); 58 add_dirty_dir_inode(dir);
59 set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
58 } 60 }
59 61
60 name.len = le32_to_cpu(raw_inode->i_namelen); 62 name.len = le32_to_cpu(raw_inode->i_namelen);