Skip to content

Commit 5d3e4f1

Browse files
fdmananakdave
authored andcommitted
btrfs: use log root when iterating over index keys when logging directory
When logging dir dentries of a directory, we iterate over the subvolume tree to find dir index keys on leaves modified in the current transaction. This however is heavy on locking, since btrfs_search_forward() may often keep locks on extent buffers for quite a while when walking the tree to find a suitable leaf modified in the current transaction and with a key not smaller than then the provided minimum key. That means it will block other tasks trying to access the subvolume tree, which may be common fs operations like creating, renaming, linking, unlinking, reflinking files, etc. A better solution is to iterate the log tree, since it's much smaller than a subvolume tree and just use plain btrfs_search_slot() (or the wrapper btrfs_for_each_slot()) and only contains dir index keys added in the current transaction. The following bonnie++ test on a non-debug kernel (with Debian's default kernel config) on a 20G null block device, was used to measure the impact: $ cat test.sh #!/bin/bash DEV=/dev/nullb0 MNT=/mnt/nullb0 NR_DIRECTORIES=20 NR_FILES=20480 # must be a multiple of 1024 DATASET_SIZE=$(( (8 * 1024 * 1024 * 1024) / 1048576 )) # 8 GiB as megabytes DIRECTORY_SIZE=$(( DATASET_SIZE / NR_FILES )) NR_FILES=$(( NR_FILES / 1024 )) umount $DEV &> /dev/null mkfs.btrfs -f $DEV mount $DEV $MNT bonnie++ -u root -d $MNT \ -n $NR_FILES:$DIRECTORY_SIZE:$DIRECTORY_SIZE:$NR_DIRECTORIES \ -r 0 -s $DATASET_SIZE -b umount $MNT Before patchset: Version 2.00a ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Name:Size etc /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP debian0 8G 376k 99 1.1g 98 939m 92 1527k 99 3.2g 99 9060 256 Latency 24920us 207us 680ms 5594us 171us 2891us Version 2.00a ------Sequential Create------ --------Random Create-------- debian0 -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 20/20 20480 96 +++++ +++ 20480 95 20480 99 +++++ +++ 20480 97 Latency 8708us 137us 5128us 6743us 60us 19712us After patchset: Version 2.00a ------Sequential Output------ --Sequential Input- --Random- -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Name:Size etc /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP debian0 8G 384k 99 1.2g 99 971m 91 1533k 99 3.3g 99 9180 309 Latency 24930us 125us 661ms 5587us 46us 2020us Version 2.00a ------Sequential Create------ --------Random Create-------- debian0 -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 20/20 20480 90 +++++ +++ 20480 99 20480 99 +++++ +++ 20480 97 Latency 7030us 61us 1246us 4942us 56us 16855us The patchset consists of this patch plus a previous one that has the following subject: "btrfs: avoid iterating over all indexes when logging directory" Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent fa4b8cb commit 5d3e4f1

File tree

1 file changed

+24
-27
lines changed

1 file changed

+24
-27
lines changed

fs/btrfs/tree-log.c

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5399,45 +5399,34 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
53995399

54005400
while (true) {
54015401
struct inode *vfs_inode;
5402-
struct extent_buffer *leaf;
5403-
struct btrfs_key min_key;
5402+
struct btrfs_key key;
5403+
struct btrfs_key found_key;
54045404
u64 next_index;
54055405
bool continue_curr_inode = true;
5406-
int nritems;
5407-
int i;
5406+
int iter_ret;
54085407

5409-
min_key.objectid = ino;
5410-
min_key.type = BTRFS_DIR_INDEX_KEY;
5411-
min_key.offset = btrfs_get_first_dir_index_to_log(curr_inode);
5412-
next_index = min_key.offset;
5408+
key.objectid = ino;
5409+
key.type = BTRFS_DIR_INDEX_KEY;
5410+
key.offset = btrfs_get_first_dir_index_to_log(curr_inode);
5411+
next_index = key.offset;
54135412
again:
5414-
ret = btrfs_search_forward(root, &min_key, path, trans->transid);
5415-
if (ret < 0) {
5416-
break;
5417-
} else if (ret > 0) {
5418-
ret = 0;
5419-
goto next;
5420-
}
5421-
5422-
leaf = path->nodes[0];
5423-
nritems = btrfs_header_nritems(leaf);
5424-
for (i = path->slots[0]; i < nritems; i++) {
5413+
btrfs_for_each_slot(root->log_root, &key, &found_key, path, iter_ret) {
5414+
struct extent_buffer *leaf = path->nodes[0];
54255415
struct btrfs_dir_item *di;
54265416
struct btrfs_key di_key;
54275417
struct inode *di_inode;
54285418
int log_mode = LOG_INODE_EXISTS;
54295419
int type;
54305420

5431-
btrfs_item_key_to_cpu(leaf, &min_key, i);
5432-
if (min_key.objectid != ino ||
5433-
min_key.type != BTRFS_DIR_INDEX_KEY) {
5421+
if (found_key.objectid != ino ||
5422+
found_key.type != BTRFS_DIR_INDEX_KEY) {
54345423
continue_curr_inode = false;
54355424
break;
54365425
}
54375426

5438-
next_index = min_key.offset + 1;
5427+
next_index = found_key.offset + 1;
54395428

5440-
di = btrfs_item_ptr(leaf, i, struct btrfs_dir_item);
5429+
di = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
54415430
type = btrfs_dir_ftype(leaf, di);
54425431
if (btrfs_dir_transid(leaf, di) < trans->transid)
54435432
continue;
@@ -5479,12 +5468,20 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
54795468

54805469
btrfs_release_path(path);
54815470

5482-
if (continue_curr_inode && min_key.offset < (u64)-1) {
5483-
min_key.offset++;
5471+
if (iter_ret < 0) {
5472+
ret = iter_ret;
5473+
goto out;
5474+
} else if (iter_ret > 0) {
5475+
continue_curr_inode = false;
5476+
} else {
5477+
key = found_key;
5478+
}
5479+
5480+
if (continue_curr_inode && key.offset < (u64)-1) {
5481+
key.offset++;
54845482
goto again;
54855483
}
54865484

5487-
next:
54885485
btrfs_set_first_dir_index_to_log(curr_inode, next_index);
54895486

54905487
if (list_empty(&dir_list))

0 commit comments

Comments
 (0)