2023-10-17 22:15:46

by Lu, Davina

[permalink] [raw]
Subject: [PATCH 1/1] ext4: remove the bottleneck of ext4-rsv-conversion work queue



When dioread_nolock and delay_alloc are both enaled, the
bio_endio() will trigger ext4-rsv-conversion work queue to do
ext4_do_flush_completed_IO(). The current work queue is
one-by-one updating for EXT4_IO_END_UNWRITTEN extend block at
io_end->list_vec which added by ext4_writepages().
So if the BIO has high performance, and only one thread to do
EXT4 flush will be an bottleneck. So we simple allow more thread
and with a semaphore protection, since the "ext4-rsv-conversion"
this workqueue is only for updating the EXT4_IO_END_UNWRITTEN
extend block(only exist on dioread_unlock and delay_alloc options
are set).
---
fs/ext4/ext4.h | 1 +
fs/ext4/extents.c | 2 ++
fs/ext4/super.c | 3 ++-
3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0a2d55faa095..15d8d7a1810e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1134,6 +1134,7 @@ struct ext4_inode_info {
atomic_t i_unwritten; /* Nr. of inflight conversions pending */

spinlock_t i_block_reservation_lock;
+ struct rw_semaphore i_rsv_unwritten_sem;

/*
* Transactions that contain inode's metadata needed to complete
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index e4115d338f10..dbd3f69853cf 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4807,6 +4807,7 @@ int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
break;
}
}
+ down_write(&EXT4_I(inode)->i_rsv_unwritten_sem);
ret = ext4_map_blocks(handle, inode, &map,
EXT4_GET_BLOCKS_IO_CONVERT_EXT);
if (ret <= 0)
@@ -4815,6 +4816,7 @@ int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
"ext4_ext_map_blocks returned %d",
inode->i_ino, map.m_lblk,
map.m_len, ret);
+ up_write(&EXT4_I(inode)->i_rsv_unwritten_sem);
ret2 = ext4_mark_inode_dirty(handle, inode);
if (credits) {
ret3 = ext4_journal_stop(handle);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c94ebf704616..af2af5173424 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1466,6 +1466,7 @@ static void init_once(void *foo)
INIT_LIST_HEAD(&ei->i_orphan);
init_rwsem(&ei->xattr_sem);
init_rwsem(&ei->i_data_sem);
+ init_rwsem(&ei->i_rsv_unwritten_sem);
inode_init_once(&ei->vfs_inode);
ext4_fc_init_inode(&ei->vfs_inode);
}
@@ -5452,7 +5453,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
* concurrency isn't really necessary. Limit it to 1.
*/
EXT4_SB(sb)->rsv_conversion_wq =
- alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+ alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
if (!EXT4_SB(sb)->rsv_conversion_wq) {
printk(KERN_ERR "EXT4-fs: failed to create workqueue\n");
err = -ENOMEM;
--
2.40.1