From e5b34f496ed59fe63316fc88d0296374ee25a208 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 14 Jul 2014 17:54:08 -0700 Subject: [PATCH] 3.15-stable patches added patches: f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch --- ...free-mem-size-to-flush-dentry-blocks.patch | 181 ++++++++++++++++++ ...eded-when-trying-to-skip-data-writes.patch | 34 ++++ queue-3.15/series | 2 + 3 files changed, 217 insertions(+) create mode 100644 queue-3.15/f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch create mode 100644 queue-3.15/f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch diff --git a/queue-3.15/f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch b/queue-3.15/f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch new file mode 100644 index 00000000000..b582efb994e --- /dev/null +++ b/queue-3.15/f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch @@ -0,0 +1,181 @@ +From 6fb03f3a40805a412c9b285010ffdc2e7563f81b Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Wed, 16 Apr 2014 10:47:06 +0900 +Subject: f2fs: adjust free mem size to flush dentry blocks + +From: Jaegeuk Kim + +commit 6fb03f3a40805a412c9b285010ffdc2e7563f81b upstream. + +If so many dirty dentry blocks are cached, not reached to the flush condition, +we should fall into livelock in balance_dirty_pages. +So, let's consider the mem size for the condition. + +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman + +--- + fs/f2fs/data.c | 3 ++- + fs/f2fs/f2fs.h | 1 + + fs/f2fs/node.c | 44 ++++++++++++++++++++++++++------------------ + fs/f2fs/node.h | 5 +++-- + 4 files changed, 32 insertions(+), 21 deletions(-) + +--- a/fs/f2fs/data.c ++++ b/fs/f2fs/data.c +@@ -869,7 +869,8 @@ static int f2fs_write_data_pages(struct + return 0; + + if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE && +- get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA)) ++ get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA) && ++ available_free_memory(sbi, DIRTY_DENTS)) + goto skip_write; + + diff = nr_pages_to_write(sbi, DATA, wbc); +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1140,6 +1140,7 @@ f2fs_hash_t f2fs_dentry_hash(const char + struct dnode_of_data; + struct node_info; + ++bool available_free_memory(struct f2fs_sb_info *, int); + int is_checkpointed_node(struct f2fs_sb_info *, nid_t); + bool fsync_mark_done(struct f2fs_sb_info *, nid_t); + void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -26,20 +26,26 @@ + static struct kmem_cache *nat_entry_slab; + static struct kmem_cache *free_nid_slab; + +-static inline bool available_free_memory(struct f2fs_nm_info *nm_i, int type) ++bool available_free_memory(struct f2fs_sb_info *sbi, int type) + { ++ struct f2fs_nm_info *nm_i = NM_I(sbi); + struct sysinfo val; + unsigned long mem_size = 0; ++ bool res = false; + + si_meminfo(&val); +- if (type == FREE_NIDS) +- mem_size = nm_i->fcnt * sizeof(struct free_nid); +- else if (type == NAT_ENTRIES) +- mem_size += nm_i->nat_cnt * sizeof(struct nat_entry); +- mem_size >>= 12; +- +- /* give 50:50 memory for free nids and nat caches respectively */ +- return (mem_size < ((val.totalram * nm_i->ram_thresh) >> 11)); ++ /* give 25%, 25%, 50% memory for each components respectively */ ++ if (type == FREE_NIDS) { ++ mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> 12; ++ res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); ++ } else if (type == NAT_ENTRIES) { ++ mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12; ++ res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); ++ } else if (type == DIRTY_DENTS) { ++ mem_size = get_pages(sbi, F2FS_DIRTY_DENTS); ++ res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1); ++ } ++ return res; + } + + static void clear_node_page_dirty(struct page *page) +@@ -243,7 +249,7 @@ int try_to_free_nats(struct f2fs_sb_info + { + struct f2fs_nm_info *nm_i = NM_I(sbi); + +- if (available_free_memory(nm_i, NAT_ENTRIES)) ++ if (available_free_memory(sbi, NAT_ENTRIES)) + return 0; + + write_lock(&nm_i->nat_tree_lock); +@@ -1315,13 +1321,14 @@ static void __del_from_free_nid_list(str + radix_tree_delete(&nm_i->free_nid_root, i->nid); + } + +-static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build) ++static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) + { ++ struct f2fs_nm_info *nm_i = NM_I(sbi); + struct free_nid *i; + struct nat_entry *ne; + bool allocated = false; + +- if (!available_free_memory(nm_i, FREE_NIDS)) ++ if (!available_free_memory(sbi, FREE_NIDS)) + return -1; + + /* 0 nid should not be used */ +@@ -1374,9 +1381,10 @@ static void remove_free_nid(struct f2fs_ + kmem_cache_free(free_nid_slab, i); + } + +-static void scan_nat_page(struct f2fs_nm_info *nm_i, ++static void scan_nat_page(struct f2fs_sb_info *sbi, + struct page *nat_page, nid_t start_nid) + { ++ struct f2fs_nm_info *nm_i = NM_I(sbi); + struct f2fs_nat_block *nat_blk = page_address(nat_page); + block_t blk_addr; + int i; +@@ -1391,7 +1399,7 @@ static void scan_nat_page(struct f2fs_nm + blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); + f2fs_bug_on(blk_addr == NEW_ADDR); + if (blk_addr == NULL_ADDR) { +- if (add_free_nid(nm_i, start_nid, true) < 0) ++ if (add_free_nid(sbi, start_nid, true) < 0) + break; + } + } +@@ -1415,7 +1423,7 @@ static void build_free_nids(struct f2fs_ + while (1) { + struct page *page = get_current_nat_page(sbi, nid); + +- scan_nat_page(nm_i, page, nid); ++ scan_nat_page(sbi, page, nid); + f2fs_put_page(page, 1); + + nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK)); +@@ -1435,7 +1443,7 @@ static void build_free_nids(struct f2fs_ + block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr); + nid = le32_to_cpu(nid_in_journal(sum, i)); + if (addr == NULL_ADDR) +- add_free_nid(nm_i, nid, true); ++ add_free_nid(sbi, nid, true); + else + remove_free_nid(nm_i, nid); + } +@@ -1512,7 +1520,7 @@ void alloc_nid_failed(struct f2fs_sb_inf + spin_lock(&nm_i->free_nid_list_lock); + i = __lookup_free_nid_list(nm_i, nid); + f2fs_bug_on(!i || i->state != NID_ALLOC); +- if (!available_free_memory(nm_i, FREE_NIDS)) { ++ if (!available_free_memory(sbi, FREE_NIDS)) { + __del_from_free_nid_list(nm_i, i); + need_free = true; + } else { +@@ -1843,7 +1851,7 @@ flush_now: + } + + if (nat_get_blkaddr(ne) == NULL_ADDR && +- add_free_nid(NM_I(sbi), nid, false) <= 0) { ++ add_free_nid(sbi, nid, false) <= 0) { + write_lock(&nm_i->nat_tree_lock); + __del_from_nat_cache(nm_i, ne); + write_unlock(&nm_i->nat_tree_lock); +--- a/fs/f2fs/node.h ++++ b/fs/f2fs/node.h +@@ -75,9 +75,10 @@ static inline void node_info_from_raw_na + ni->version = raw_ne->version; + } + +-enum nid_type { ++enum mem_type { + FREE_NIDS, /* indicates the free nid list */ +- NAT_ENTRIES /* indicates the cached nat entry */ ++ NAT_ENTRIES, /* indicates the cached nat entry */ ++ DIRTY_DENTS /* indicates dirty dentry pages */ + }; + + /* diff --git a/queue-3.15/f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch b/queue-3.15/f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch new file mode 100644 index 00000000000..932d197e809 --- /dev/null +++ b/queue-3.15/f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch @@ -0,0 +1,34 @@ +From 2743f865543c0c4a5e12fc13edb2bf89a6e9687c Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Sat, 28 Jun 2014 01:00:41 +0900 +Subject: f2fs: check bdi->dirty_exceeded when trying to skip data writes + +From: Jaegeuk Kim + +commit 2743f865543c0c4a5e12fc13edb2bf89a6e9687c upstream. + +If we don't check the current backing device status, balance_dirty_pages can +fall into infinite pausing routine. + +This can be occurred when a lot of directories make a small number of dirty +dentry pages including files. + +Reported-by: Brian Chadwick +Signed-off-by: Jaegeuk Kim +Signed-off-by: Greg Kroah-Hartman + +--- + fs/f2fs/node.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/f2fs/node.c ++++ b/fs/f2fs/node.c +@@ -42,6 +42,8 @@ bool available_free_memory(struct f2fs_s + mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12; + res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); + } else if (type == DIRTY_DENTS) { ++ if (sbi->sb->s_bdi->dirty_exceeded) ++ return false; + mem_size = get_pages(sbi, F2FS_DIRTY_DENTS); + res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1); + } diff --git a/queue-3.15/series b/queue-3.15/series index 7bf3e73b27b..563bff653ae 100644 --- a/queue-3.15/series +++ b/queue-3.15/series @@ -70,3 +70,5 @@ cgroup-fix-mount-failure-in-a-corner-case.patch kernfs-implement-kernfs_root-supers-list.patch kernfs-introduce-kernfs_pin_sb.patch cgroup-fix-a-race-between-cgroup_mount-and-cgroup_kill_sb.patch +f2fs-adjust-free-mem-size-to-flush-dentry-blocks.patch +f2fs-check-bdi-dirty_exceeded-when-trying-to-skip-data-writes.patch -- 2.47.3