Btrfs: less fs tree lock contention when using autodefrag
PATCH 1/2 Btrfs: less fs tree lock contention when using autodefrag
When finding new extents during an autodefrag, don't do so many fs tree lookups to find an extent with a size smaller then the target treshold. Instead, after each fs tree forward search immediately unlock upper levels and process the entire leaf while holding a read lock on the leaf, since our leaf processing is very fast.
This reduces lock contention, allowing for higher concurrency when other tasks want to write/update items related to other inodes in the fs tree, as we're not holding read locks on upper tree levels while processing the leaf and we do less tree searches.
Test:
sysbench --test=fileio --file-num=512 --file-total-size=16G \
--file-test-mode=rndrw --num-threads=32 --file-block-size=32768 \
--file-rw-ratio=3 --file-io-mode=sync --max-time=1800 \
--max-requests=10000000000 [prepare|run](fileystem mounted with -o autodefrag, averages of 5 runs)
Before this change: 58.852Mb/sec throughtput, read 77.589Gb, written 25.863Gb After this change: 62.683Mb/sec throughtput, read 82.111Gb, written 27.37Gb
Test machine: quad core intel i5-3570K, 32Gb of RAM, SSD.
--- fs/btrfs/ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/btrfs/ioctl.c +8 -0
@@ -941,6 +941,8 @@ static int find_new_extents(struct btrfs_root *root, ret =btrfs_search_forward (root, &min_key, path, newer_than);if (ret !=0 ) goto none; +btrfs_unlock_up_safe (path,1 ); +process_slot:if (min_key.objectid != ino) goto none;if (min_key.type !=BTRFS_EXTENT_DATA_KEY )
@@ -959,6 +961,12 @@ static int find_new_extents(struct btrfs_root *root,return 0 ; } + path->slots[0 ]++; +if (path->slots[0 ] <btrfs_header_nritems (leaf)) { +btrfs_item_key_to_cpu (leaf, &min_key, path->slots[0 ]); + goto process_slot; + } +if (min_key.offset == (u64)-1 ) goto none;
Signature · 1 line
1.7.9.5
PATCH 2/2 Btrfs: cache extent states in defrag code path
When locking file ranges in the inode's io_tree, cache the first extent state that belongs to the target range, so that when unlocking the range we don't need to search in the io_tree again, reducing cpu time and making and therefore holding the io_tree's lock for a shorter period.
--- fs/btrfs/ioctl.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/btrfs/ioctl.c +9 -4
@@ -994,10 +994,13 @@ static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start)read_unlock (&em_tree->lock);if (!em) { +struct extent_state *cached =NULL ; +u64 end = start + len -1 ; +/* get the big lock and read metadata off disk */ -lock_extent (io_tree, start, start + len -1 ); +lock_extent_bits (io_tree, start, end,0 , &cached); em =btrfs_get_extent (inode,NULL ,0 , start, len,0 ); -unlock_extent (io_tree, start, start + len -1 ); +unlock_extent_cached (io_tree, start, end, &cached,GFP_NOFS );if (IS_ERR (em))return NULL ;
@@ -1136,10 +1139,12 @@ again: page_start =page_offset (page); page_end = page_start +PAGE_CACHE_SIZE -1 ;while (1 ) { -lock_extent (tree, page_start, page_end); +lock_extent_bits (tree, page_start, page_end, +0 , &cached_state); ordered =btrfs_lookup_ordered_extent (inode, page_start); -unlock_extent (tree, page_start, page_end); +unlock_extent_cached (tree, page_start, page_end, + &cached_state,GFP_NOFS );if (!ordered)break ;
Signature · 1 line
1.7.9.5
PATCH v2 1/2 Btrfs: less fs tree lock contention when using autodefrag
In reply to Filipe David Borba MananaWhen finding new extents during an autodefrag, don't do so many fs tree lookups to find an extent with a size smaller then the target treshold. Instead, after each fs tree forward search immediately unlock upper levels and process the entire leaf while holding a read lock on the leaf, since our leaf processing is very fast.
This reduces lock contention, allowing for higher concurrency when other tasks want to write/update items related to other inodes in the fs tree, as we're not holding read locks on upper tree levels while processing the leaf and we do less tree searches.
Test:
sysbench --test=fileio --file-num=512 --file-total-size=16G \
--file-test-mode=rndrw --num-threads=32 --file-block-size=32768 \
--file-rw-ratio=3 --file-io-mode=sync --max-time=1800 \
--max-requests=10000000000 [prepare|run](fileystem mounted with -o autodefrag, averages of 5 runs)
Before this change: 58.852Mb/sec throughtput, read 77.589Gb, written 25.863Gb After this change: 63.034Mb/sec throughtput, read 83.102Gb, written 27.701Gb
Test machine: quad core intel i5-3570K, 32Gb of RAM, SSD.
---
V2: Added missing path->keep_locks reset, which made the unlock_up_safe call
be a noop. And updated commit message test numbers.
fs/btrfs/ioctl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
fs/btrfs/ioctl.c +10 -2
@@ -935,12 +935,14 @@ static int find_new_extents(struct btrfs_root *root, min_key.type =BTRFS_EXTENT_DATA_KEY ; min_key.offset = *off; - path->keep_locks =1 ; -while (1 ) { + path->keep_locks =1 ; ret =btrfs_search_forward (root, &min_key, path, newer_than);if (ret !=0 ) goto none; + path->keep_locks =0 ; +btrfs_unlock_up_safe (path,1 ); +process_slot:if (min_key.objectid != ino) goto none;if (min_key.type !=BTRFS_EXTENT_DATA_KEY )
@@ -959,6 +961,12 @@ static int find_new_extents(struct btrfs_root *root,return 0 ; } + path->slots[0 ]++; +if (path->slots[0 ] <btrfs_header_nritems (leaf)) { +btrfs_item_key_to_cpu (leaf, &min_key, path->slots[0 ]); + goto process_slot; + } +if (min_key.offset == (u64)-1 ) goto none;
Signature · 1 line
1.7.9.5