[PATCH v2 1/5] btrfs: stop sleeping for one jiffy in non-ssd mounts during log commit
[email protected] Wed, 22 Jul 2026 16:24:38 +0100
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <13fd7ba0d00232d4126531173e9f43e079449775.1784733395.git.fdmanana@suse.com> |
From: Filipe Manana <[email protected]> Joining/starting a log transaction tracks if we ever had more than one task concurrently logging by setting the flag BTRFS_ROOT_MULTI_LOG_TASKS in the respective root. Once set, this flag remains for the rest of the lifetime of the transaction, only cleared when we don't have a log root and need to create a new one (transaction commits drop log roots). During log commit, if we are not on a ssd mount (or use the -o nossd mount option) and the BTRFS_ROOT_MULTI_LOG_TASKS flag is set, we sleep for one jiffy with the excuse to allow future log writers to join and log inodes and then commit a larger log transaction to reduce overall IO. However this is extremely inefficient because: 1) If at some point we had multiple tasks logging concurrently but now we have only one task at a time, we force it to wait for 1 jiffy; 2) One jiffy can vary between 1ms to 10ms, depending on the kernel config option CONFIG_HZ, which by default has a value of 250HZ and that corresponds to 4ms - that is a lot. This massively reduces the latency of fsyncs for non-ssd mounts, even on consumer grade spinning disks. Remove this mechanism to track if we have (or ever had) multiple tasks logging and wait for 1 jiffy. The following fio test was used to benchmark: $ cat fio-buffered-fsync.sh DEV=/dev/sdj MNT=/mnt/sdj MOUNT_OPTIONS="" MKFS_OPTIONS="" if [ $# -ne 6 ]; then echo "Use $0 NUM_JOBS FILE_SIZE IO_SIZE FSYNC_FREQ BLOCK_SIZE [write|randwrite]" exit 1 fi NUM_JOBS=$1 FILE_SIZE=$2 IO_SIZE=$3 FSYNC_FREQ=$4 BLOCK_SIZE=$5 WRITE_MODE=$6 if [ "$WRITE_MODE" != "write" ] && [ "$WRITE_MODE" != "randwrite" ]; then echo "Invalid WRITE_MODE, must be 'write' or 'randwrite'" exit 1 fi cat <<EOF > /tmp/fio-job.ini [writers] rw=$WRITE_MODE fsync=$FSYNC_FREQ fallocate=none group_reporting=1 direct=0 bs=$BLOCK_SIZE ioengine=psync filesize=$FILE_SIZE io_size=$IO_SIZE directory=$MNT numjobs=$NUM_JOBS EOF echo echo "Using config:" echo cat /tmp/fio-job.ini echo umount $MNT &> /dev/null mkfs.btrfs -f $MKFS_OPTIONS $DEV mount $MOUNT_OPTIONS $DEV $MNT fio /tmp/fio-job.ini umount $MNT Running the script as: ./fio-buffered-fsync.sh 8 64M 64M 1 4K randwrite Before patch: WRITE: bw=2647KiB/s (2711kB/s), 2647KiB/s-2647KiB/s (2711kB/s-2711kB/s), io=512MiB (537MB), run=198055-198055msec After patch: WRITE: bw=14.9MiB/s (15.6MB/s), 14.9MiB/s-14.9MiB/s (15.6MB/s-15.6MB/s), io=512MiB (537MB), run=34471-34471msec That's about 5.7 times faster. Signed-off-by: Filipe Manana <[email protected]> --- fs/btrfs/ctree.h | 2 -- fs/btrfs/tree-log.c | 18 +----------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 6de7ad191e04..0f2653182405 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -131,7 +131,6 @@ enum { BTRFS_ROOT_ORPHAN_ITEM_INSERTED, BTRFS_ROOT_DEFRAG_RUNNING, BTRFS_ROOT_FORCE_COW, - BTRFS_ROOT_MULTI_LOG_TASKS, BTRFS_ROOT_DIRTY, BTRFS_ROOT_DELETING, @@ -216,7 +215,6 @@ struct btrfs_root { * to access this field. */ int last_log_commit; - pid_t log_start_pid; u64 last_trans; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 875e4ddc68ea..ccc262833a7c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -316,13 +316,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans, wait_log_commit(root, root->log_transid - 1); goto again; } - - if (!root->log_start_pid) { - clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - root->log_start_pid = current->pid; - } else if (root->log_start_pid != current->pid) { - set_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - } } else { /* * This means fs_info->log_root_tree was already created @@ -340,8 +333,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans, goto out; set_bit(BTRFS_ROOT_HAS_LOG_TREE, &root->state); - clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - root->log_start_pid = current->pid; } atomic_inc(&root->log_writers); @@ -3347,13 +3338,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, while (1) { int batch = atomic_read(&root->log_batch); - /* when we're on an ssd, just kick the log commit out */ - if (!btrfs_test_opt(fs_info, SSD) && - test_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state)) { - mutex_unlock(&root->log_mutex); - schedule_timeout_uninterruptible(1); - mutex_lock(&root->log_mutex); - } + wait_for_writer(root); if (batch == atomic_read(&root->log_batch)) break; @@ -3414,7 +3399,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, btrfs_set_root_log_transid(root, root->log_transid + 1); log->log_transid = root->log_transid; - root->log_start_pid = 0; /* * IO has been started, blocks of the log tree have WRITTEN flag set * in their headers. new modifications of the log will be written to -- 2.47.2