diff mbox series

[1/1] ext4: remove the bottleneck of ext4-rsv-conversion work queue

Message ID 18c6a1302c9a4a94a44e7262b97c8750@amazon.com
State New
Headers show
Series [1/1] ext4: remove the bottleneck of ext4-rsv-conversion work queue | expand

Commit Message

Lu, Davina Oct. 17, 2023, 10:11 p.m. UTC
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 mbox series

Patch

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;