Skip to contentSkip to conversation

Btrfs: introduce extent buffer cache for each i-node

RFC PATCH New Miao Xie 1 participant 1 message Jun 21, 2012 Btrfs file system

lore
Share & tools
lore

Miao Xie

author
#0 lore raw

RFC PATCH v2 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 can save the search time and reduce the lock contention of the root because we needn't search the item from the root of b+ tree.

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 variant to tell us that it is still in the b+ tree.
- When we want to search fs/file trees or the relative log trees, we will 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 done small file performance (inline file) by sysbench and file creation test by fs_mark for the patch, and found it can make btrfs 5% ~ 16% faster.

I think as the tree becomes deeper, the performance improvement of this patch will become bigger.

---
 fs/btrfs/btrfs_inode.h |    3 +
 fs/btrfs/ctree.c       |  591 +++++++++++++++++++++++++++++++++++++-----------
 fs/btrfs/ctree.h       |   40 +++-
 fs/btrfs/dir-item.c    |   28 ++-
 fs/btrfs/extent_io.c   |    2 +-
 fs/btrfs/extent_io.h   |    1 +
 fs/btrfs/file-item.c   |   14 +-
 fs/btrfs/file.c        |    5 +-
 fs/btrfs/inode-item.c  |   11 +-
 fs/btrfs/inode.c       |   46 +++--
 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 +-
 15 files changed, 577 insertions(+), 192 deletions(-)
fs/btrfs/btrfs_inode.h +3 -0
index 12394a9..9912575 100644
@@ -162,6 +162,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 +461 -130

738 lines not on this page · raw message

fs/btrfs/ctree.h +33 -7
index db15e9e..716f1e1 100644
@@ -2709,6 +2709,11 @@ int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
 int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, struct btrfs_path *p, int
 		      ins_len, int cow);
+int btrfs_search_slot_for_inode(struct btrfs_trans_handle *trans,
+				struct btrfs_root *root,
+				struct inode *inode,
+				struct btrfs_key *key, struct btrfs_path *p,
+				int ins_len, int cow);
 int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
 			  struct btrfs_path *p, u64 time_seq);
 int btrfs_realloc_node(struct btrfs_trans_handle *trans,
@@ -2752,6 +2757,25 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 	return btrfs_insert_empty_items(trans, root, path, key, &data_size, 1);
 }
 
+int btrfs_insert_empty_items_for_inode(struct btrfs_trans_handle *trans,
+				       struct btrfs_root *root,
+				       struct inode *inode,
+				       struct btrfs_path *path,
+				       struct btrfs_key *cpu_key,
+				       u32 *data_size,
+				       int nr);
+static inline int btrfs_insert_empty_item_for_inode(
+					struct btrfs_trans_handle *trans,
+					struct btrfs_root *root,
+					struct inode *inode,
+					struct btrfs_path *path,
+					struct btrfs_key *key,
+					u32 data_size)
+{
+	return btrfs_insert_empty_items_for_inode(trans, root, inode, path,
+						  key, &data_size, 1);
+}
+
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
 			u64 time_seq);
@@ -2829,7 +2853,8 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
 			  struct btrfs_key *location, u8 type, u64 index);
 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);
 struct btrfs_dir_item *
@@ -2851,7 +2876,8 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
 			      struct btrfs_dir_item *di);
 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);
 struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
@@ -2876,9 +2902,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
 			   const char *name, int name_len,
 			   u64 inode_objectid, u64 ref_objectid, u64 index);
 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_inode_ref *
 btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root,
@@ -2901,13 +2927,13 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
 			      struct bio *bio, u64 logical_offset, u32 *dst);
 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);
 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 bytenr, int mod);
 int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root,
fs/btrfs/dir-item.c +18 -10
index c1a074d..6a396e6 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);
@@ -67,7 +69,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)
 {
@@ -81,13 +84,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 aaa12c1..9172836 100644
@@ -3753,7 +3753,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/extent_io.h +1 -0
index 25900af..3803812 100644
@@ -129,6 +129,7 @@ struct extent_buffer {
 	unsigned long map_start;
 	unsigned long map_len;
 	unsigned long bflags;
+	u64 root_objectid;
 	struct extent_io_tree *tree;
 	spinlock_t refs_lock;
 	atomic_t refs;
fs/btrfs/file-item.c +8 -6
index 5d158d3..bc90d80 100644
@@ -38,7 +38,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)
@@ -48,6 +48,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)
@@ -57,8 +58,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); /* Can't happen */
@@ -135,7 +136,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;
@@ -143,10 +144,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 fc0f485..c98a3cb 100644
@@ -611,7 +611,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, modify_tree);
 		if (ret < 0)
 			break;
@@ -905,7 +905,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 a13cf1a..db07467 100644
@@ -78,9 +78,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;
@@ -93,7 +93,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);
 
@@ -103,7 +103,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 +27 -19

154 lines not on this page · raw message

fs/btrfs/ioctl.c +1 -1
index 0e92e57..1718afb 100644
@@ -2786,7 +2786,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 646ee21..d149998 100644
@@ -1506,7 +1506,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 0eb9a4d..382df88 100644
@@ -698,7 +698,8 @@ static struct dentry *get_default_root(struct super_block *sb,
 	 * to mount.
 	 */
 	dir_id = btrfs_super_root_dir(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 2017d0f..04dec02 100644
@@ -517,7 +517,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 &&
@@ -717,7 +717,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)
@@ -920,7 +921,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);
@@ -1227,8 +1228,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,
@@ -1448,7 +1450,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) {
@@ -2288,7 +2291,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);
@@ -2379,7 +2382,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 3f4e2d6..1dbbe91 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