ext4: make running and commit transaction have their own freed_data_list
authorJinke Han <hanjinke.666@bytedance.com>
Mon, 12 Jun 2023 12:40:17 +0000 (20:40 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 6 Oct 2023 01:48:03 +0000 (21:48 -0400)
When releasing space in jbd, we traverse s_freed_data_list to get the
free range belonging to the current commit transaction. In extreme cases,
the time spent may not be small, and we have observed cases exceeding
10ms. This patch makes running and commit transactions manage their own
free_data_list respectively, eliminating unnecessary traversal.

And in the callback phase of the commit transaction, no one will touch
it except the jbd thread itself, so s_md_lock is no longer needed.

Signed-off-by: Jinke Han <hanjinke.666@bytedance.com>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://lore.kernel.org/r/20230612124017.14115-1-hanjinke.666@bytedance.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/ext4.h
fs/ext4/mballoc.c

index cd4ccae1e28a1957d57f59618519616ae97fcff7..3b8bc44be5283fca53a8a8a92fccc1727c5bd37b 100644 (file)
@@ -1564,7 +1564,7 @@ struct ext4_sb_info {
        unsigned int *s_mb_maxs;
        unsigned int s_group_info_size;
        unsigned int s_mb_free_pending;
-       struct list_head s_freed_data_list;     /* List of blocks to be freed
+       struct list_head s_freed_data_list[2];  /* List of blocks to be freed
                                                   after commit completed */
        struct list_head s_discard_list;
        struct work_struct s_discard_work;
index 1e599305d85fa2b0a4356c2ac9cd4eef905ab456..1d65c738c4c981eaf294a0ea2d085ce2c8ab7c37 100644 (file)
@@ -3631,7 +3631,8 @@ int ext4_mb_init(struct super_block *sb)
 
        spin_lock_init(&sbi->s_md_lock);
        sbi->s_mb_free_pending = 0;
-       INIT_LIST_HEAD(&sbi->s_freed_data_list);
+       INIT_LIST_HEAD(&sbi->s_freed_data_list[0]);
+       INIT_LIST_HEAD(&sbi->s_freed_data_list[1]);
        INIT_LIST_HEAD(&sbi->s_discard_list);
        INIT_WORK(&sbi->s_discard_work, ext4_discard_work);
        atomic_set(&sbi->s_retry_alloc_pending, 0);
@@ -3883,19 +3884,10 @@ void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_free_data *entry, *tmp;
        LIST_HEAD(freed_data_list);
-       struct list_head *cut_pos = NULL;
+       struct list_head *s_freed_head = &sbi->s_freed_data_list[commit_tid & 1];
        bool wake;
 
-       spin_lock(&sbi->s_md_lock);
-       list_for_each_entry(entry, &sbi->s_freed_data_list, efd_list) {
-               if (entry->efd_tid != commit_tid)
-                       break;
-               cut_pos = &entry->efd_list;
-       }
-       if (cut_pos)
-               list_cut_position(&freed_data_list, &sbi->s_freed_data_list,
-                                 cut_pos);
-       spin_unlock(&sbi->s_md_lock);
+       list_replace_init(s_freed_head, &freed_data_list);
 
        list_for_each_entry(entry, &freed_data_list, efd_list)
                ext4_free_data_in_buddy(sb, entry);
@@ -6378,7 +6370,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        }
 
        spin_lock(&sbi->s_md_lock);
-       list_add_tail(&new_entry->efd_list, &sbi->s_freed_data_list);
+       list_add_tail(&new_entry->efd_list, &sbi->s_freed_data_list[new_entry->efd_tid & 1]);
        sbi->s_mb_free_pending += clusters;
        spin_unlock(&sbi->s_md_lock);
 }