Skip to contentSkip to conversation

Btrfs: introduce extent buffer cache for each i-node

RFC PATCH Superseded Miao Xie 1 participant 1 message Feb 16, 2012 Btrfs file system

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Miao Xie

author
#0 lore raw

RFC PATCH 1/1 Btrfs: introduce extent buffer cache for each i-node

This patch introduce extent buffer cache for every i-node. By this way, we needn't search the item from the root of b+ tree, and can save the search time. Besides that we can also reduce the lock contention of the root.

Implementation:
- add two pointers of extent buffer into btrfs_inode struct, one for nodes/leaves of fs/file tree, the other for nodes/leaves of the log tree.
- add a BTRFS_HEADER_FLAG_COWED flag, which is used to mark the cowed nodes/leaves
- When we want to search fs/file trees or the relative log trees, we must try to search the cached extent buffer at first, if we can not find the item, we will do the common search. At some condition, we will jump to the common search directly:
I. a new transaction starts.
II. the cached extent buffer was cowed.
III. the cached extent buffer's level is below the level we must lock. and so on.
And beside that, if we can not find the item, and the slot points to the first the item or the last item in the leaf, we must jump out the cached extent buffer search, and do the common search.
- After the common search (use btrfs_search_slot), we will cache the leaf or the level-1 node into the btrfs i-node object.

I have do small file write performance (inline file) by sysbench for the patch, and found it can make btrfs 5%~10% faster.

Surely, I will do function test(such as xfstests) and run more performance test next to validate this patch. And there is some redundant code in this patch. I will cleanup it in the next version.

---
 fs/btrfs/btrfs_inode.h |    3 +
 fs/btrfs/ctree.c       |  358 ++++++++++++++++++++++++++++++++++++++++++++++--
 fs/btrfs/ctree.h       |   41 +++++-
 fs/btrfs/dir-item.c    |   28 +++--
 fs/btrfs/extent_io.c   |    2 +-
 fs/btrfs/file-item.c   |   14 +-
 fs/btrfs/file.c        |    5 +-
 fs/btrfs/inode-item.c  |   11 +-
 fs/btrfs/inode.c       |   44 ++++---
 fs/btrfs/ioctl.c       |    2 +-
 fs/btrfs/relocation.c  |    2 +-
 fs/btrfs/super.c       |    3 +-
 fs/btrfs/tree-log.c    |   19 ++-
 fs/btrfs/xattr.c       |    2 +-
 14 files changed, 463 insertions(+), 71 deletions(-)
fs/btrfs/btrfs_inode.h +3 -0
index 9b9b15f..2374920 100644
@@ -164,6 +164,9 @@ struct btrfs_inode {
 
 	struct btrfs_delayed_node *delayed_node;
 
+	struct extent_buffer *fs_eb;
+	struct extent_buffer *log_eb;
+
 	struct inode vfs_inode;
 };
 
fs/btrfs/ctree.c +348 -10

394 lines not on this page · raw message

fs/btrfs/ctree.h +34 -7

88 lines not on this page · raw message

fs/btrfs/dir-item.c +18 -10
index 31d84e7..050998f 100644
@@ -32,6 +32,7 @@
 static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
 						   *trans,
 						   struct btrfs_root *root,
+						   struct inode *inode,
 						   struct btrfs_path *path,
 						   struct btrfs_key *cpu_key,
 						   u32 data_size,
@@ -43,7 +44,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
 	struct btrfs_item *item;
 	struct extent_buffer *leaf;
 
-	ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size);
+	ret = btrfs_insert_empty_item_for_inode(trans, root, inode, path,
+						cpu_key, data_size);
 	if (ret == -EEXIST) {
 		struct btrfs_dir_item *di;
 		di = btrfs_match_dir_item_name(root, path, name, name_len);
@@ -68,7 +70,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
  */
 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
 			    struct btrfs_root *root,
-			    struct btrfs_path *path, u64 objectid,
+			    struct inode *inode,
+			    struct btrfs_path *path,
 			    const char *name, u16 name_len,
 			    const void *data, u16 data_len)
 {
@@ -82,13 +85,13 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
 
 	BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
 
-	key.objectid = objectid;
+	key.objectid = btrfs_ino(inode);
 	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
 	key.offset = btrfs_name_hash(name, name_len);
 
 	data_size = sizeof(*dir_item) + name_len + data_len;
-	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
-					name, name_len);
+	dir_item = insert_with_overflow(trans, root, inode, path, &key,
+					data_size, name, name_len);
 	if (IS_ERR(dir_item))
 		return PTR_ERR(dir_item);
 	memset(&location, 0, sizeof(location));
@@ -144,7 +147,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	btrfs_cpu_key_to_disk(&disk_key, location);
 
 	data_size = sizeof(*dir_item) + name_len;
