[PATCH 3/7] btrfs: do an initial lockless committed log transaction check during log syncing
[email protected] Wed, 22 Jul 2026 13:41:39 +0100
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <e3e5b937d269982a826ec1b8f65351883e1b5d48.1784656641.git.fdmanana@suse.com> |
From: Filipe Manana <[email protected]> When calling btrfs_sync_log() one of the things we do first is to check if the log transaction the given context belongs to was already committed and return immediately if it was committed before. However we take the root's log_mutex before doing the check, which adds lock contention in case the log transaction was already committed, as this is a heavily used mutex in case we have multiple tasks doing fsyncs or renaming and adding hard links to files that were fsynced before in the current transaction. So add an initial lockless check in btrfs_sync_log() to reduce lock contention. 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 12 64M 64M 1 4K randwrite Before patch: WRITE: bw=16.6MiB/s (17.4MB/s), 16.6MiB/s-16.6MiB/s (17.4MB/s-17.4MB/s), io=768MiB (805MB), run=46235-46235msec After patch: WRITE: bw=18.2MiB/s (19.0MB/s), 18.2MiB/s-18.2MiB/s (19.0MB/s-19.0MB/s), io=768MiB (805MB), run=42277-42277msec Signed-off-by: Filipe Manana <[email protected]> --- fs/btrfs/tree-log.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 580f2aabc065..191308982e9c 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3306,15 +3306,21 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, struct btrfs_root *log = root->log_root; struct btrfs_root *log_root_tree = fs_info->log_root_tree; struct btrfs_root_item new_root_item; - int log_transid = 0; + int log_transid = ctx->log_transid; struct btrfs_log_ctx root_log_ctx; struct blk_plug plug; u64 log_root_start; u64 log_root_level; + /* Avoid fist taking root->log_mutex, reduce lock contention. */ + if (data_race(root->log_transid_committed) >= log_transid) { + trace_btrfs_sync_log_enter(trans, root, ctx); + trace_btrfs_sync_log_exit(trans, root, ctx, ctx->log_ret); + return ctx->log_ret; + } + mutex_lock(&root->log_mutex); trace_btrfs_sync_log_enter(trans, root, ctx); - log_transid = ctx->log_transid; if (root->log_transid_committed >= log_transid) { trace_btrfs_sync_log_exit(trans, root, ctx, ctx->log_ret); mutex_unlock(&root->log_mutex); -- 2.47.2