]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - fs/f2fs/node.c
page cache: use xa_lock
[mirror_ubuntu-jammy-kernel.git] / fs / f2fs / node.c
index 177c438e4a5680bce447d9981626b9c45f3b4660..f202398e20eaaec752c9f5736b047748cee39c65 100644 (file)
@@ -91,11 +91,11 @@ static void clear_node_page_dirty(struct page *page)
        unsigned int long flags;
 
        if (PageDirty(page)) {
-               spin_lock_irqsave(&mapping->tree_lock, flags);
-               radix_tree_tag_clear(&mapping->page_tree,
+               xa_lock_irqsave(&mapping->i_pages, flags);
+               radix_tree_tag_clear(&mapping->i_pages,
                                page_index(page),
                                PAGECACHE_TAG_DIRTY);
-               spin_unlock_irqrestore(&mapping->tree_lock, flags);
+               xa_unlock_irqrestore(&mapping->i_pages, flags);
 
                clear_page_dirty_for_io(page);
                dec_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES);
@@ -193,8 +193,8 @@ static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e)
        __free_nat_entry(e);
 }
 
-static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
-                                               struct nat_entry *ne)
+static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i,
+                                                       struct nat_entry *ne)
 {
        nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
        struct nat_entry_set *head;
@@ -209,15 +209,36 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
                head->entry_cnt = 0;
                f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);
        }
+       return head;
+}
+
+static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
+                                               struct nat_entry *ne)
+{
+       struct nat_entry_set *head;
+       bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR;
+
+       if (!new_ne)
+               head = __grab_nat_entry_set(nm_i, ne);
+
+       /*
+        * update entry_cnt in below condition:
+        * 1. update NEW_ADDR to valid block address;
+        * 2. update old block address to new one;
+        */
+       if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) ||
+                               !get_nat_flag(ne, IS_DIRTY)))
+               head->entry_cnt++;
+
+       set_nat_flag(ne, IS_PREALLOC, new_ne);
 
        if (get_nat_flag(ne, IS_DIRTY))
                goto refresh_list;
 
        nm_i->dirty_nat_cnt++;
-       head->entry_cnt++;
        set_nat_flag(ne, IS_DIRTY, true);
 refresh_list:
-       if (nat_get_blkaddr(ne) == NEW_ADDR)
+       if (new_ne)
                list_del_init(&ne->list);
        else
                list_move_tail(&ne->list, &head->entry_list);
@@ -1076,7 +1097,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
 
        f2fs_wait_on_page_writeback(page, NODE, true);
        fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
-       set_cold_node(dn->inode, page);
+       set_cold_node(page, S_ISDIR(dn->inode->i_mode));
        if (!PageUptodate(page))
                SetPageUptodate(page);
        if (set_page_dirty(page))
@@ -1140,7 +1161,7 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
        f2fs_bug_on(sbi, check_nid_range(sbi, nid));
 
        rcu_read_lock();
-       apage = radix_tree_lookup(&NODE_MAPPING(sbi)->page_tree, nid);
+       apage = radix_tree_lookup(&NODE_MAPPING(sbi)->i_pages, nid);
        rcu_read_unlock();
        if (apage)
                return;
@@ -2291,6 +2312,7 @@ retry:
        if (!PageUptodate(ipage))
                SetPageUptodate(ipage);
        fill_node_footer(ipage, ino, ino, 0, true);
+       set_cold_node(page, false);
 
        src = F2FS_INODE(page);
        dst = F2FS_INODE(ipage);
@@ -2580,8 +2602,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
        if (!enabled_nat_bits(sbi, NULL))
                return 0;
 
-       nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 +
-                                               F2FS_BLKSIZE - 1);
+       nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
        nm_i->nat_bits = f2fs_kzalloc(sbi,
                        nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
        if (!nm_i->nat_bits)
@@ -2707,12 +2728,20 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
 static int init_free_nid_cache(struct f2fs_sb_info *sbi)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
+       int i;
 
-       nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
-                                       NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
+       nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks *
+                               sizeof(unsigned char *), GFP_KERNEL);
        if (!nm_i->free_nid_bitmap)
                return -ENOMEM;
 
+       for (i = 0; i < nm_i->nat_blocks; i++) {
+               nm_i->free_nid_bitmap[i] = f2fs_kvzalloc(sbi,
+                               NAT_ENTRY_BITMAP_SIZE_ALIGNED, GFP_KERNEL);
+               if (!nm_i->free_nid_bitmap)
+                       return -ENOMEM;
+       }
+
        nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8,
                                                                GFP_KERNEL);
        if (!nm_i->nat_block_bitmap)
@@ -2803,7 +2832,13 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
        up_write(&nm_i->nat_tree_lock);
 
        kvfree(nm_i->nat_block_bitmap);
-       kvfree(nm_i->free_nid_bitmap);
+       if (nm_i->free_nid_bitmap) {
+               int i;
+
+               for (i = 0; i < nm_i->nat_blocks; i++)
+                       kvfree(nm_i->free_nid_bitmap[i]);
+               kfree(nm_i->free_nid_bitmap);
+       }
        kvfree(nm_i->free_nid_count);
 
        kfree(nm_i->nat_bitmap);