aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);