From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751546AbdKVIIT (ORCPT ); Wed, 22 Nov 2017 03:08:19 -0500 Received: from mailout3.samsung.com ([203.254.224.33]:22705 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751458AbdKVIIR (ORCPT ); Wed, 22 Nov 2017 03:08:17 -0500 DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20171122080815epoutp039dcb48c9b3ed7d4cb74a64d79d21b2af~5Wf2WG4he2735127351epoutp03a X-AuditID: b6c32a4a-b79ff70000001151-7d-5a15306f2cf4 From: "LiFan" To: "'Chao Yu'" , "'Chao Yu'" , "'Jaegeuk Kim'" Cc: , Subject: [f2fs-dev] [PATCH RESEND v3] f2fs: fix concurrent problem for updating free bitmap Date: Wed, 22 Nov 2017 16:07:23 +0800 Message-ID: <001501d36369$0bb9d3c0$232d7b40$@samsung.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Mailer: Microsoft Outlook 14.0 Content-Language: zh-cn Thread-Index: AdNjaO1wcQCLHa3PQOi1/Qjromn3QA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprNKsWRmVeSWpSXmKPExsWy7bCmhm6+gWiUwf1vvBanp55lsniyfhaz xaVF7haXd81hs5j6eC2rA6tHy5G3rB6bVnWyeexe8JnJ4/MmuQCWKC6blNSczLLUIn27BK6M idPmsxZc1K34sOo7ewPjEtUuRk4OCQETicNTuti7GLk4hAR2M0o0bFnCDOF8YpS43v4NKvON UWLjpz42mJb9b3+zgthCAnsZJdY0JEIUPWWUWPRxIlARBwebgIbE1M0yIDUiAtkSM88fZwax mQV8JH7fugdmCwvESnyd9YYdxGYRUJW4e+EkE4jNK2Ap0X2kmRXCFpQ4OfMJC0SvvMT2t3OY IW5QkNhx9jUjRFxc4k5rKyvELj2JbX0vwY6WENjBJnF02XxGiAYXifPrV7BA2MISr45vYYew pSQ+v9sL9dg6RonPZywgmrczSsz7+JEJImEtsXnNL3aQx5gFNCXW79KHCNtKLFj+hhXiCD6J 3t9PmEBKJAR4JTrahCBK1CRerp4FtVZGYt79PqgSD4ktX9gnMCrNQvLlLCRfzkLy2SyEvQsY WVYxSqYWFOempxabFhjlpZbrFSfmFpfmpesl5+duYgQnGS2vHYzLzvkcYhTgYFTi4Z2RJBIl xJpYVlyZe4hRgoNZSYR3r4JolBBvSmJlVWpRfnxRaU5q8SFGaQ4WJXHeYztLI4UE0hNLUrNT UwtSi2CyTBycUg2MzWoprbGXs21etiqrxnRPO3TZKCk/cI/c28Ntxu/X9f/b+PlDUNK0ZReS 1n88e62c51DjHt2glvWXdlQa603bt+VcqdCB9xNPb9pZtbvo+rcLi557V2Tqm0e8CVVwjZEK NVazzuncn9pRoPd9x4XsV8uulDwoObmo462BTd3NmFVZ09ScYqwElViKMxINtZiLihMB903Y oC4DAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrOLMWRmVeSWpSXmKPExsWy7bCSnG6egWiUwYu/Uhanp55lsniyfhaz xaVF7haXd81hs5j6eC2rA6tHy5G3rB6bVnWyeexe8JnJ4/MmuQCWKC6blNSczLLUIn27BK6M idPmsxZc1K34sOo7ewPjEtUuRk4OCQETif1vf7N2MXJxCAnsZpSYeG49I0RCRmLB4S/sELaw xMp/z9khih4zSix+dJmli5GDg01AQ2LqZhmQGhGBXImpU74zgdjMAn4Sux6uYAaxhQWiJSZt mc4KYrMIqErcvXASrIZXwFKi+0gzK4QtKHFy5hMWiF5tid6HrYwQtrzE9rdzmCFuUJDYcfY1 VFxc4k5rKyvEXj2JbX0v2ScwCs5CMmoWklGzkIyahaR9ASPLKkbJ1ILi3PTcYsMCw7zUcr3i xNzi0rx0veT83E2M4ODX0tzBeHlJ/CFGAQ5GJR5ehwSRKCHWxLLiytxDjBIczEoivHsVRKOE eFMSK6tSi/Lji0pzUosPMUpzsCiJ8z7NOxYpJJCeWJKanZpakFoEk2Xi4JRqYEwuZtogsp+H n31voJfukhN3Zx65bOGisshq/1Jb36valekd5Sw/Dt1YsuVRgXtLpv1f6SWHdzVM27rwix1P j/nFrQtn8NTvF67e+p299IzhJDPOglT7kInfH/gJRAjWT9jnytHT57xUtNm7qO+QtLBk6yun F3mSBT9fbu41d2HfZt+dcepJnhJLcUaioRZzUXEiAI++1dl6AgAA X-CMS-MailID: 20171122080814epcas5p4694a196adb1a55eeb8ac086ca0aace05 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-MTR: 20171122080814epcas5p4694a196adb1a55eeb8ac086ca0aace05 CMS-TYPE: 105P X-CMS-RootMailID: 20171122080814epcas5p4694a196adb1a55eeb8ac086ca0aace05 X-RootMTR: 20171122080814epcas5p4694a196adb1a55eeb8ac086ca0aace05 References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org alloc_nid_failed and scan_nat_page can be called at the same time, and we haven't protected add_free_nid and update_free_nid_bitmap with the same nid_list_lock. That could lead to Thread A Thread B - __build_free_nids - scan_nat_page - add_free_nid - alloc_nid_failed - update_free_nid_bitmap - update_free_nid_bitmap scan_nat_page will clear the free bitmap since the nid is PREALLOC_NID, but alloc_nid_failed needs to set the free bitmap. This results in free nid with free bitmap cleared. This patch update the bitmap under the same nid_list_lock in add_free_nid. And use __GFP_NOFAIL to make sure to update status of free nid correctly. Signed-off-by: Fan li --- fs/f2fs/node.c | 85 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index fe1fc66..8d5a06b 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1831,8 +1831,33 @@ static void __move_free_nid(struct f2fs_sb_info *sbi, struct free_nid *i, } } +static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, + bool set, bool build) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid); + unsigned int nid_ofs = nid - START_NID(nid); + + if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap)) + return; + + if (set) { + if (test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs])) + return; + __set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]); + nm_i->free_nid_count[nat_ofs]++; + } else { + if (!test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs])) + return; + __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]); + if (!build) + nm_i->free_nid_count[nat_ofs]--; + } +} + /* return if the nid is recognized as free */ -static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) +static bool add_free_nid(struct f2fs_sb_info *sbi, + nid_t nid, bool build, bool update) { struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i, *e; @@ -1848,8 +1873,7 @@ static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) i->nid = nid; i->state = FREE_NID; - if (radix_tree_preload(GFP_NOFS)) - goto err; + radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); spin_lock(&nm_i->nid_list_lock); @@ -1890,9 +1914,14 @@ static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) ret = true; err = __insert_free_nid(sbi, i, FREE_NID); err_out: + if (update) { + update_free_nid_bitmap(sbi, nid, ret, build); + if (!build) + nm_i->available_nids++; + } spin_unlock(&nm_i->nid_list_lock); radix_tree_preload_end(); -err: + if (err) kmem_cache_free(free_nid_slab, i); return ret; @@ -1916,30 +1945,6 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid) kmem_cache_free(free_nid_slab, i); } -static void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, - bool set, bool build) -{ - struct f2fs_nm_info *nm_i = NM_I(sbi); - unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid); - unsigned int nid_ofs = nid - START_NID(nid); - - if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap)) - return; - - if (set) { - if (test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs])) - return; - __set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]); - nm_i->free_nid_count[nat_ofs]++; - } else { - if (!test_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs])) - return; - __clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]); - if (!build) - nm_i->free_nid_count[nat_ofs]--; - } -} - static void scan_nat_page(struct f2fs_sb_info *sbi, struct page *nat_page, nid_t start_nid) { @@ -1957,18 +1962,18 @@ static void scan_nat_page(struct f2fs_sb_info *sbi, i = start_nid % NAT_ENTRY_PER_BLOCK; for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) { - bool freed = false; - if (unlikely(start_nid >= nm_i->max_nid)) break; blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); f2fs_bug_on(sbi, blk_addr == NEW_ADDR); - if (blk_addr == NULL_ADDR) - freed = add_free_nid(sbi, start_nid, true); - spin_lock(&NM_I(sbi)->nid_list_lock); - update_free_nid_bitmap(sbi, start_nid, freed, true); - spin_unlock(&NM_I(sbi)->nid_list_lock); + if (blk_addr == NULL_ADDR) { + add_free_nid(sbi, start_nid, true, true); + } else { + spin_lock(&NM_I(sbi)->nid_list_lock); + update_free_nid_bitmap(sbi, start_nid, false, true); + spin_unlock(&NM_I(sbi)->nid_list_lock); + } } } @@ -1986,7 +1991,7 @@ static void scan_curseg_cache(struct f2fs_sb_info *sbi) addr = le32_to_cpu(nat_in_journal(journal, i).block_addr); nid = le32_to_cpu(nid_in_journal(journal, i)); if (addr == NULL_ADDR) - add_free_nid(sbi, nid, true); + add_free_nid(sbi, nid, true, false); else remove_free_nid(sbi, nid); } @@ -2013,7 +2018,7 @@ static void scan_free_nid_bits(struct f2fs_sb_info *sbi) break; nid = i * NAT_ENTRY_PER_BLOCK + idx; - add_free_nid(sbi, nid, true); + add_free_nid(sbi, nid, true, false); if (nm_i->nid_cnt[FREE_NID] >= MAX_FREE_NIDS) goto out; @@ -2516,11 +2521,7 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, nat_reset_flag(ne); __clear_nat_cache_dirty(NM_I(sbi), set, ne); if (nat_get_blkaddr(ne) == NULL_ADDR) { - add_free_nid(sbi, nid, false); - spin_lock(&NM_I(sbi)->nid_list_lock); - NM_I(sbi)->available_nids++; - update_free_nid_bitmap(sbi, nid, true, false); - spin_unlock(&NM_I(sbi)->nid_list_lock); + add_free_nid(sbi, nid, false, true); } else { spin_lock(&NM_I(sbi)->nid_list_lock); update_free_nid_bitmap(sbi, nid, false, false); -- 2.7.4