diff options
-rw-r--r-- | fs/f2fs/checkpoint.c | 52 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 3 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 18 |
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: | |||
552 | static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new) | 552 | static 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) | |||
608 | void remove_dirty_dir_inode(struct inode *inode) | 607 | void 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 | ||
635 | done: | ||
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 | ||
643 | struct 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 | |||
663 | void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi) | 637 | void 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 | ||
223 | static inline void get_extent_info(struct extent_info *ext, | 224 | static inline void get_extent_info(struct extent_info *ext, |
@@ -958,6 +959,7 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr) | |||
958 | enum { | 959 | enum { |
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 *); | |||
1222 | void set_dirty_dir_page(struct inode *, struct page *); | 1224 | void set_dirty_dir_page(struct inode *, struct page *); |
1223 | void add_dirty_dir_inode(struct inode *); | 1225 | void add_dirty_dir_inode(struct inode *); |
1224 | void remove_dirty_dir_inode(struct inode *); | 1226 | void remove_dirty_dir_inode(struct inode *); |
1225 | struct inode *check_dirty_dir_inode(struct f2fs_sb_info *, nid_t); | ||
1226 | void sync_dirty_dir_inodes(struct f2fs_sb_info *); | 1227 | void sync_dirty_dir_inodes(struct f2fs_sb_info *); |
1227 | void write_checkpoint(struct f2fs_sb_info *, bool); | 1228 | void write_checkpoint(struct f2fs_sb_info *, bool); |
1228 | void init_orphan_info(struct f2fs_sb_info *); | 1229 | void 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); |