Btrfs: less fs tree lock contention when using autodefrag
authorFilipe Manana <fdmanana@gmail.com>
Wed, 12 Mar 2014 01:28:24 +0000 (01:28 +0000)
committerChris Mason <clm@fb.com>
Fri, 21 Mar 2014 00:15:27 +0000 (17:15 -0700)
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:  63.034Mb/sec throughtput, read 83.102Gb, written 27.701Gb

Test machine: quad core intel i5-3570K, 32Gb of RAM, SSD.

Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/ioctl.c

index 10c18a6582cc7e30706aa3765dfde70fe42e7dee..3ca313b138caf7d2b73c07fe9b3a4bd7ed95f4fd 100644 (file)
@@ -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;