aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2017-02-22 21:53:49 -0500
committerJaegeuk Kim <jaegeuk@kernel.org>2017-02-27 13:07:47 -0500
commit4ac912427c4214d8031d9ad6fbc3bc75e71512df (patch)
treed1724cb87c35b2b83fa2b8d4da4a0e9ecd64e9af
parentced2c7ea8e99b46755a270872cd5ba61c27cffad (diff)
f2fs: introduce free nid bitmap
In scenario of intensively node allocation, free nids will be ran out soon, then it needs to stop to load free nids by traversing NAT blocks, in worse case, if NAT blocks does not be cached in memory, it generates IOs which slows down our foreground operations. In order to speed up node allocation, in this patch we introduce a new free_nid_bitmap array, so there is an bitmap table for each NAT block, Once the NAT block is loaded, related bitmap cache will be switched on, and bitmap will be set during traversing nat entries in NAT block, later we can query and update nid usage status in memory completely. With such implementation, I expect performance of node allocation can be improved in the long-term after filesystem image is mounted. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/debug.c2
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/node.c125
-rw-r--r--include/linux/f2fs_fs.h1
4 files changed, 120 insertions, 10 deletions
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 015ad2b73a92..a77df377e2e8 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -194,6 +194,8 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
194 si->base_mem += sizeof(struct f2fs_nm_info); 194 si->base_mem += sizeof(struct f2fs_nm_info);
195 si->base_mem += __bitmap_size(sbi, NAT_BITMAP); 195 si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
196 si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS); 196 si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
197 si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
198 si->base_mem += NM_I(sbi)->nat_blocks / 8;
197 199
198get_cache: 200get_cache:
199 si->cache_mem = 0; 201 si->cache_mem = 0;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 4d332b396384..7e2924981eeb 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -555,6 +555,8 @@ struct f2fs_nm_info {
555 unsigned int nid_cnt[MAX_NID_LIST]; /* the number of free node id */ 555 unsigned int nid_cnt[MAX_NID_LIST]; /* the number of free node id */
556 spinlock_t nid_list_lock; /* protect nid lists ops */ 556 spinlock_t nid_list_lock; /* protect nid lists ops */
557 struct mutex build_lock; /* lock for build free nids */ 557 struct mutex build_lock; /* lock for build free nids */
558 unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
559 unsigned char *nat_block_bitmap;
558 560
559 /* for checkpoint */ 561 /* for checkpoint */
560 char *nat_bitmap; /* NAT bitmap pointer */ 562 char *nat_bitmap; /* NAT bitmap pointer */
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 8e53181d5db1..fd12a32f7e87 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1765,7 +1765,8 @@ static void __remove_nid_from_list(struct f2fs_sb_info *sbi,
1765 radix_tree_delete(&nm_i->free_nid_root, i->nid); 1765 radix_tree_delete(&nm_i->free_nid_root, i->nid);
1766} 1766}
1767 1767
1768static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build) 1768/* return if the nid is recognized as free */
1769static bool add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
1769{ 1770{
1770 struct f2fs_nm_info *nm_i = NM_I(sbi); 1771 struct f2fs_nm_info *nm_i = NM_I(sbi);
1771 struct free_nid *i; 1772 struct free_nid *i;
@@ -1774,14 +1775,14 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
1774 1775
1775 /* 0 nid should not be used */ 1776 /* 0 nid should not be used */
1776 if (unlikely(nid == 0)) 1777 if (unlikely(nid == 0))
1777 return 0; 1778 return false;
1778 1779
1779 if (build) { 1780 if (build) {
1780 /* do not add allocated nids */ 1781 /* do not add allocated nids */
1781 ne = __lookup_nat_cache(nm_i, nid); 1782 ne = __lookup_nat_cache(nm_i, nid);
1782 if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) || 1783 if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
1783 nat_get_blkaddr(ne) != NULL_ADDR)) 1784 nat_get_blkaddr(ne) != NULL_ADDR))
1784 return 0; 1785 return false;
1785 } 1786 }
1786 1787
1787 i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS); 1788 i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
@@ -1790,7 +1791,7 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
1790 1791
1791 if (radix_tree_preload(GFP_NOFS)) { 1792 if (radix_tree_preload(GFP_NOFS)) {
1792 kmem_cache_free(free_nid_slab, i); 1793 kmem_cache_free(free_nid_slab, i);
1793 return 0; 1794 return true;
1794 } 1795 }
1795 1796
1796 spin_lock(&nm_i->nid_list_lock); 1797 spin_lock(&nm_i->nid_list_lock);
@@ -1799,9 +1800,9 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
1799 radix_tree_preload_end(); 1800 radix_tree_preload_end();
1800 if (err) { 1801 if (err) {
1801 kmem_cache_free(free_nid_slab, i); 1802 kmem_cache_free(free_nid_slab, i);
1802 return 0; 1803 return true;
1803 } 1804 }
1804 return 1; 1805 return true;
1805} 1806}
1806 1807
1807static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid) 1808static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
@@ -1822,17 +1823,36 @@ static void remove_free_nid(struct f2fs_sb_info *sbi, nid_t nid)
1822 kmem_cache_free(free_nid_slab, i); 1823 kmem_cache_free(free_nid_slab, i);
1823} 1824}
1824 1825
1826void update_free_nid_bitmap(struct f2fs_sb_info *sbi, nid_t nid, bool set)
1827{
1828 struct f2fs_nm_info *nm_i = NM_I(sbi);
1829 unsigned int nat_ofs = NAT_BLOCK_OFFSET(nid);
1830 unsigned int nid_ofs = nid - START_NID(nid);
1831
1832 if (!test_bit_le(nat_ofs, nm_i->nat_block_bitmap))
1833 return;
1834
1835 if (set)
1836 set_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
1837 else
1838 clear_bit_le(nid_ofs, nm_i->free_nid_bitmap[nat_ofs]);
1839}
1840
1825static void scan_nat_page(struct f2fs_sb_info *sbi, 1841static void scan_nat_page(struct f2fs_sb_info *sbi,
1826 struct page *nat_page, nid_t start_nid) 1842 struct page *nat_page, nid_t start_nid)
1827{ 1843{
1828 struct f2fs_nm_info *nm_i = NM_I(sbi); 1844 struct f2fs_nm_info *nm_i = NM_I(sbi);
1829 struct f2fs_nat_block *nat_blk = page_address(nat_page); 1845 struct f2fs_nat_block *nat_blk = page_address(nat_page);
1830 block_t blk_addr; 1846 block_t blk_addr;
1847 unsigned int nat_ofs = NAT_BLOCK_OFFSET(start_nid);
1831 int i; 1848 int i;
1832 1849
1850 set_bit_le(nat_ofs, nm_i->nat_block_bitmap);
1851
1833 i = start_nid % NAT_ENTRY_PER_BLOCK; 1852 i = start_nid % NAT_ENTRY_PER_BLOCK;
1834 1853
1835 for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) { 1854 for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
1855 bool freed = false;
1836 1856
1837 if (unlikely(start_nid >= nm_i->max_nid)) 1857 if (unlikely(start_nid >= nm_i->max_nid))
1838 break; 1858 break;
@@ -1840,8 +1860,52 @@ static void scan_nat_page(struct f2fs_sb_info *sbi,
1840 blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr); 1860 blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
1841 f2fs_bug_on(sbi, blk_addr == NEW_ADDR); 1861 f2fs_bug_on(sbi, blk_addr == NEW_ADDR);
1842 if (blk_addr == NULL_ADDR) 1862 if (blk_addr == NULL_ADDR)
1843 add_free_nid(sbi, start_nid, true); 1863 freed = add_free_nid(sbi, start_nid, true);
1864 update_free_nid_bitmap(sbi, start_nid, freed);
1865 }
1866}
1867
1868static void scan_free_nid_bits(struct f2fs_sb_info *sbi)
1869{
1870 struct f2fs_nm_info *nm_i = NM_I(sbi);
1871 struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
1872 struct f2fs_journal *journal = curseg->journal;
1873 unsigned int i, idx;
1874 unsigned int target = FREE_NID_PAGES * NAT_ENTRY_PER_BLOCK;
1875
1876 down_read(&nm_i->nat_tree_lock);
1877
1878 for (i = 0; i < nm_i->nat_blocks; i++) {
1879 if (!test_bit_le(i, nm_i->nat_block_bitmap))
1880 continue;
1881 for (idx = 0; idx < NAT_ENTRY_PER_BLOCK; idx++) {
1882 nid_t nid;
1883
1884 if (!test_bit_le(idx, nm_i->free_nid_bitmap[i]))
1885 continue;
1886
1887 nid = i * NAT_ENTRY_PER_BLOCK + idx;
1888 add_free_nid(sbi, nid, true);
1889
1890 if (nm_i->nid_cnt[FREE_NID_LIST] >= target)
1891 goto out;
1892 }
1893 }
1894out:
1895 down_read(&curseg->journal_rwsem);
1896 for (i = 0; i < nats_in_cursum(journal); i++) {
1897 block_t addr;
1898 nid_t nid;
1899
1900 addr = le32_to_cpu(nat_in_journal(journal, i).block_addr);
1901 nid = le32_to_cpu(nid_in_journal(journal, i));
1902 if (addr == NULL_ADDR)
1903 add_free_nid(sbi, nid, true);
1904 else
1905 remove_free_nid(sbi, nid);
1844 } 1906 }
1907 up_read(&curseg->journal_rwsem);
1908 up_read(&nm_i->nat_tree_lock);
1845} 1909}
1846 1910
1847static int scan_nat_bits(struct f2fs_sb_info *sbi) 1911static int scan_nat_bits(struct f2fs_sb_info *sbi)
@@ -1912,9 +1976,17 @@ static void __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
1912 if (!sync && !available_free_memory(sbi, FREE_NIDS)) 1976 if (!sync && !available_free_memory(sbi, FREE_NIDS))
1913 return; 1977 return;
1914 1978
1915 /* try to find free nids with nat_bits */ 1979 if (!mount) {
1916 if (!mount && !scan_nat_bits(sbi) && nm_i->nid_cnt[FREE_NID_LIST]) 1980 /* try to find free nids in free_nid_bitmap */
1917 return; 1981 scan_free_nid_bits(sbi);
1982
1983 if (nm_i->nid_cnt[FREE_NID_LIST])
1984 return;
1985
1986 /* try to find free nids with nat_bits */
1987 if (!scan_nat_bits(sbi) && nm_i->nid_cnt[FREE_NID_LIST])
1988 return;
1989 }
1918 1990
1919 /* find next valid candidate */ 1991 /* find next valid candidate */
1920 if (enabled_nat_bits(sbi, NULL)) { 1992 if (enabled_nat_bits(sbi, NULL)) {
@@ -2010,6 +2082,9 @@ retry:
2010 i->state = NID_ALLOC; 2082 i->state = NID_ALLOC;
2011 __insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false); 2083 __insert_nid_to_list(sbi, i, ALLOC_NID_LIST, false);
2012 nm_i->available_nids--; 2084 nm_i->available_nids--;
2085
2086 update_free_nid_bitmap(sbi, *nid, false);
2087
2013 spin_unlock(&nm_i->nid_list_lock); 2088 spin_unlock(&nm_i->nid_list_lock);
2014 return true; 2089 return true;
2015 } 2090 }
@@ -2064,6 +2139,8 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
2064 2139
2065 nm_i->available_nids++; 2140 nm_i->available_nids++;
2066 2141
2142 update_free_nid_bitmap(sbi, nid, true);
2143
2067 spin_unlock(&nm_i->nid_list_lock); 2144 spin_unlock(&nm_i->nid_list_lock);
2068 2145
2069 if (need_free) 2146 if (need_free)
@@ -2392,6 +2469,11 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
2392 add_free_nid(sbi, nid, false); 2469 add_free_nid(sbi, nid, false);
2393 spin_lock(&NM_I(sbi)->nid_list_lock); 2470 spin_lock(&NM_I(sbi)->nid_list_lock);
2394 NM_I(sbi)->available_nids++; 2471 NM_I(sbi)->available_nids++;
2472 update_free_nid_bitmap(sbi, nid, true);
2473 spin_unlock(&NM_I(sbi)->nid_list_lock);
2474 } else {
2475 spin_lock(&NM_I(sbi)->nid_list_lock);
2476 update_free_nid_bitmap(sbi, nid, false);
2395 spin_unlock(&NM_I(sbi)->nid_list_lock); 2477 spin_unlock(&NM_I(sbi)->nid_list_lock);
2396 } 2478 }
2397 } 2479 }
@@ -2558,6 +2640,22 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
2558 return 0; 2640 return 0;
2559} 2641}
2560 2642
2643int init_free_nid_cache(struct f2fs_sb_info *sbi)
2644{
2645 struct f2fs_nm_info *nm_i = NM_I(sbi);
2646
2647 nm_i->free_nid_bitmap = f2fs_kvzalloc(nm_i->nat_blocks *
2648 NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
2649 if (!nm_i->free_nid_bitmap)
2650 return -ENOMEM;
2651
2652 nm_i->nat_block_bitmap = f2fs_kvzalloc(nm_i->nat_blocks / 8,
2653 GFP_KERNEL);
2654 if (!nm_i->nat_block_bitmap)
2655 return -ENOMEM;
2656 return 0;
2657}
2658
2561int build_node_manager(struct f2fs_sb_info *sbi) 2659int build_node_manager(struct f2fs_sb_info *sbi)
2562{ 2660{
2563 int err; 2661 int err;
@@ -2570,6 +2668,10 @@ int build_node_manager(struct f2fs_sb_info *sbi)
2570 if (err) 2668 if (err)
2571 return err; 2669 return err;
2572 2670
2671 err = init_free_nid_cache(sbi);
2672 if (err)
2673 return err;
2674
2573 build_free_nids(sbi, true, true); 2675 build_free_nids(sbi, true, true);
2574 return 0; 2676 return 0;
2575} 2677}
@@ -2628,6 +2730,9 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
2628 } 2730 }
2629 up_write(&nm_i->nat_tree_lock); 2731 up_write(&nm_i->nat_tree_lock);
2630 2732
2733 kvfree(nm_i->nat_block_bitmap);
2734 kvfree(nm_i->free_nid_bitmap);
2735
2631 kfree(nm_i->nat_bitmap); 2736 kfree(nm_i->nat_bitmap);
2632 kfree(nm_i->nat_bits); 2737 kfree(nm_i->nat_bits);
2633#ifdef CONFIG_F2FS_CHECK_FS 2738#ifdef CONFIG_F2FS_CHECK_FS
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 1c92ace2e8f8..e2d239ed4c60 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -279,6 +279,7 @@ struct f2fs_node {
279 * For NAT entries 279 * For NAT entries
280 */ 280 */
281#define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry)) 281#define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry))
282#define NAT_ENTRY_BITMAP_SIZE ((NAT_ENTRY_PER_BLOCK + 7) / 8)
282 283
283struct f2fs_nat_entry { 284struct f2fs_nat_entry {
284 __u8 version; /* latest version of cached nat entry */ 285 __u8 version; /* latest version of cached nat entry */