-	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
+	dir_item = insert_with_overflow(trans, root, dir, path, &key, data_size,
 					name, name_len);
 	if (IS_ERR(dir_item)) {
 		ret = PTR_ERR(dir_item);
@@ -184,13 +187,14 @@ out_free:
 }
 
 /*
- * lookup a directory item based on name.  'dir' is the objectid
+ * lookup a directory item based on name.  'dirid' is the objectid
  * we're searching in, and 'mod' tells us if you plan on deleting the
  * item (use mod < 0) or changing the options (use mod > 0)
  */
 struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 					     struct btrfs_root *root,
-					     struct btrfs_path *path, u64 dir,
+					     struct inode *dir,
+					     struct btrfs_path *path, u64 dirid,
 					     const char *name, int name_len,
 					     int mod)
 {
@@ -199,12 +203,16 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 	int ins_len = mod < 0 ? -1 : 0;
 	int cow = mod != 0;
 
-	key.objectid = dir;
+	key.objectid = dirid;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 
 	key.offset = btrfs_name_hash(name, name_len);
 
-	ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
+	if (dir)
+		ret = btrfs_search_slot_for_inode(trans, root, dir, &key, path,
+						  ins_len, cow);
+	else
+		ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
 	if (ret < 0)
 		return ERR_PTR(ret);
 	if (ret > 0)
fs/btrfs/extent_io.c +1 -1
index fcf77e1..48c11b3 100644
@@ -3396,7 +3396,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 	 * because there might be preallocation past i_size
 	 */
 	ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
-				       path, btrfs_ino(inode), -1, 0);
+				       path, inode, -1, 0);
 	if (ret < 0) {
 		btrfs_free_path(path);
 		return ret;
fs/btrfs/file-item.c +8 -6
index c7fb3a4..332ff9a 100644
@@ -36,7 +36,7 @@
 
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *root,
-			     u64 objectid, u64 pos,
+			     struct inode *inode, u64 pos,
 			     u64 disk_offset, u64 disk_num_bytes,
 			     u64 num_bytes, u64 offset, u64 ram_bytes,
 			     u8 compression, u8 encryption, u16 other_encoding)
@@ -46,6 +46,7 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
 	struct btrfs_key file_key;
 	struct btrfs_path *path;
 	struct extent_buffer *leaf;
+	u64 objectid = btrfs_ino(inode);
 
 	path = btrfs_alloc_path();
 	if (!path)
@@ -55,8 +56,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
 
 	path->leave_spinning = 1;
-	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
-				      sizeof(*item));
+	ret = btrfs_insert_empty_item_for_inode(trans, root, inode, path,
+						&file_key, sizeof(*item));
 	if (ret < 0)
 		goto out;
 	BUG_ON(ret);
@@ -133,7 +134,7 @@ fail:
 
 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *root,
-			     struct btrfs_path *path, u64 objectid,
+			     struct btrfs_path *path, struct inode *inode,
 			     u64 offset, int mod)
 {
 	int ret;
@@ -141,10 +142,11 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 	int ins_len = mod < 0 ? -1 : 0;
 	int cow = mod != 0;
 
-	file_key.objectid = objectid;
+	file_key.objectid = btrfs_ino(inode);
 	file_key.offset = offset;
 	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
-	ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
+	ret = btrfs_search_slot_for_inode(trans, root, inode, &file_key, path,
+					  ins_len, cow);
 	return ret;
 }
 
fs/btrfs/file.c +3 -2
index 0621a3a..8c7a786 100644
@@ -577,7 +577,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,
 
 	while (1) {
 		recow = 0;
-		ret = btrfs_lookup_file_extent(trans, root, path, ino,
+		ret = btrfs_lookup_file_extent(trans, root, path, inode,
 					       search_start, -1);
 		if (ret < 0)
 			break;
@@ -865,7 +865,8 @@ again:
 	key.type = BTRFS_EXTENT_DATA_KEY;
 	key.offset = split;
 
-	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+	ret = btrfs_search_slot_for_inode(trans, root, inode, &key, path,
+					  -1, 1);
 	if (ret < 0)
 		goto out;
 	if (ret > 0 && path->slots[0] > 0)
fs/btrfs/inode-item.c +6 -5
index baa74f3..68f2031 100644
@@ -77,9 +77,9 @@ btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
 }
 
 int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root,
-			   const char *name, int name_len,
-			   u64 inode_objectid, u64 ref_objectid, u64 *index)
+			struct btrfs_root *root,
+			const char *name, int name_len,
+			struct inode *inode, u64 ref_objectid, u64 *index)
 {
 	struct btrfs_path *path;
 	struct btrfs_key key;
@@ -92,7 +92,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
 	int ret;
 	int del_len = name_len + sizeof(*ref);
 
-	key.objectid = inode_objectid;
+	key.objectid = btrfs_ino(inode);
 	key.offset = ref_objectid;
 	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);
 
