Loading Documentation/ABI/testing/sysfs-fs-f2fs +48 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,18 @@ Description: Controls the dirty page count condition for the in-place-update policies. What: /sys/fs/f2fs/<disk>/min_hot_blocks Date: March 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls the dirty page count condition for redefining hot data. What: /sys/fs/f2fs/<disk>/min_ssr_sections Date: October 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls the fee section threshold to trigger SSR allocation. What: /sys/fs/f2fs/<disk>/max_small_discards Date: November 2013 Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> Loading Loading @@ -102,6 +114,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls the idle timing. What: /sys/fs/f2fs/<disk>/iostat_enable Date: August 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls to enable/disable IO stat. What: /sys/fs/f2fs/<disk>/ra_nid_pages Date: October 2015 Contact: "Chao Yu" <chao2.yu@samsung.com> Loading @@ -122,6 +140,12 @@ Contact: "Shuoran Liu" <liushuoran@huawei.com> Description: Shows total written kbytes issued to disk. What: /sys/fs/f2fs/<disk>/feature Date: July 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Shows all enabled features in current device. What: /sys/fs/f2fs/<disk>/inject_rate Date: May 2016 Contact: "Sheng Yong" <shengyong1@huawei.com> Loading @@ -138,4 +162,27 @@ What: /sys/fs/f2fs/<disk>/reserved_blocks Date: June 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls current reserved blocks in system. Controls target reserved blocks in system, the threshold is soft, it could exceed current available user space. What: /sys/fs/f2fs/<disk>/current_reserved_blocks Date: October 2017 Contact: "Yunlong Song" <yunlong.song@huawei.com> Contact: "Chao Yu" <yuchao0@huawei.com> Description: Shows current reserved blocks in system, it may be temporarily smaller than target_reserved_blocks, but will gradually increase to target_reserved_blocks when more free blocks are freed by user later. What: /sys/fs/f2fs/<disk>/gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Do background GC agressively What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time Date: August 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls sleep time of GC urgent mode Documentation/filesystems/f2fs.txt +19 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,16 @@ io_bits=%u Set the bit size of write IO requests. It should be set with "mode=lfs". usrquota Enable plain user disk quota accounting. grpquota Enable plain group disk quota accounting. prjquota Enable plain project quota accounting. usrjquota=<file> Appoint specified file and type during mount, so that quota grpjquota=<file> information can be properly updated during recovery flow, prjjquota=<file> <quota file>: must be in root directory; jqfmt=<quota type> <quota type>: [vfsold,vfsv0,vfsv1]. offusrjquota Turn off user journelled quota. offgrpjquota Turn off group journelled quota. offprjjquota Turn off project journelled quota. quota Enable plain user disk quota accounting. noquota Disable all plain disk quota option. ================================================================================ DEBUGFS ENTRIES Loading Loading @@ -196,6 +206,15 @@ Files in /sys/fs/f2fs/<devname> gc_idle = 1 will select the Cost Benefit approach & setting gc_idle = 2 will select the greedy aproach. gc_urgent This parameter controls triggering background GCs urgently or not. Setting gc_urgent = 0 [default] makes back to default behavior, while if it is set to 1, background thread starts to do GC by given gc_urgent_sleep_time interval. gc_urgent_sleep_time This parameter controls sleep time for gc_urgent. 500 ms is set by default. See above gc_urgent. reclaim_segments This parameter controls the number of prefree segments to be reclaimed. If the number of prefree segments is larger than the number of segments Loading fs/ext4/inode.c +6 −0 Original line number Diff line number Diff line Loading @@ -5110,11 +5110,17 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) * If the inode is marked synchronous, we don't honour that here - doing * so would cause a commit on atime updates, which we don't bother doing. * We handle synchronous inodes at the highest possible level. * * If only the I_DIRTY_TIME flag is set, we can skip everything. If * I_DIRTY_TIME and I_DIRTY_SYNC is set, the only inode fields we need * to copy into the on-disk inode structure are the timestamp files. */ void ext4_dirty_inode(struct inode *inode, int flags) { handle_t *handle; if (flags == I_DIRTY_TIME) return; handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); if (IS_ERR(handle)) goto out; Loading fs/f2fs/acl.c +6 −2 Original line number Diff line number Diff line Loading @@ -207,15 +207,16 @@ static int __f2fs_set_acl(struct inode *inode, int type, void *value = NULL; size_t size = 0; int error; umode_t mode = inode->i_mode; switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl && !ipage) { error = posix_acl_update_mode(inode, &inode->i_mode, &acl); error = posix_acl_update_mode(inode, &mode, &acl); if (error) return error; set_acl_inode(inode, inode->i_mode); set_acl_inode(inode, mode); } break; Loading Loading @@ -249,6 +250,9 @@ static int __f2fs_set_acl(struct inode *inode, int type, int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; return __f2fs_set_acl(inode, type, acl, NULL); } Loading fs/f2fs/checkpoint.c +94 −26 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ struct kmem_cache *inode_entry_slab; void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) { set_ckpt_flags(sbi, CP_ERROR_FLAG); sbi->sb->s_flags |= MS_RDONLY; if (!end_io) f2fs_flush_merged_writes(sbi); } Loading Loading @@ -231,8 +230,9 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); } static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) static int __f2fs_write_meta_page(struct page *page, struct writeback_control *wbc, enum iostat_type io_type) { struct f2fs_sb_info *sbi = F2FS_P_SB(page); Loading @@ -245,7 +245,7 @@ static int f2fs_write_meta_page(struct page *page, if (unlikely(f2fs_cp_error(sbi))) goto redirty_out; write_meta_page(sbi, page); write_meta_page(sbi, page, io_type); dec_page_count(sbi, F2FS_DIRTY_META); if (wbc->for_reclaim) Loading @@ -264,6 +264,12 @@ redirty_out: return AOP_WRITEPAGE_ACTIVATE; } static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) { return __f2fs_write_meta_page(page, wbc, FS_META_IO); } static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { Loading @@ -284,7 +290,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, trace_f2fs_writepages(mapping->host, wbc, META); diff = nr_pages_to_write(sbi, META, wbc); written = sync_meta_pages(sbi, META, wbc->nr_to_write); written = sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO); mutex_unlock(&sbi->cp_mutex); wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); return 0; Loading @@ -296,7 +302,7 @@ skip_write: } long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write) long nr_to_write, enum iostat_type io_type) { struct address_space *mapping = META_MAPPING(sbi); pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX; Loading Loading @@ -347,7 +353,7 @@ continue_unlock: if (!clear_page_dirty_for_io(page)) goto continue_unlock; if (mapping->a_ops->writepage(page, &wbc)) { if (__f2fs_write_meta_page(page, &wbc, io_type)) { unlock_page(page); break; } Loading Loading @@ -395,24 +401,23 @@ const struct address_space_operations f2fs_meta_aops = { #endif }; static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e, *tmp; tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); retry: radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (!e) { e = tmp; if (radix_tree_insert(&im->ino_root, ino, e)) { spin_unlock(&im->ino_lock); radix_tree_preload_end(); goto retry; } if (unlikely(radix_tree_insert(&im->ino_root, ino, e))) f2fs_bug_on(sbi, 1); memset(e, 0, sizeof(struct ino_entry)); e->ino = ino; Loading @@ -420,6 +425,10 @@ retry: if (type != ORPHAN_INO) im->ino_num++; } if (type == FLUSH_INO) f2fs_set_bit(devidx, (char *)&e->dirty_device); spin_unlock(&im->ino_lock); radix_tree_preload_end(); Loading Loading @@ -448,7 +457,7 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* add new dirty ino entry into list */ __add_ino_entry(sbi, ino, type); __add_ino_entry(sbi, ino, 0, type); } void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) Loading @@ -474,7 +483,7 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) struct ino_entry *e, *tmp; int i; for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) { for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) { struct inode_management *im = &sbi->im[i]; spin_lock(&im->ino_lock); Loading @@ -488,6 +497,27 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) } } void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { __add_ino_entry(sbi, ino, devidx, type); } bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e; bool is_dirty = false; spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (e && f2fs_test_bit(devidx, (char *)&e->dirty_device)) is_dirty = true; spin_unlock(&im->ino_lock); return is_dirty; } int acquire_orphan_inode(struct f2fs_sb_info *sbi) { struct inode_management *im = &sbi->im[ORPHAN_INO]; Loading Loading @@ -524,7 +554,7 @@ void release_orphan_inode(struct f2fs_sb_info *sbi) void add_orphan_inode(struct inode *inode) { /* add new orphan ino entry into list */ __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO); __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO); update_inode_page(inode); } Loading @@ -548,7 +578,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) return err; } __add_ino_entry(sbi, ino, ORPHAN_INO); __add_ino_entry(sbi, ino, 0, ORPHAN_INO); inode = f2fs_iget_retry(sbi->sb, ino); if (IS_ERR(inode)) { Loading Loading @@ -582,11 +612,28 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) int recover_orphan_inodes(struct f2fs_sb_info *sbi) { block_t start_blk, orphan_blocks, i, j; int err; unsigned int s_flags = sbi->sb->s_flags; int err = 0; #ifdef CONFIG_QUOTA int quota_enabled; #endif if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) return 0; if (s_flags & MS_RDONLY) { f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs"); sbi->sb->s_flags &= ~MS_RDONLY; } #ifdef CONFIG_QUOTA /* Needed for iput() to work correctly and not trash data */ sbi->sb->s_flags |= MS_ACTIVE; /* Turn on quotas so that they are updated correctly */ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY); #endif start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi); Loading @@ -602,14 +649,22 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) err = recover_orphan_inode(sbi, ino); if (err) { f2fs_put_page(page, 1); return err; goto out; } } f2fs_put_page(page, 1); } /* clear Orphan Flag */ clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); return 0; out: #ifdef CONFIG_QUOTA /* Turn quotas off */ if (quota_enabled) f2fs_quota_off_umount(sbi->sb); #endif sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */ return err; } static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) Loading Loading @@ -905,7 +960,14 @@ retry: if (inode) { unsigned long cur_ino = inode->i_ino; if (is_dir) F2FS_I(inode)->cp_task = current; filemap_fdatawrite(inode->i_mapping); if (is_dir) F2FS_I(inode)->cp_task = NULL; iput(inode); /* We need to give cpu to another writers. */ if (ino == cur_ino) { Loading Loading @@ -953,7 +1015,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) update_inode_page(inode); iput(inode); } }; } return 0; } Loading Loading @@ -1018,7 +1080,7 @@ retry_flush_nodes: if (get_pages(sbi, F2FS_DIRTY_NODES)) { up_write(&sbi->node_write); err = sync_node_pages(sbi, &wbc); err = sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO); if (err) { up_write(&sbi->node_change); f2fs_unlock_all(sbi); Loading Loading @@ -1113,10 +1175,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct super_block *sb = sbi->sb; struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); u64 kbytes_written; int err; /* Flush all the NAT/SIT pages */ while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); if (unlikely(f2fs_cp_error(sbi))) return -EIO; } Loading Loading @@ -1195,7 +1258,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Flush all the NAT BITS pages */ while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); if (unlikely(f2fs_cp_error(sbi))) return -EIO; } Loading @@ -1206,6 +1269,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (unlikely(f2fs_cp_error(sbi))) return -EIO; /* flush all device cache */ err = f2fs_flush_device_cache(sbi); if (err) return err; /* write out checkpoint buffer at block 0 */ update_meta_page(sbi, ckpt, start_blk++); Loading Loading @@ -1250,7 +1318,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) percpu_counter_set(&sbi->alloc_valid_block_count, 0); /* Here, we only have one bio having CP pack */ sync_meta_pages(sbi, META_FLUSH, LONG_MAX); sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO); /* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback(sbi); Loading Loading
Documentation/ABI/testing/sysfs-fs-f2fs +48 −1 Original line number Diff line number Diff line Loading @@ -51,6 +51,18 @@ Description: Controls the dirty page count condition for the in-place-update policies. What: /sys/fs/f2fs/<disk>/min_hot_blocks Date: March 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls the dirty page count condition for redefining hot data. What: /sys/fs/f2fs/<disk>/min_ssr_sections Date: October 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls the fee section threshold to trigger SSR allocation. What: /sys/fs/f2fs/<disk>/max_small_discards Date: November 2013 Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com> Loading Loading @@ -102,6 +114,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls the idle timing. What: /sys/fs/f2fs/<disk>/iostat_enable Date: August 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls to enable/disable IO stat. What: /sys/fs/f2fs/<disk>/ra_nid_pages Date: October 2015 Contact: "Chao Yu" <chao2.yu@samsung.com> Loading @@ -122,6 +140,12 @@ Contact: "Shuoran Liu" <liushuoran@huawei.com> Description: Shows total written kbytes issued to disk. What: /sys/fs/f2fs/<disk>/feature Date: July 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Shows all enabled features in current device. What: /sys/fs/f2fs/<disk>/inject_rate Date: May 2016 Contact: "Sheng Yong" <shengyong1@huawei.com> Loading @@ -138,4 +162,27 @@ What: /sys/fs/f2fs/<disk>/reserved_blocks Date: June 2017 Contact: "Chao Yu" <yuchao0@huawei.com> Description: Controls current reserved blocks in system. Controls target reserved blocks in system, the threshold is soft, it could exceed current available user space. What: /sys/fs/f2fs/<disk>/current_reserved_blocks Date: October 2017 Contact: "Yunlong Song" <yunlong.song@huawei.com> Contact: "Chao Yu" <yuchao0@huawei.com> Description: Shows current reserved blocks in system, it may be temporarily smaller than target_reserved_blocks, but will gradually increase to target_reserved_blocks when more free blocks are freed by user later. What: /sys/fs/f2fs/<disk>/gc_urgent Date: August 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Do background GC agressively What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time Date: August 2017 Contact: "Jaegeuk Kim" <jaegeuk@kernel.org> Description: Controls sleep time of GC urgent mode
Documentation/filesystems/f2fs.txt +19 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,16 @@ io_bits=%u Set the bit size of write IO requests. It should be set with "mode=lfs". usrquota Enable plain user disk quota accounting. grpquota Enable plain group disk quota accounting. prjquota Enable plain project quota accounting. usrjquota=<file> Appoint specified file and type during mount, so that quota grpjquota=<file> information can be properly updated during recovery flow, prjjquota=<file> <quota file>: must be in root directory; jqfmt=<quota type> <quota type>: [vfsold,vfsv0,vfsv1]. offusrjquota Turn off user journelled quota. offgrpjquota Turn off group journelled quota. offprjjquota Turn off project journelled quota. quota Enable plain user disk quota accounting. noquota Disable all plain disk quota option. ================================================================================ DEBUGFS ENTRIES Loading Loading @@ -196,6 +206,15 @@ Files in /sys/fs/f2fs/<devname> gc_idle = 1 will select the Cost Benefit approach & setting gc_idle = 2 will select the greedy aproach. gc_urgent This parameter controls triggering background GCs urgently or not. Setting gc_urgent = 0 [default] makes back to default behavior, while if it is set to 1, background thread starts to do GC by given gc_urgent_sleep_time interval. gc_urgent_sleep_time This parameter controls sleep time for gc_urgent. 500 ms is set by default. See above gc_urgent. reclaim_segments This parameter controls the number of prefree segments to be reclaimed. If the number of prefree segments is larger than the number of segments Loading
fs/ext4/inode.c +6 −0 Original line number Diff line number Diff line Loading @@ -5110,11 +5110,17 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) * If the inode is marked synchronous, we don't honour that here - doing * so would cause a commit on atime updates, which we don't bother doing. * We handle synchronous inodes at the highest possible level. * * If only the I_DIRTY_TIME flag is set, we can skip everything. If * I_DIRTY_TIME and I_DIRTY_SYNC is set, the only inode fields we need * to copy into the on-disk inode structure are the timestamp files. */ void ext4_dirty_inode(struct inode *inode, int flags) { handle_t *handle; if (flags == I_DIRTY_TIME) return; handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); if (IS_ERR(handle)) goto out; Loading
fs/f2fs/acl.c +6 −2 Original line number Diff line number Diff line Loading @@ -207,15 +207,16 @@ static int __f2fs_set_acl(struct inode *inode, int type, void *value = NULL; size_t size = 0; int error; umode_t mode = inode->i_mode; switch (type) { case ACL_TYPE_ACCESS: name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; if (acl && !ipage) { error = posix_acl_update_mode(inode, &inode->i_mode, &acl); error = posix_acl_update_mode(inode, &mode, &acl); if (error) return error; set_acl_inode(inode, inode->i_mode); set_acl_inode(inode, mode); } break; Loading Loading @@ -249,6 +250,9 @@ static int __f2fs_set_acl(struct inode *inode, int type, int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; return __f2fs_set_acl(inode, type, acl, NULL); } Loading
fs/f2fs/checkpoint.c +94 −26 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ struct kmem_cache *inode_entry_slab; void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io) { set_ckpt_flags(sbi, CP_ERROR_FLAG); sbi->sb->s_flags |= MS_RDONLY; if (!end_io) f2fs_flush_merged_writes(sbi); } Loading Loading @@ -231,8 +230,9 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); } static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) static int __f2fs_write_meta_page(struct page *page, struct writeback_control *wbc, enum iostat_type io_type) { struct f2fs_sb_info *sbi = F2FS_P_SB(page); Loading @@ -245,7 +245,7 @@ static int f2fs_write_meta_page(struct page *page, if (unlikely(f2fs_cp_error(sbi))) goto redirty_out; write_meta_page(sbi, page); write_meta_page(sbi, page, io_type); dec_page_count(sbi, F2FS_DIRTY_META); if (wbc->for_reclaim) Loading @@ -264,6 +264,12 @@ redirty_out: return AOP_WRITEPAGE_ACTIVATE; } static int f2fs_write_meta_page(struct page *page, struct writeback_control *wbc) { return __f2fs_write_meta_page(page, wbc, FS_META_IO); } static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { Loading @@ -284,7 +290,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, trace_f2fs_writepages(mapping->host, wbc, META); diff = nr_pages_to_write(sbi, META, wbc); written = sync_meta_pages(sbi, META, wbc->nr_to_write); written = sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO); mutex_unlock(&sbi->cp_mutex); wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); return 0; Loading @@ -296,7 +302,7 @@ skip_write: } long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long nr_to_write) long nr_to_write, enum iostat_type io_type) { struct address_space *mapping = META_MAPPING(sbi); pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX; Loading Loading @@ -347,7 +353,7 @@ continue_unlock: if (!clear_page_dirty_for_io(page)) goto continue_unlock; if (mapping->a_ops->writepage(page, &wbc)) { if (__f2fs_write_meta_page(page, &wbc, io_type)) { unlock_page(page); break; } Loading Loading @@ -395,24 +401,23 @@ const struct address_space_operations f2fs_meta_aops = { #endif }; static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e, *tmp; tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); retry: radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (!e) { e = tmp; if (radix_tree_insert(&im->ino_root, ino, e)) { spin_unlock(&im->ino_lock); radix_tree_preload_end(); goto retry; } if (unlikely(radix_tree_insert(&im->ino_root, ino, e))) f2fs_bug_on(sbi, 1); memset(e, 0, sizeof(struct ino_entry)); e->ino = ino; Loading @@ -420,6 +425,10 @@ retry: if (type != ORPHAN_INO) im->ino_num++; } if (type == FLUSH_INO) f2fs_set_bit(devidx, (char *)&e->dirty_device); spin_unlock(&im->ino_lock); radix_tree_preload_end(); Loading Loading @@ -448,7 +457,7 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { /* add new dirty ino entry into list */ __add_ino_entry(sbi, ino, type); __add_ino_entry(sbi, ino, 0, type); } void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) Loading @@ -474,7 +483,7 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) struct ino_entry *e, *tmp; int i; for (i = all ? ORPHAN_INO: APPEND_INO; i <= UPDATE_INO; i++) { for (i = all ? ORPHAN_INO : APPEND_INO; i < MAX_INO_ENTRY; i++) { struct inode_management *im = &sbi->im[i]; spin_lock(&im->ino_lock); Loading @@ -488,6 +497,27 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all) } } void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { __add_ino_entry(sbi, ino, devidx, type); } bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino, unsigned int devidx, int type) { struct inode_management *im = &sbi->im[type]; struct ino_entry *e; bool is_dirty = false; spin_lock(&im->ino_lock); e = radix_tree_lookup(&im->ino_root, ino); if (e && f2fs_test_bit(devidx, (char *)&e->dirty_device)) is_dirty = true; spin_unlock(&im->ino_lock); return is_dirty; } int acquire_orphan_inode(struct f2fs_sb_info *sbi) { struct inode_management *im = &sbi->im[ORPHAN_INO]; Loading Loading @@ -524,7 +554,7 @@ void release_orphan_inode(struct f2fs_sb_info *sbi) void add_orphan_inode(struct inode *inode) { /* add new orphan ino entry into list */ __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, ORPHAN_INO); __add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO); update_inode_page(inode); } Loading @@ -548,7 +578,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) return err; } __add_ino_entry(sbi, ino, ORPHAN_INO); __add_ino_entry(sbi, ino, 0, ORPHAN_INO); inode = f2fs_iget_retry(sbi->sb, ino); if (IS_ERR(inode)) { Loading Loading @@ -582,11 +612,28 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) int recover_orphan_inodes(struct f2fs_sb_info *sbi) { block_t start_blk, orphan_blocks, i, j; int err; unsigned int s_flags = sbi->sb->s_flags; int err = 0; #ifdef CONFIG_QUOTA int quota_enabled; #endif if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) return 0; if (s_flags & MS_RDONLY) { f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs"); sbi->sb->s_flags &= ~MS_RDONLY; } #ifdef CONFIG_QUOTA /* Needed for iput() to work correctly and not trash data */ sbi->sb->s_flags |= MS_ACTIVE; /* Turn on quotas so that they are updated correctly */ quota_enabled = f2fs_enable_quota_files(sbi, s_flags & MS_RDONLY); #endif start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi); orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi); Loading @@ -602,14 +649,22 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi) err = recover_orphan_inode(sbi, ino); if (err) { f2fs_put_page(page, 1); return err; goto out; } } f2fs_put_page(page, 1); } /* clear Orphan Flag */ clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG); return 0; out: #ifdef CONFIG_QUOTA /* Turn quotas off */ if (quota_enabled) f2fs_quota_off_umount(sbi->sb); #endif sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */ return err; } static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) Loading Loading @@ -905,7 +960,14 @@ retry: if (inode) { unsigned long cur_ino = inode->i_ino; if (is_dir) F2FS_I(inode)->cp_task = current; filemap_fdatawrite(inode->i_mapping); if (is_dir) F2FS_I(inode)->cp_task = NULL; iput(inode); /* We need to give cpu to another writers. */ if (ino == cur_ino) { Loading Loading @@ -953,7 +1015,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi) update_inode_page(inode); iput(inode); } }; } return 0; } Loading Loading @@ -1018,7 +1080,7 @@ retry_flush_nodes: if (get_pages(sbi, F2FS_DIRTY_NODES)) { up_write(&sbi->node_write); err = sync_node_pages(sbi, &wbc); err = sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO); if (err) { up_write(&sbi->node_change); f2fs_unlock_all(sbi); Loading Loading @@ -1113,10 +1175,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct super_block *sb = sbi->sb; struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); u64 kbytes_written; int err; /* Flush all the NAT/SIT pages */ while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); if (unlikely(f2fs_cp_error(sbi))) return -EIO; } Loading Loading @@ -1195,7 +1258,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) /* Flush all the NAT BITS pages */ while (get_pages(sbi, F2FS_DIRTY_META)) { sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); if (unlikely(f2fs_cp_error(sbi))) return -EIO; } Loading @@ -1206,6 +1269,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (unlikely(f2fs_cp_error(sbi))) return -EIO; /* flush all device cache */ err = f2fs_flush_device_cache(sbi); if (err) return err; /* write out checkpoint buffer at block 0 */ update_meta_page(sbi, ckpt, start_blk++); Loading Loading @@ -1250,7 +1318,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) percpu_counter_set(&sbi->alloc_valid_block_count, 0); /* Here, we only have one bio having CP pack */ sync_meta_pages(sbi, META_FLUSH, LONG_MAX); sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO); /* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback(sbi); Loading