Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

f2fs: fix unlocked nat set cache operation

nm_i->nat_tree_lock is used to sync both the operations of nat entry
cache tree and nat set cache tree, however, it isn't held when flush
nat entries during checkpoint which lead to potential race, this patch
fix it by holding the lock when gang lookup nat set cache and delete
item from nat set cache.

Signed-off-by: Wanpeng Li <wanpeng.li@linux.intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>

authored by

Wanpeng Li and committed by
Jaegeuk Kim
57ed1e95 e0150392

+5
+5
fs/f2fs/node.c
··· 1830 1830 struct f2fs_nat_block *nat_blk; 1831 1831 struct nat_entry *ne, *cur; 1832 1832 struct page *page = NULL; 1833 + struct f2fs_nm_info *nm_i = NM_I(sbi); 1833 1834 1834 1835 /* 1835 1836 * there are two steps to flush nat entries: ··· 1884 1883 1885 1884 f2fs_bug_on(sbi, set->entry_cnt); 1886 1885 1886 + down_write(&nm_i->nat_tree_lock); 1887 1887 radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set); 1888 + up_write(&nm_i->nat_tree_lock); 1888 1889 kmem_cache_free(nat_entry_set_slab, set); 1889 1890 } 1890 1891 ··· 1914 1911 if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL)) 1915 1912 remove_nats_in_journal(sbi); 1916 1913 1914 + down_write(&nm_i->nat_tree_lock); 1917 1915 while ((found = __gang_lookup_nat_set(nm_i, 1918 1916 set_idx, SETVEC_SIZE, setvec))) { 1919 1917 unsigned idx; ··· 1923 1919 __adjust_nat_entry_set(setvec[idx], &sets, 1924 1920 MAX_NAT_JENTRIES(sum)); 1925 1921 } 1922 + up_write(&nm_i->nat_tree_lock); 1926 1923 1927 1924 /* flush dirty nats in nat entry set */ 1928 1925 list_for_each_entry_safe(set, tmp, &sets, set_list)