@@ -102,7 +102,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
 
 	path->leave_spinning = 1;
 
-	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+	ret = btrfs_search_slot_for_inode(trans, root, inode, &key,
+					  path, -1, 1);
 	if (ret > 0) {
 		ret = -ENOENT;
 		goto out;
fs/btrfs/inode.c +26 -18

146 lines not on this page · raw message

fs/btrfs/ioctl.c +1 -1
index 0b06a5c..7a7fa8b 100644
@@ -2657,7 +2657,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
 	}
 
 	dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
-	di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path,
+	di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, NULL, path,
 				   dir_id, "default", 7, 1);
 	if (IS_ERR_OR_NULL(di)) {
 		btrfs_free_path(path);
fs/btrfs/relocation.c +1 -1
index 8c1aae2..8ebf52f 100644
@@ -1477,7 +1477,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,
 		return -ENOMEM;
 
 	bytenr -= BTRFS_I(reloc_inode)->index_cnt;
-	ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(reloc_inode),
+	ret = btrfs_lookup_file_extent(NULL, root, path, reloc_inode,
 				       bytenr, 0);
 	if (ret < 0)
 		goto out;
fs/btrfs/super.c +2 -1
index 61717a4..f078df7 100644
@@ -573,7 +573,8 @@ static struct dentry *get_default_root(struct super_block *sb,
 	 * to mount.
 	 */
 	dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
-	di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
+	di = btrfs_lookup_dir_item(NULL, root, NULL, path, dir_id, "default",
+				   7, 0);
 	if (IS_ERR(di)) {
 		btrfs_free_path(path);
 		return ERR_CAST(di);
fs/btrfs/tree-log.c +11 -8
index 966cc74..466dd0d 100644
@@ -519,7 +519,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
 	 * file.  This must be done before the btrfs_drop_extents run
 	 * so we don't try to drop this extent.
 	 */
-	ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
+	ret = btrfs_lookup_file_extent(trans, root, path, inode,
 				       start, 0);
 
 	if (ret == 0 &&
@@ -719,7 +719,8 @@ static noinline int inode_in_dir(struct btrfs_root *root,
 		goto out;
 	btrfs_release_path(path);
 
-	di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0);
+	di = btrfs_lookup_dir_item(NULL, root, NULL, path, dirid, name,
+				   name_len, 0);
 	if (di && !IS_ERR(di)) {
 		btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
 		if (location.objectid != objectid)
@@ -922,7 +923,7 @@ again:
 	btrfs_release_path(path);
 
 	/* look for a conflicing name */
-	di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir),
+	di = btrfs_lookup_dir_item(trans, root, dir, path, btrfs_ino(dir),
 				   name, namelen, 0);
 	if (di && !IS_ERR(di)) {
 		ret = drop_one_dir_item(trans, root, path, dir, di);
@@ -1229,8 +1230,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
 	btrfs_release_path(path);
 
 	if (key->type == BTRFS_DIR_ITEM_KEY) {
-		dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid,
-				       name, name_len, 1);
+		dst_di = btrfs_lookup_dir_item(trans, root, NULL, path,
+					       key->objectid, name,
+					       name_len, 1);
 	} else if (key->type == BTRFS_DIR_INDEX_KEY) {
 		dst_di = btrfs_lookup_dir_index_item(trans, root, path,
 						     key->objectid,
@@ -1450,7 +1452,8 @@ again:
 				  name_len);
 		log_di = NULL;
 		if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) {
-			log_di = btrfs_lookup_dir_item(trans, log, log_path,
+			log_di = btrfs_lookup_dir_item(trans, log, dir,
+						       log_path,
 						       dir_key->objectid,
 						       name, name_len, 0);
 		} else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) {
@@ -2262,7 +2265,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 		goto out_unlock;
 	}
 
-	di = btrfs_lookup_dir_item(trans, log, path, dir_ino,
+	di = btrfs_lookup_dir_item(trans, log, dir, path, dir_ino,
 				   name, name_len, -1);
 	if (IS_ERR(di)) {
 		err = PTR_ERR(di);
@@ -2351,7 +2354,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
 	log = root->log_root;
 	mutex_lock(&BTRFS_I(inode)->log_mutex);
 
-	ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode),
+	ret = btrfs_del_inode_ref(trans, log, name, name_len, inode,
 				  dirid, &index);
 	mutex_unlock(&BTRFS_I(inode)->log_mutex);
 	if (ret == -ENOSPC) {
fs/btrfs/xattr.c +1 -1
index e7a5659..c7e3cab 100644
@@ -125,7 +125,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
 	}
 
 again:
-	ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
+	ret = btrfs_insert_xattr_item(trans, root, inode, path,
 				      name, name_len, value, size);
 	/*
 	 * If we're setting an xattr to a new value but the new value is say
Signature · 1 line
1.7.6.5