Skip to contentSkip to conversation

btrfs: implement delayed inode items operation

PATCH In review Miao Xie 3 participants 17 messages Mar 18, 2011 – Mar 24, 2011 Btrfs file system

lore
Share & tools
lore

Miao Xie

author
#0 lore raw

PATCH v4 1/1 btrfs: implement delayed inode items operation

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inodes in time.

Changelog V2 -> V3:
- Fix the race between the delayed worker and the task which does delayed items balance, which is reported by Tsutomu Itoh.
- Modify the patch address David Sterba's comment.
- Fix the bug of the cpu recursion spinlock, reported by Chris Mason

Changelog V1 -> V2:
- break up the global rb-tree, use a list to manage the delayed nodes, which is created for every directory and file, and used to manage the delayed directory name index items and the delayed inode item.
- introduce a worker to deal with the delayed nodes.

Compare with Ext3/4, the performance of file creation and deletion on btrfs is very poor. the reason is that btrfs must do a lot of b+ tree insertions, such as inode item, directory name item, directory name index and so on.

If we can do some delayed b+ tree insertion or deletion, we can improve the performance, so we made this patch which implemented delayed directory name index insertion/deletion and delayed inode update.

Implementation:
- introduce a delayed root object into the filesystem, that use two lists to manage the delayed nodes which are created for every file/directory. One is used to manage all the delayed nodes that have delayed items. And the other is used to manage the delayed nodes which is waiting to be dealt with by the work thread.
- Every delayed node has two rb-tree, one is used to manage the directory name index which is going to be inserted into b+ tree, and the other is used to manage the directory name index which is going to be deleted from b+ tree.
- introduce a worker to deal with the delayed operation. This worker is used to deal with the works of the delayed directory name index items insertion and deletion and the delayed inode update.
When the delayed items is beyond the lower limit, we create works for some delayed nodes and insert them into the work queue of the worker, and then go back.
When the delayed items is beyond the upper bound, we create works for all the delayed nodes that haven't been dealt with, and insert them into the work queue of the worker, and then wait for that the untreated items is below some threshold value.
- When we want to insert a directory name index into b+ tree, we just add the information into the delayed inserting rb-tree.
And then we check the number of the delayed items and do delayed items balance. (The balance policy is above.)
- When we want to delete a directory name index from the b+ tree, we search it in the inserting rb-tree at first. If we look it up, just drop it. If not, add the key of it into the delayed deleting rb-tree.
Similar to the delayed inserting rb-tree, we also check the number of the delayed items and do delayed items balance.
(The same to inserting manipulation)
- When we want to update the metadata of some inode, we cached the data of the inode into the delayed node. the worker will flush it into the b+ tree after dealing with the delayed insertion and deletion.
- We will move the delayed node to the tail of the list after we access the delayed node, By this way, we can cache more delayed items and merge more inode updates.
- If we want to commit transaction, we will deal with all the delayed node.
- the delayed node will be freed when we free the btrfs inode.
- Before we log the inode items, we commit all the directory name index items and the delayed inode update.

I did a quick test by the benchmark tool[1] and found we can improve the performance of file creation by ~15%, and file deletion by ~20%.

Before applying this patch:
Create files:

	Total files: 50000
	Total time: 1.096108
	Average time: 0.000022
Delete files:
	Total files: 50000
	Total time: 1.510403
	Average time: 0.000030

After applying this patch:
Create files:

	Total files: 50000
	Total time: 0.932899
	Average time: 0.000019
Delete files:
	Total files: 50000
	Total time: 1.215732
	Average time: 0.000024

[1] http://marc.info/?l=linux-btrfs&m=128212635122920&q=p3

---
 fs/btrfs/Makefile        |    2 +-
 fs/btrfs/btrfs_inode.h   |    5 +
 fs/btrfs/ctree.c         |   14 +-
 fs/btrfs/ctree.h         |   24 +-
 fs/btrfs/delayed-inode.c | 1629 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/delayed-inode.h |  139 ++++
 fs/btrfs/dir-item.c      |   32 +-
 fs/btrfs/disk-io.c       |   26 +-
 fs/btrfs/extent-tree.c   |   18 +-
 fs/btrfs/inode.c         |  108 +++-
 fs/btrfs/ioctl.c         |    2 +-
 fs/btrfs/super.c         |   10 +-
 fs/btrfs/transaction.c   |   49 ++-
 fs/btrfs/transaction.h   |    2 +
 fs/btrfs/tree-log.c      |    7 +
 15 files changed, 1978 insertions(+), 89 deletions(-)
 create mode 100644 fs/btrfs/delayed-inode.c
 create mode 100644 fs/btrfs/delayed-inode.h
fs/btrfs/Makefile +1 -1
index 31610ea..a8411c2 100644
@@ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
 	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
 	   export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
-	   compression.o delayed-ref.o relocation.o
+	   compression.o delayed-ref.o relocation.o delayed-inode.o
fs/btrfs/btrfs_inode.h +5 -0
index ccc991c..ef3baa8 100644
@@ -22,6 +22,7 @@
 #include "extent_map.h"
 #include "extent_io.h"
 #include "ordered-data.h"
+#include "delayed-inode.h"
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -159,9 +160,13 @@ struct btrfs_inode {
 	 */
 	unsigned force_compress:4;
 
+	struct btrfs_delayed_node *delayed_node;
+
 	struct inode vfs_inode;
 };
 
+extern unsigned char btrfs_filetype_table[];
+
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 {
 	return container_of(inode, struct btrfs_inode, vfs_inode);
fs/btrfs/ctree.c +4 -10
index b5baff0..6e3e4c3 100644
@@ -38,11 +38,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
 			      struct extent_buffer *src_buf);
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   struct btrfs_path *path, int level, int slot);
-static int setup_items_for_insert(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root, struct btrfs_path *path,
-			struct btrfs_key *cpu_key, u32 *data_size,
-			u32 total_data, u32 total_size, int nr);
-
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
@@ -3688,11 +3683,10 @@ out:
  * to save stack depth by doing the bulk of the work in a function
  * that doesn't call btrfs_search_slot
  */
-static noinline_for_stack int
-setup_items_for_insert(struct btrfs_trans_handle *trans,
-		      struct btrfs_root *root, struct btrfs_path *path,
-		      struct btrfs_key *cpu_key, u32 *data_size,
-		      u32 total_data, u32 total_size, int nr)
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr)
 {
 	struct btrfs_item *item;
 	int i;
fs/btrfs/ctree.h +22 -2
index 28188a7..bafca2e 100644
@@ -859,6 +859,7 @@ struct btrfs_block_group_cache {
 struct reloc_control;
 struct btrfs_device;
 struct btrfs_fs_devices;
+struct btrfs_delayed_root;
 struct btrfs_fs_info {
 	u8 fsid[BTRFS_FSID_SIZE];
 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
@@ -885,7 +886,10 @@ struct btrfs_fs_info {
 	/* logical->physical extent mapping */
 	struct btrfs_mapping_tree mapping_tree;
 
-	/* block reservation for extent, checksum and root tree */
+	/*
+	 * block reservation for extent, checksum, root tree and
+	 * delayed dir index item
+	 */
 	struct btrfs_block_rsv global_block_rsv;
 	/* block reservation for delay allocation */
 	struct btrfs_block_rsv delalloc_block_rsv;
@@ -1012,6 +1016,7 @@ struct btrfs_fs_info {
 	 * for the sys_munmap function call path
 	 */
 	struct btrfs_workers fixup_workers;
+	struct btrfs_workers delayed_workers;
 	struct task_struct *transaction_kthread;
 	struct task_struct *cleaner_kthread;
 	int thread_pool_size;
@@ -1069,6 +1074,8 @@ struct btrfs_fs_info {
 
 	/* filesystem state */
 	u64 fs_state;
+
+	struct btrfs_delayed_root *delayed_root;
 };
 
 /*
@@ -2086,6 +2093,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 }
 
 /* extent-tree.c */
+static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
+						 int num_items)
+{
+	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+		3 * num_items;
+}
+
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root, unsigned long count);
@@ -2277,6 +2291,8 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
+void btrfs_clear_path_blocking(struct btrfs_path *p,
+			       struct extent_buffer *held);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2288,6 +2304,10 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
 	return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr);
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, void *data, u32 data_size);
 int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
@@ -2349,7 +2369,7 @@ int btrfs_set_root_node(struct btrfs_root_item *item,
 /* dir-item.c */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root, const char *name,
-			  int name_len, u64 dir,
+			  int name_len, struct inode *dir,
 			  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,
fs/btrfs/delayed-inode.c new file +1629 -0

1,629 lines not on this page · raw message

fs/btrfs/delayed-inode.h new file +139 -0

139 lines not on this page · raw message

fs/btrfs/dir-item.c +10 -22
index f0cad5a..696c793 100644
@@ -124,8 +124,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  * to use for the second index (if one is created).
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-			  *root, const char *name, int name_len, u64 dir,
-			  struct btrfs_key *location, u8 type, u64 index)
+			  *root, const char *name, int name_len,
+			  struct inode *dir, struct btrfs_key *location,
+			  u8 type, u64 index)
 {
 	int ret = 0;
 	int ret2 = 0;
@@ -137,13 +138,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	struct btrfs_disk_key disk_key;
 	u32 data_size;
 
-	key.objectid = dir;
+	key.objectid = dir->i_ino;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 	key.offset = btrfs_name_hash(name, name_len);
 
 	path = btrfs_alloc_path();
+	if (!path)
+		return -ENOMEM;
 	path->leave_spinning = 1;
 
+	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,
 					name, name_len);
@@ -155,7 +160,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	}
 
 	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 	btrfs_set_dir_type(leaf, dir_item, type);
 	btrfs_set_dir_data_len(leaf, dir_item, 0);
@@ -174,24 +178,8 @@ second_insert:
 	}
 	btrfs_release_path(root, path);
 
-	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
-	key.offset = index;
-	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
-					name, name_len);
-	if (IS_ERR(dir_item)) {
-		ret2 = PTR_ERR(dir_item);
-		goto out;
-	}
-	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
-	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-	btrfs_set_dir_type(leaf, dir_item, type);
-	btrfs_set_dir_data_len(leaf, dir_item, 0);
-	btrfs_set_dir_name_len(leaf, dir_item, name_len);
-	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
-	name_ptr = (unsigned long)(dir_item + 1);
-	write_extent_buffer(leaf, name, name_ptr, name_len);
-	btrfs_mark_buffer_dirty(leaf);
+	ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
+					      &disk_key, type, index);
 out:
 	btrfs_free_path(path);
 	if (ret)
fs/btrfs/disk-io.c +21 -5
index 3e1ea3e..ea3c145 100644
@@ -1676,6 +1676,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
 	INIT_LIST_HEAD(&fs_info->ordered_extents);
 	spin_lock_init(&fs_info->ordered_extent_lock);
+	fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root),
+					GFP_NOFS);
+	if (!fs_info->delayed_root) {
+		err = -ENOMEM;
+		goto fail_iput;
+	}
+	btrfs_init_delayed_root(fs_info->delayed_root);
 
 	sb->s_blocksize = 4096;
 	sb->s_blocksize_bits = blksize_bits(4096);
@@ -1743,7 +1750,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	bh = btrfs_read_dev_super(fs_devices->latest_bdev);
 	if (!bh) {
 		err = -EINVAL;
-		goto fail_iput;
+		goto fail_alloc;
 	}
 
 	memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
@@ -1755,7 +1762,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 
 	disk_super = &fs_info->super_copy;
 	if (!btrfs_super_root(disk_super))
-		goto fail_iput;
+		goto fail_alloc;
 
 	/* check FS state, whether FS is broken. */
 	fs_info->fs_state |= btrfs_super_flags(disk_super);
@@ -1765,7 +1772,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	ret = btrfs_parse_options(tree_root, options);
 	if (ret) {
 		err = ret;
-		goto fail_iput;
+		goto fail_alloc;
 	}
 
 	features = btrfs_super_incompat_flags(disk_super) &
@@ -1775,7 +1782,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 		       "unsupported optional features (%Lx).\n",
 		       (unsigned long long)features);
 		err = -EINVAL;
-		goto fail_iput;
+		goto fail_alloc;
 	}
 
 	features = btrfs_super_incompat_flags(disk_super);
@@ -1791,7 +1798,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 		       "unsupported option features (%Lx).\n",
 		       (unsigned long long)features);
 		err = -EINVAL;
-		goto fail_iput;
+		goto fail_alloc;
 	}
 
 	btrfs_init_workers(&fs_info->generic_worker,
@@ -1838,6 +1845,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 			   &fs_info->generic_worker);
 	btrfs_init_workers(&fs_info->endio_freespace_worker, "freespace-write",
 			   1, &fs_info->generic_worker);
+	btrfs_init_workers(&fs_info->delayed_workers, "delayed-meta",
+			   fs_info->thread_pool_size,
+			   &fs_info->generic_worker);
 
 	/*
 	 * endios are largely parallel and should have a very
@@ -1859,6 +1869,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
 	btrfs_start_workers(&fs_info->endio_write_workers, 1);
 	btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
+	btrfs_start_workers(&fs_info->delayed_workers, 1);
 
 	fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
 	fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2104,6 +2115,9 @@ fail_sb_buffer:
 	btrfs_stop_workers(&fs_info->endio_write_workers);
 	btrfs_stop_workers(&fs_info->endio_freespace_worker);
 	btrfs_stop_workers(&fs_info->submit_workers);
+	btrfs_stop_workers(&fs_info->delayed_workers);
+fail_alloc:
+	kfree(fs_info->delayed_root);
 fail_iput:
 	invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
 	iput(fs_info->btree_inode);
@@ -2551,6 +2565,7 @@ int close_ctree(struct btrfs_root *root)
 	del_fs_roots(fs_info);
 
 	iput(fs_info->btree_inode);
+	kfree(fs_info->delayed_root);
 
 	btrfs_stop_workers(&fs_info->generic_worker);
 	btrfs_stop_workers(&fs_info->fixup_workers);
@@ -2562,6 +2577,7 @@ int close_ctree(struct btrfs_root *root)
 	btrfs_stop_workers(&fs_info->endio_write_workers);
 	btrfs_stop_workers(&fs_info->endio_freespace_worker);
 	btrfs_stop_workers(&fs_info->submit_workers);
+	btrfs_stop_workers(&fs_info->delayed_workers);
 
 	btrfs_close_devices(fs_info->fs_devices);
 	btrfs_mapping_tree_free(&fs_info->mapping_tree);
fs/btrfs/extent-tree.c +6 -12
index 100e409..aed763f 100644
@@ -3897,12 +3897,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 	WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
 }
 
-static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
-{
-	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-		3 * num_items;
-}
-
 int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root,
 				 int num_items)
@@ -3913,7 +3907,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 	if (num_items == 0 || root->fs_info->chunk_root == root)
 		return 0;
 
-	num_bytes = calc_trans_metadata_size(root, num_items);
+	num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
 	ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
 				  num_bytes);
 	if (!ret) {
@@ -3952,14 +3946,14 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * If all of the metadata space is used, we can commit
 	 * transaction and use space it freed.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
 void btrfs_orphan_release_metadata(struct inode *inode)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
 }
 
@@ -3973,7 +3967,7 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * two for root back/forward refs, two for directory entries
 	 * and one for root of the snapshot.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 5);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
 	dst_rsv->space_info = src_rsv->space_info;
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
@@ -4000,7 +3994,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 	nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
 	if (nr_extents > BTRFS_I(inode)->reserved_extents) {
 		nr_extents -= BTRFS_I(inode)->reserved_extents;
-		to_reserve = calc_trans_metadata_size(root, nr_extents);
+		to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
 	} else {
 		nr_extents = 0;
 		to_reserve = 0;
@@ -4047,7 +4041,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
 	to_free = calc_csum_metadata_size(inode, num_bytes);
 	if (nr_extents > 0)
-		to_free += calc_trans_metadata_size(root, nr_extents);
+		to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
 
 	btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
 				to_free);
fs/btrfs/inode.c +77 -31

237 lines not on this page · raw message

fs/btrfs/ioctl.c +1 -1
index 5fdb2ab..b200e07 100644
@@ -333,7 +333,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 	BUG_ON(ret);
 
 	ret = btrfs_insert_dir_item(trans, root,
-				    name, namelen, dir->i_ino, &key,
+				    name, namelen, dir, &key,
 				    BTRFS_FT_DIR, index);
 	if (ret)
 		goto fail;
fs/btrfs/super.c +9 -1
index db0a827..593ce8a 100644
@@ -40,6 +40,7 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 #include "compat.h"
+#include "delayed-inode.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -1163,10 +1164,14 @@ static int __init init_btrfs_fs(void)
 	if (err)
 		goto free_extent_io;
 
-	err = btrfs_interface_init();
+	err = btrfs_delayed_inode_init();
 	if (err)
 		goto free_extent_map;
 
+	err = btrfs_interface_init();
+	if (err)
+		goto free_delayed_inode;
+
 	err = register_filesystem(&btrfs_fs_type);
 	if (err)
 		goto unregister_ioctl;
@@ -1176,6 +1181,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
 	btrfs_interface_exit();
+free_delayed_inode:
+	btrfs_delayed_inode_exit();
 free_extent_map:
 	extent_map_exit();
 free_extent_io:
@@ -1192,6 +1199,7 @@ free_sysfs:
 static void __exit exit_btrfs_fs(void)
 {
 	btrfs_destroy_cachep();
+	btrfs_delayed_inode_exit();
 	extent_map_exit();
 	extent_io_exit();
 	btrfs_interface_exit();
fs/btrfs/transaction.c +45 -4

89 lines not on this page · raw message

fs/btrfs/transaction.h +2 -0
index 229a594..a4a441f 100644
@@ -115,6 +115,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 				   int wait_for_unblock);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 				   struct btrfs_root *root);
+int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+				struct btrfs_root *root);
 int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
fs/btrfs/tree-log.c +7 -0
index a4bbb85..e8a2e95 100644
@@ -2775,6 +2775,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 		max_key.type = (u8)-1;
 	max_key.offset = (u64)-1;
 
+	ret = btrfs_commit_inode_delayed_items(trans, root, inode);
+	if (ret) {
+		btrfs_free_path(path);
+		btrfs_free_path(dst_path);
+		return ret;
+	}
+
 	mutex_lock(&BTRFS_I(inode)->log_mutex);
 
 	/*
Signature · 1 line
1.7.3.1
#1 lore raw

Excerpts from Miao Xie's message of 2011-03-18 05:24:46 -0400:

Quoted 3 lines

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inodes in time.

I ran some tests on this and had trouble with my stress.sh script:

http://oss.oracle.com/~mason/stress.sh

I used:

stress.sh -n 50 -c <path to linux kernel git tree> /mnt

The git tree has all the .git files but no .o files.

The problem was that within about 20 minutes, the filesystem was spending almost all of its time in balance_dirty_pages(). The problem is that data writeback isn't complete until the endio handlers have finished inserting metadata into the btree.

The v4 patch calls btrfs_btree_balance_dirty() from all the btrfs_end_transaction variants, which means that the FS writeback code waits for balance_dirty_pages(), which won't make progress until the FS writeback code is done.

So I changed things to call the delayed inode balance function only from inside btrfs_btree_balance_dirty(), which did resolve the stalls. But I found a few times that when I did rmmod btrfs, there would be delayed inode objects leaked in the slab cache. rmmod will try to destroy the slab cache, which will fail because we haven't freed everything.

It looks like we have a race in btrfs_get_or_create_delayed_node, where two concurrent callers can both create delayed nodes and then race on adding it to the inode.

I also think that code is racing with the code that frees delayed nodes, but haven't yet triggered my debugging printks to prove either one.

My current incremental patch is below, please take a look:

fs/btrfs/delayed-inode.c +21 -7
index 727d9a8..02e9390 100644
@@ -32,7 +32,8 @@ int __init btrfs_delayed_inode_init(void)
 	delayed_node_cache = kmem_cache_create("delayed_node",
 					sizeof(struct btrfs_delayed_node),
 					0,
-					SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+					SLAB_RECLAIM_ACCOUNT |
+					SLAB_MEM_SPREAD | SLAB_DESTROY_BY_RCU,
 					NULL);
 	if (!delayed_node_cache)
 		return -ENOMEM;
@@ -90,22 +91,35 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
 	struct btrfs_inode *btrfs_inode = BTRFS_I(inode);
 	struct btrfs_root *root = btrfs_inode->root;
 
-	if (btrfs_inode->delayed_node) {
-		node = btrfs_inode->delayed_node;
-		atomic_inc(&node->refs);	/* can be accessed */
-		return node;
+again:
+	rcu_read_lock();
+again_rcu:
+	node = btrfs_inode->delayed_node;
+	if (node) {
+		if (atomic_inc_not_zero(&node->refs)) {
+			rcu_read_unlock();
+			return node;
+		}
+printk("racing on node access!\n");
+		goto again_rcu;
 	}
+	rcu_read_unlock();
 
 	node = kmem_cache_alloc(delayed_node_cache, GFP_NOFS);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
 	btrfs_init_delayed_node(node, root->objectid, inode->i_ino);
 
-	btrfs_inode->delayed_node = node;
 	node->delayed_root = btrfs_get_delayed_root(root);
 	atomic_inc(&node->refs);	/* cached in the btrfs inode */
 	atomic_inc(&node->refs);	/* can be accessed */
 
+	if (cmpxchg(&BTRFS_I(inode)->delayed_node, NULL, node)) {
+		kmem_cache_free(delayed_node_cache, node);
+printk("racing on new node insertion!\n");
+		goto again;
+	}
+
 	return node;
 }
 
@@ -1167,7 +1181,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
 	nr = trans->blocks_used;
 
 	btrfs_end_transaction_dmeta(trans, root);
-	btrfs_btree_balance_dirty(root, nr);
+	__btrfs_btree_balance_dirty(root, nr);
 free_path:
 	btrfs_free_path(path);
 out:
fs/btrfs/disk-io.c +22 -0
index 0f589b1..0c6c336 100644
@@ -2649,6 +2649,28 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
 		balance_dirty_pages_ratelimited_nr(
 				   root->fs_info->btree_inode->i_mapping, 1);
 	}
+	btrfs_balance_delayed_items(root);
+	return;
+}
+
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+{
+	/*
+	 * looks as though older kernels can get into trouble with
+	 * this code, they end up stuck in balance_dirty_pages forever
+	 */
+	u64 num_dirty;
+	unsigned long thresh = 32 * 1024 * 1024;
+
+	if (current->flags & PF_MEMALLOC)
+		return;
+
+	num_dirty = root->fs_info->dirty_metadata_bytes;
+
+	if (num_dirty > thresh) {
+		balance_dirty_pages_ratelimited_nr(
+				   root->fs_info->btree_inode->i_mapping, 1);
+	}
 	return;
 }
 
fs/btrfs/disk-io.h +1 -0
index 07b20dc..aca35af 100644
@@ -71,6 +71,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 			   u64 block_start,
 			   u64 num_blocks);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
fs/btrfs/inode.c +2 -0
index 6b238b2..ef240d8 100644
@@ -4449,6 +4449,8 @@ void btrfs_dirty_inode(struct inode *inode)
 		}
 	}
 	btrfs_end_transaction(trans, root);
+	if (BTRFS_I(inode)->delayed_node)
+		btrfs_balance_delayed_items(root);
 }
 
 /*
fs/btrfs/transaction.c +0 -6
index 31b328b..8f0ca33 100644
@@ -483,8 +483,6 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 0, 1);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
@@ -496,8 +494,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 1, 1);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
@@ -509,8 +505,6 @@ int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 0, 0);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
author
#2 lore raw
Quoted 20 lines · Chris Mason

Excerpts from Miao Xie's message of 2011-03-18 05:24:46 -0400:

Quoted 3 lines

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inodes in time.

I ran some tests on this and had trouble with my stress.sh script:

http://oss.oracle.com/~mason/stress.sh

I used:

stress.sh -n 50 -c <path to linux kernel git tree> /mnt

The git tree has all the .git files but no .o files.

The problem was that within about 20 minutes, the filesystem was spending almost all of its time in balance_dirty_pages(). The problem is that data writeback isn't complete until the endio handlers have finished inserting metadata into the btree.

Quoted 7 lines

The v4 patch calls btrfs_btree_balance_dirty() from all the btrfs_end_transaction variants, which means that the FS writeback code waits for balance_dirty_pages(), which won't make progress until the FS writeback code is done.

So I changed things to call the delayed inode balance function only from inside btrfs_btree_balance_dirty(), which did resolve the stalls. But

Ok, but can we invoke the delayed inode balance function before balance_dirty_pages_ratelimited_nr(), because the delayed item insertion and deletion also bring us some dirty pages.

Quoted 7 lines

I found a few times that when I did rmmod btrfs, there would be delayed inode objects leaked in the slab cache. rmmod will try to destroy the slab cache, which will fail because we haven't freed everything.

It looks like we have a race in btrfs_get_or_create_delayed_node, where two concurrent callers can both create delayed nodes and then race on adding it to the inode.

Sorry for my mistake, I thought we updated the inodes when holding i_mutex originally, so I didn't use any lock or other method to protect delayed_node of the inodes.

But I think we needn't use rcu lock to protect delayed_node when we want to get the delayed node, because we won't change it after it is created, cmpxchg() and ACCESS_ONCE() can protect it well. What do you think about?

PS: I worry about the inode update without holding i_mutex.

Quoted 2 lines

I also think that code is racing with the code that frees delayed nodes, but haven't yet triggered my debugging printks to prove either one.

We free delayed nodes when we want to destroy the inode, at that time, just one task, which is destroying inode, can access the delayed nodes, so I think ACCESS_ONCE() is enough. What do you think about?

Thanks
Miao

Quoted 161 lines

My current incremental patch is below, please take a look:

fs/btrfs/delayed-inode.c +21 -7
index 727d9a8..02e9390 100644
@@ -32,7 +32,8 @@ int __init btrfs_delayed_inode_init(void)
 	delayed_node_cache = kmem_cache_create("delayed_node",
 					sizeof(struct btrfs_delayed_node),
 					0,
-					SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+					SLAB_RECLAIM_ACCOUNT |
+					SLAB_MEM_SPREAD | SLAB_DESTROY_BY_RCU,
 					NULL);
 	if (!delayed_node_cache)
 		return -ENOMEM;
@@ -90,22 +91,35 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
 	struct btrfs_inode *btrfs_inode = BTRFS_I(inode);
 	struct btrfs_root *root = btrfs_inode->root;
 
-	if (btrfs_inode->delayed_node) {
-		node = btrfs_inode->delayed_node;
-		atomic_inc(&node->refs);	/* can be accessed */
-		return node;
+again:
+	rcu_read_lock();
+again_rcu:
+	node = btrfs_inode->delayed_node;
+	if (node) {
+		if (atomic_inc_not_zero(&node->refs)) {
+			rcu_read_unlock();
+			return node;
+		}
+printk("racing on node access!\n");
+		goto again_rcu;
 	}
+	rcu_read_unlock();
 
 	node = kmem_cache_alloc(delayed_node_cache, GFP_NOFS);
 	if (!node)
 		return ERR_PTR(-ENOMEM);
 	btrfs_init_delayed_node(node, root->objectid, inode->i_ino);
 
-	btrfs_inode->delayed_node = node;
 	node->delayed_root = btrfs_get_delayed_root(root);
 	atomic_inc(&node->refs);	/* cached in the btrfs inode */
 	atomic_inc(&node->refs);	/* can be accessed */
 
+	if (cmpxchg(&BTRFS_I(inode)->delayed_node, NULL, node)) {
+		kmem_cache_free(delayed_node_cache, node);
+printk("racing on new node insertion!\n");
+		goto again;
+	}
+
 	return node;
 }
 
@@ -1167,7 +1181,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
 	nr = trans->blocks_used;
 
 	btrfs_end_transaction_dmeta(trans, root);
-	btrfs_btree_balance_dirty(root, nr);
+	__btrfs_btree_balance_dirty(root, nr);
 free_path:
 	btrfs_free_path(path);
 out:
fs/btrfs/disk-io.c +22 -0
index 0f589b1..0c6c336 100644
@@ -2649,6 +2649,28 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
 		balance_dirty_pages_ratelimited_nr(
 				   root->fs_info->btree_inode->i_mapping, 1);
 	}
+	btrfs_balance_delayed_items(root);
+	return;
+}
+
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+{
+	/*
+	 * looks as though older kernels can get into trouble with
+	 * this code, they end up stuck in balance_dirty_pages forever
+	 */
+	u64 num_dirty;
+	unsigned long thresh = 32 * 1024 * 1024;
+
+	if (current->flags & PF_MEMALLOC)
+		return;
+
+	num_dirty = root->fs_info->dirty_metadata_bytes;
+
+	if (num_dirty > thresh) {
+		balance_dirty_pages_ratelimited_nr(
+				   root->fs_info->btree_inode->i_mapping, 1);
+	}
 	return;
 }
 
fs/btrfs/disk-io.h +1 -0
index 07b20dc..aca35af 100644
@@ -71,6 +71,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 			   u64 block_start,
 			   u64 num_blocks);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
fs/btrfs/inode.c +2 -0
index 6b238b2..ef240d8 100644
@@ -4449,6 +4449,8 @@ void btrfs_dirty_inode(struct inode *inode)
 		}
 	}
 	btrfs_end_transaction(trans, root);
+	if (BTRFS_I(inode)->delayed_node)
+		btrfs_balance_delayed_items(root);
 }
 
 /*
fs/btrfs/transaction.c +0 -7
index 31b328b..8f0ca33 100644
@@ -483,8 +483,6 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 0, 1);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
@@ -496,8 +494,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 1, 1);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
@@ -509,8 +505,6 @@ int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
 	ret = __btrfs_end_transaction(trans, root, 0, 0);
 	if (ret)
 		return ret;
-
-	btrfs_balance_delayed_items(root);
 	return 0;
 }
 
--

To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

Excerpts from Miao Xie's message of 2011-03-21 01:05:22 -0400:

Quoted 26 lines · Chris Mason
Quoted 25 lines

Excerpts from Miao Xie's message of 2011-03-18 05:24:46 -0400:

Quoted 3 lines

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inodes in time.

I ran some tests on this and had trouble with my stress.sh script:

http://oss.oracle.com/~mason/stress.sh

I used:

stress.sh -n 50 -c <path to linux kernel git tree> /mnt

The git tree has all the .git files but no .o files.

The problem was that within about 20 minutes, the filesystem was spending almost all of its time in balance_dirty_pages(). The problem is that data writeback isn't complete until the endio handlers have finished inserting metadata into the btree.

The v4 patch calls btrfs_btree_balance_dirty() from all the btrfs_end_transaction variants, which means that the FS writeback code waits for balance_dirty_pages(), which won't make progress until the FS writeback code is done.

Quoted 6 lines
Quoted 2 lines

So I changed things to call the delayed inode balance function only from inside btrfs_btree_balance_dirty(), which did resolve the stalls. But

Ok, but can we invoke the delayed inode balance function before balance_dirty_pages_ratelimited_nr(), because the delayed item insertion and deletion also bring us some dirty pages.

Yes, good point.

Quoted 9 lines
Quoted 8 lines

I found a few times that when I did rmmod btrfs, there would be delayed inode objects leaked in the slab cache. rmmod will try to destroy the slab cache, which will fail because we haven't freed everything.

It looks like we have a race in btrfs_get_or_create_delayed_node, where two concurrent callers can both create delayed nodes and then race on adding it to the inode.

Quoted 8 lines

Sorry for my mistake, I thought we updated the inodes when holding i_mutex originally, so I didn't use any lock or other method to protect delayed_node of the inodes.

But I think we needn't use rcu lock to protect delayed_node when we want to get the delayed node, because we won't change it after it is created, cmpxchg() and ACCESS_ONCE() can protect it well. What do you think about?

PS: I worry about the inode update without holding i_mutex.

We have the tree locks to make sure we're serialized while we actually change the tree. The only places that go in without locking are times updates.

Quoted 7 lines
Quoted 3 lines

I also think that code is racing with the code that frees delayed nodes, but haven't yet triggered my debugging printks to prove either one.

We free delayed nodes when we want to destroy the inode, at that time, just one task, which is destroying inode, can access the delayed nodes, so I think ACCESS_ONCE() is enough. What do you think about?

Great, I see what you mean. The bigger problem right now is that we may do a lot of operations in destroy_inode(), which can block the slab shrinkers on our metadata operations. That same stress.sh -n 50 run is running into OOM.

So we need to rework the part where the final free is done. We could keep a ref on the inode until the delayed items are complete, or we could let the inode go and make a way to lookup the delayed node when the inode is read.

I'll read more today.

-chris

author
#4 lore raw
Quoted 12 lines · Chris Mason
Quoted 6 lines
Quoted 2 lines

I also think that code is racing with the code that frees delayed nodes, but haven't yet triggered my debugging printks to prove either one.

We free delayed nodes when we want to destroy the inode, at that time, just one task, which is destroying inode, can access the delayed nodes, so I think ACCESS_ONCE() is enough. What do you think about?

Great, I see what you mean. The bigger problem right now is that we may do a lot of operations in destroy_inode(), which can block the slab shrinkers on our metadata operations. That same stress.sh -n 50 run is running into OOM.

Quoted 4 lines

So we need to rework the part where the final free is done. We could keep a ref on the inode until the delayed items are complete, or we could let the inode go and make a way to lookup the delayed node when the inode is read.

I find the slab shrinkers just reclaim inodes which are in the inode_unused list, so if we free delayed nodes before moving the inode into the inode_unused list, we can avoid blocking the slab shrinker. Thus maybe we can fix the above problem by moving btrfs_remove_delayed_node() from btrfs_destroy_inode() to btrfs_drop_inode(). How do you think about?

Thanks
Miao

Quoted 5 lines

I'll read more today.

-chris

author
#5 lore raw
Quoted 18 lines · Miao Xie
Quoted 12 lines · Chris Mason
Quoted 6 lines
Quoted 2 lines

I also think that code is racing with the code that frees delayed nodes, but haven't yet triggered my debugging printks to prove either one.

We free delayed nodes when we want to destroy the inode, at that time, just one task, which is destroying inode, can access the delayed nodes, so I think ACCESS_ONCE() is enough. What do you think about?

Great, I see what you mean. The bigger problem right now is that we may do a lot of operations in destroy_inode(), which can block the slab shrinkers on our metadata operations. That same stress.sh -n 50 run is running into OOM.

Quoted 4 lines

So we need to rework the part where the final free is done. We could keep a ref on the inode until the delayed items are complete, or we could let the inode go and make a way to lookup the delayed node when the inode is read.

Quoted 5 lines

I find the slab shrinkers just reclaim inodes which are in the inode_unused list, so if we free delayed nodes before moving the inode into the inode_unused list, we can avoid blocking the slab shrinker. Thus maybe we can fix the above problem by moving btrfs_remove_delayed_node() from btrfs_destroy_inode() to btrfs_drop_inode(). How do you think about?

This method is not good, because we may do delayed insertion/deletion and free the delayed node when we release the inode, but we may access its delayed node soon.

After reading the lockdep message reported by Kitayama, I guess the reason of the slab shrinker block may not be that we do a lot of operations in destroy_inode(), maybe the real reason is that we pass GFP_KERNEL into kzalloc()(in cache_block_group()), which makes the slab shrinkers hang up. (I don't trigger OOM by running stress.sh till now, so I can't locate this bug.)

Thanks
Miao

Quoted 12 lines
Quoted 6 lines

I'll read more today.

-chris

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw
In reply to Miao Xie

Hi Miao,

Here is an excerpt of the V4 patch applied kernel boot log:

=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.36-xie+ #117
-------------------------------------------------------
vgs/1210 is trying to acquire lock:
(&delayed_node->mutex){+.+...}, at: [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101

but task is already holding lock:
(&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>] sys_mmap_pgoff+0xd6/0x12e

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #1 (&mm->mmap_sem){++++++}:

       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
       [<ffffffff810edc79>] might_fault+0x95/0xb8
       [<ffffffff8112b5ce>] filldir+0x75/0xd0
       [<ffffffff811d77f8>] btrfs_real_readdir+0x3d7/0x528
       [<ffffffff8112b75c>] vfs_readdir+0x79/0xb6
       [<ffffffff8112b8e9>] sys_getdents+0x85/0xd8
       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

-> #0 (&delayed_node->mutex){+.+...}:

       [<ffffffff81076612>] __lock_acquire+0xa98/0xda6
       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
       [<ffffffff814c38b1>] __mutex_lock_common+0x5a/0x444
       [<ffffffff814c3d50>] mutex_lock_nested+0x39/0x3e
       [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101
       [<ffffffff811dbd4f>] btrfs_update_inode+0x2e/0x129
       [<ffffffff811de008>] btrfs_dirty_inode+0x57/0x113
       [<ffffffff8113c2a5>] __mark_inode_dirty+0x33/0x1aa
       [<ffffffff81130939>] touch_atime+0x107/0x12a
       [<ffffffff811e15b2>] btrfs_file_mmap+0x3e/0x57
       [<ffffffff810f5f40>] mmap_region+0x2bb/0x4c4
       [<ffffffff810f63d9>] do_mmap_pgoff+0x290/0x2f3
       [<ffffffff810f6532>] sys_mmap_pgoff+0xf6/0x12e
       [<ffffffff81006e9a>] sys_mmap+0x22/0x24
       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

other info that might help us debug this:

1 lock held by vgs/1210:
#0: (&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>] sys_mmap_pgoff+0xd6/0x12e

stack backtrace:
Pid: 1210, comm: vgs Not tainted 2.6.36-xie+ #117
Call Trace:
 [<ffffffff81074c15>] print_circular_bug+0xaf/0xbd
 [<ffffffff81076612>] __lock_acquire+0xa98/0xda6
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff814c38b1>] __mutex_lock_common+0x5a/0x444
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff8107162f>] ? debug_mutex_init+0x31/0x3c
 [<ffffffff814c3d50>] mutex_lock_nested+0x39/0x3e
 [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff814c36c6>] ? __mutex_unlock_slowpath+0x129/0x13a
 [<ffffffff811dbd4f>] btrfs_update_inode+0x2e/0x129
 [<ffffffff811de008>] btrfs_dirty_inode+0x57/0x113
 [<ffffffff8113c2a5>] __mark_inode_dirty+0x33/0x1aa
 [<ffffffff81130939>] touch_atime+0x107/0x12a
 [<ffffffff811e15b2>] btrfs_file_mmap+0x3e/0x57
 [<ffffffff810f5f40>] mmap_region+0x2bb/0x4c4
 [<ffffffff81229f10>] ? file_map_prot_check+0x9a/0xa3
 [<ffffffff810f63d9>] do_mmap_pgoff+0x290/0x2f3
 [<ffffffff810f6512>] ? sys_mmap_pgoff+0xd6/0x12e
 [<ffffffff810f6532>] sys_mmap_pgoff+0xf6/0x12e
 [<ffffffff814c4b75>] ? trace_hardirqs_on_thunk+0x3a/0x3f
 [<ffffffff81006e9a>] sys_mmap+0x22/0x24
 [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

As the corresponding delayed node mutex lock is taken in btrfs_real_readdir, that seems deadlockable. vfs_readdir holds i_mutex, I wonder if we can execute btrfs_readdir_delayed_dir_index without taking the node lock.

author
#7 lore raw
Quoted 77 lines · Itaru Kitayama

Here is an excerpt of the V4 patch applied kernel boot log:

=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.36-xie+ #117
-------------------------------------------------------
vgs/1210 is trying to acquire lock:
(&delayed_node->mutex){+.+...}, at: [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101

but task is already holding lock:
(&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>] sys_mmap_pgoff+0xd6/0x12e

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #1 (&mm->mmap_sem){++++++}:

       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
       [<ffffffff810edc79>] might_fault+0x95/0xb8
       [<ffffffff8112b5ce>] filldir+0x75/0xd0
       [<ffffffff811d77f8>] btrfs_real_readdir+0x3d7/0x528
       [<ffffffff8112b75c>] vfs_readdir+0x79/0xb6
       [<ffffffff8112b8e9>] sys_getdents+0x85/0xd8
       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

-> #0 (&delayed_node->mutex){+.+...}:

       [<ffffffff81076612>] __lock_acquire+0xa98/0xda6
       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
       [<ffffffff814c38b1>] __mutex_lock_common+0x5a/0x444
       [<ffffffff814c3d50>] mutex_lock_nested+0x39/0x3e
       [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101
       [<ffffffff811dbd4f>] btrfs_update_inode+0x2e/0x129
       [<ffffffff811de008>] btrfs_dirty_inode+0x57/0x113
       [<ffffffff8113c2a5>] __mark_inode_dirty+0x33/0x1aa
       [<ffffffff81130939>] touch_atime+0x107/0x12a
       [<ffffffff811e15b2>] btrfs_file_mmap+0x3e/0x57
       [<ffffffff810f5f40>] mmap_region+0x2bb/0x4c4
       [<ffffffff810f63d9>] do_mmap_pgoff+0x290/0x2f3
       [<ffffffff810f6532>] sys_mmap_pgoff+0xf6/0x12e
       [<ffffffff81006e9a>] sys_mmap+0x22/0x24
       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

other info that might help us debug this:

1 lock held by vgs/1210:
#0: (&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>] sys_mmap_pgoff+0xd6/0x12e

stack backtrace:
Pid: 1210, comm: vgs Not tainted 2.6.36-xie+ #117
Call Trace:
 [<ffffffff81074c15>] print_circular_bug+0xaf/0xbd
 [<ffffffff81076612>] __lock_acquire+0xa98/0xda6
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff814c38b1>] __mutex_lock_common+0x5a/0x444
 [<ffffffff8121184b>] ? btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff8107162f>] ? debug_mutex_init+0x31/0x3c
 [<ffffffff814c3d50>] mutex_lock_nested+0x39/0x3e
 [<ffffffff8121184b>] btrfs_delayed_update_inode+0x45/0x101
 [<ffffffff814c36c6>] ? __mutex_unlock_slowpath+0x129/0x13a
 [<ffffffff811dbd4f>] btrfs_update_inode+0x2e/0x129
 [<ffffffff811de008>] btrfs_dirty_inode+0x57/0x113
 [<ffffffff8113c2a5>] __mark_inode_dirty+0x33/0x1aa
 [<ffffffff81130939>] touch_atime+0x107/0x12a
 [<ffffffff811e15b2>] btrfs_file_mmap+0x3e/0x57
 [<ffffffff810f5f40>] mmap_region+0x2bb/0x4c4
 [<ffffffff81229f10>] ? file_map_prot_check+0x9a/0xa3
 [<ffffffff810f63d9>] do_mmap_pgoff+0x290/0x2f3
 [<ffffffff810f6512>] ? sys_mmap_pgoff+0xd6/0x12e
 [<ffffffff810f6532>] sys_mmap_pgoff+0xf6/0x12e
 [<ffffffff814c4b75>] ? trace_hardirqs_on_thunk+0x3a/0x3f
 [<ffffffff81006e9a>] sys_mmap+0x22/0x24
 [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
Quoted 3 lines

As the corresponding delayed node mutex lock is taken in btrfs_real_readdir, that seems deadlockable. vfs_readdir holds i_mutex, I wonder if we can execute btrfs_readdir_delayed_dir_index without taking the node lock.

We can't fix it by this way, because the work threads may do insertion or deletion at the same time, and we may lose some directory items.

Maybe we can fix it by adding a reference for the delayed directory items, we can do read dir just like this:
1. hold the node lock
2. increase the directory items' reference and put all the directory items into a list
3. release the node lock
4. read dir
5. decrease the directory items' reference and free them if the reference is zero. What do you think about?

Thanks
Miao

Quoted 7 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw
Quoted 2 lines · On Tue, 22 Mar 2011 11:12:37 +0800 Miao Xie <[email protected]> wrote:

We can't fix it by this way, because the work threads may do insertion or deletion at the same time, and we may lose some directory items.

Ok.

Quoted 8 lines

Maybe we can fix it by adding a reference for the delayed directory items, we can do read dir just like this:
1. hold the node lock
2. increase the directory items' reference and put all the directory items into a list
3. release the node lock
4. read dir
5. decrease the directory items' reference and free them if the reference is zero. What do you think about?

Sounds doable to me.

itaru

author
#9 lore raw
Quoted 17 lines · Itaru Kitayama
Quoted 2 lines · On Tue, 22 Mar 2011 11:12:37 +0800 Miao Xie <[email protected]> wrote:

We can't fix it by this way, because the work threads may do insertion or deletion at the same time, and we may lose some directory items.

Ok.

Quoted 8 lines

Maybe we can fix it by adding a reference for the delayed directory items, we can do read dir just like this:
1. hold the node lock
2. increase the directory items' reference and put all the directory items into a list
3. release the node lock
4. read dir
5. decrease the directory items' reference and free them if the reference is zero. What do you think about?

Quoted 1 line

Sounds doable to me.

The V5 patch is attached, could you test it for me? I have run Chris stress test, dbench benchmark on my machine, it work well. I want to check if the above bug still exists or not.

Thanks
Miao

Quoted 5 lines

itaru

From 3be2da7ce535f87548e27721668a9dbdaf74dd46 Mon Sep 17 00:00:00 2001

From: Miao Xie <[email protected]>
Date: Tue, 15 Feb 2011 16:20:15 +0800
Subject: [PATCH] btrfs: implement delayed inode items operation - v5

Changelog V4 -> V5:
- Fix the race on adding the delayed node to the inode, which is spotted by Chris Mason.
- Merge Chris Mason's incremental patch into this patch.
- Fix deadlock between readdir() and memory fault, which is reported by Itaru Kitayama.

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inode in time.

Changelog V2 -> V3:
- Fix the race between the delayed worker and the task which does delayed items balance, which is reported by Tsutomu Itoh.
- Modify the patch address David Sterba's comment.
- Fix the bug of the cpu recursion spinlock, reported by Chris Mason

Changelog V1 -> V2:
- break up the global rb-tree, use a list to manage the delayed nodes, which is created for every directory and file, and used to manage the delayed directory name index items and the delayed inode item.
- introduce a worker to deal with the delayed nodes.

Compare with Ext3/4, the performance of file creation and deletion on btrfs is very poor. the reason is that btrfs must do a lot of b+ tree insertions, such as inode item, directory name item, directory name index and so on.

If we can do some delayed b+ tree insertion or deletion, we can improve the performance, so we made this patch which implemented delayed directory name index insertion/deletion and delayed inode update.

Implementation:
- introduce a delayed root object into the filesystem, that use two lists to manage the delayed nodes which are created for every file/directory. One is used to manage all the delayed nodes that have delayed items. And the other is used to manage the delayed nodes which is waiting to be dealt with by the work thread.
- Every delayed node has two rb-tree, one is used to manage the directory name index which is going to be inserted into b+ tree, and the other is used to manage the directory name index which is going to be deleted from b+ tree.
- introduce a worker to deal with the delayed operation. This worker is used to deal with the works of the delayed directory name index items insertion and deletion and the delayed inode update.
When the delayed items is beyond the lower limit, we create works for some delayed nodes and insert them into the work queue of the worker, and then go back.
When the delayed items is beyond the upper bound, we create works for all the delayed nodes that haven't been dealt with, and insert them into the work queue of the worker, and then wait for that the untreated items is below some threshold value.
- When we want to insert a directory name index into b+ tree, we just add the information into the delayed inserting rb-tree.
And then we check the number of the delayed items and do delayed items balance. (The balance policy is above.)
- When we want to delete a directory name index from the b+ tree, we search it in the inserting rb-tree at first. If we look it up, just drop it. If not, add the key of it into the delayed deleting rb-tree.
Similar to the delayed inserting rb-tree, we also check the number of the delayed items and do delayed items balance.
(The same to inserting manipulation)
- When we want to update the metadata of some inode, we cached the data of the inode into the delayed node. the worker will flush it into the b+ tree after dealing with the delayed insertion and deletion.
- We will move the delayed node to the tail of the list after we access the delayed node, By this way, we can cache more delayed items and merge more inode updates.
- If we want to commit transaction, we will deal with all the delayed node.
- the delayed node will be freed when we free the btrfs inode.
- Before we log the inode items, we commit all the directory name index items and the delayed inode update.

I did a quick test by the benchmark tool[1] and found we can improve the performance of file creation by ~15%, and file deletion by ~20%.

Before applying this patch:
Create files:

	Total files: 50000
	Total time: 1.096108
	Average time: 0.000022
Delete files:
	Total files: 50000
	Total time: 1.510403
	Average time: 0.000030

After applying this patch:
Create files:

	Total files: 50000
	Total time: 0.932899
	Average time: 0.000019
Delete files:
	Total files: 50000
	Total time: 1.215732
	Average time: 0.000024

[1] http://marc.info/?l=linux-btrfs&m=128212635122920&q=p3

---
 fs/btrfs/Makefile        |    2 +-
 fs/btrfs/btrfs_inode.h   |    5 +
 fs/btrfs/ctree.c         |   14 +-
 fs/btrfs/ctree.h         |   24 +-
 fs/btrfs/delayed-inode.c | 1665 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/delayed-inode.h |  142 ++++
 fs/btrfs/dir-item.c      |   32 +-
 fs/btrfs/disk-io.c       |   49 ++-
 fs/btrfs/disk-io.h       |    1 +
 fs/btrfs/extent-tree.c   |   18 +-
 fs/btrfs/inode.c         |  113 +++-
 fs/btrfs/ioctl.c         |    2 +-
 fs/btrfs/super.c         |   10 +-
 fs/btrfs/transaction.c   |   43 ++-
 fs/btrfs/transaction.h   |    2 +
 fs/btrfs/tree-log.c      |    7 +
 16 files changed, 2040 insertions(+), 89 deletions(-)
 create mode 100644 fs/btrfs/delayed-inode.c
 create mode 100644 fs/btrfs/delayed-inode.h
fs/btrfs/Makefile +1 -1
index 31610ea..a8411c2 100644
@@ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
 	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
 	   export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
-	   compression.o delayed-ref.o relocation.o
+	   compression.o delayed-ref.o relocation.o delayed-inode.o
fs/btrfs/btrfs_inode.h +5 -0
index ccc991c..ef3baa8 100644
@@ -22,6 +22,7 @@
 #include "extent_map.h"
 #include "extent_io.h"
 #include "ordered-data.h"
+#include "delayed-inode.h"
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -159,9 +160,13 @@ struct btrfs_inode {
 	 */
 	unsigned force_compress:4;
 
+	struct btrfs_delayed_node *delayed_node;
+
 	struct inode vfs_inode;
 };
 
+extern unsigned char btrfs_filetype_table[];
+
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 {
 	return container_of(inode, struct btrfs_inode, vfs_inode);
fs/btrfs/ctree.c +4 -10
index b5baff0..6e3e4c3 100644
@@ -38,11 +38,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
 			      struct extent_buffer *src_buf);
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   struct btrfs_path *path, int level, int slot);
-static int setup_items_for_insert(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root, struct btrfs_path *path,
-			struct btrfs_key *cpu_key, u32 *data_size,
-			u32 total_data, u32 total_size, int nr);
-
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
@@ -3688,11 +3683,10 @@ out:
  * to save stack depth by doing the bulk of the work in a function
  * that doesn't call btrfs_search_slot
  */
-static noinline_for_stack int
-setup_items_for_insert(struct btrfs_trans_handle *trans,
-		      struct btrfs_root *root, struct btrfs_path *path,
-		      struct btrfs_key *cpu_key, u32 *data_size,
-		      u32 total_data, u32 total_size, int nr)
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr)
 {
 	struct btrfs_item *item;
 	int i;
fs/btrfs/ctree.h +22 -2
index 28188a7..bafca2e 100644
@@ -859,6 +859,7 @@ struct btrfs_block_group_cache {
 struct reloc_control;
 struct btrfs_device;
 struct btrfs_fs_devices;
+struct btrfs_delayed_root;
 struct btrfs_fs_info {
 	u8 fsid[BTRFS_FSID_SIZE];
 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
@@ -885,7 +886,10 @@ struct btrfs_fs_info {
 	/* logical->physical extent mapping */
 	struct btrfs_mapping_tree mapping_tree;
 
-	/* block reservation for extent, checksum and root tree */
+	/*
+	 * block reservation for extent, checksum, root tree and
+	 * delayed dir index item
+	 */
 	struct btrfs_block_rsv global_block_rsv;
 	/* block reservation for delay allocation */
 	struct btrfs_block_rsv delalloc_block_rsv;
@@ -1012,6 +1016,7 @@ struct btrfs_fs_info {
 	 * for the sys_munmap function call path
 	 */
 	struct btrfs_workers fixup_workers;
+	struct btrfs_workers delayed_workers;
 	struct task_struct *transaction_kthread;
 	struct task_struct *cleaner_kthread;
 	int thread_pool_size;
@@ -1069,6 +1074,8 @@ struct btrfs_fs_info {
 
 	/* filesystem state */
 	u64 fs_state;
+
+	struct btrfs_delayed_root *delayed_root;
 };
 
 /*
@@ -2086,6 +2093,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 }
 
 /* extent-tree.c */
+static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
+						 int num_items)
+{
+	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+		3 * num_items;
+}
+
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root, unsigned long count);
@@ -2277,6 +2291,8 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
+void btrfs_clear_path_blocking(struct btrfs_path *p,
+			       struct extent_buffer *held);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2288,6 +2304,10 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
 	return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr);
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, void *data, u32 data_size);
 int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
@@ -2349,7 +2369,7 @@ int btrfs_set_root_node(struct btrfs_root_item *item,
 /* dir-item.c */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root, const char *name,
-			  int name_len, u64 dir,
+			  int name_len, struct inode *dir,
 			  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,
fs/btrfs/delayed-inode.c new file +1665 -0

1,665 lines not on this page · raw message

fs/btrfs/delayed-inode.h new file +142 -0

142 lines not on this page · raw message

fs/btrfs/dir-item.c +10 -22
index f0cad5a..696c793 100644
@@ -124,8 +124,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  * to use for the second index (if one is created).
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-			  *root, const char *name, int name_len, u64 dir,
-			  struct btrfs_key *location, u8 type, u64 index)
+			  *root, const char *name, int name_len,
+			  struct inode *dir, struct btrfs_key *location,
+			  u8 type, u64 index)
 {
 	int ret = 0;
 	int ret2 = 0;
@@ -137,13 +138,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	struct btrfs_disk_key disk_key;
 	u32 data_size;
 
-	key.objectid = dir;
+	key.objectid = dir->i_ino;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 	key.offset = btrfs_name_hash(name, name_len);
 
 	path = btrfs_alloc_path();
+	if (!path)
+		return -ENOMEM;
 	path->leave_spinning = 1;
 
+	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,
 					name, name_len);
@@ -155,7 +160,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	}
 
 	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 	btrfs_set_dir_type(leaf, dir_item, type);
 	btrfs_set_dir_data_len(leaf, dir_item, 0);
@@ -174,24 +178,8 @@ second_insert:
 	}
 	btrfs_release_path(root, path);
 
-	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
-	key.offset = index;
-	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
-					name, name_len);
-	if (IS_ERR(dir_item)) {
-		ret2 = PTR_ERR(dir_item);
-		goto out;
-	}
-	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
-	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-	btrfs_set_dir_type(leaf, dir_item, type);
-	btrfs_set_dir_data_len(leaf, dir_item, 0);
-	btrfs_set_dir_name_len(leaf, dir_item, name_len);
-	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
-	name_ptr = (unsigned long)(dir_item + 1);
-	write_extent_buffer(leaf, name, name_ptr, name_len);
-	btrfs_mark_buffer_dirty(leaf);
+	ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
+					      &disk_key, type, index);
 out:
 	btrfs_free_path(path);
 	if (ret)
fs/btrfs/disk-io.c +44 -5

121 lines not on this page · raw message

fs/btrfs/disk-io.h +1 -0
index 07b20dc..aca35af 100644
@@ -71,6 +71,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 			   u64 block_start,
 			   u64 num_blocks);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
fs/btrfs/extent-tree.c +6 -12
index 100e409..aed763f 100644
@@ -3897,12 +3897,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 	WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
 }
 
-static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
-{
-	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-		3 * num_items;
-}
-
 int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root,
 				 int num_items)
@@ -3913,7 +3907,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 	if (num_items == 0 || root->fs_info->chunk_root == root)
 		return 0;
 
-	num_bytes = calc_trans_metadata_size(root, num_items);
+	num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
 	ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
 				  num_bytes);
 	if (!ret) {
@@ -3952,14 +3946,14 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * If all of the metadata space is used, we can commit
 	 * transaction and use space it freed.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
 void btrfs_orphan_release_metadata(struct inode *inode)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
 }
 
@@ -3973,7 +3967,7 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * two for root back/forward refs, two for directory entries
 	 * and one for root of the snapshot.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 5);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
 	dst_rsv->space_info = src_rsv->space_info;
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
@@ -4000,7 +3994,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 	nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
 	if (nr_extents > BTRFS_I(inode)->reserved_extents) {
 		nr_extents -= BTRFS_I(inode)->reserved_extents;
-		to_reserve = calc_trans_metadata_size(root, nr_extents);
+		to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
 	} else {
 		nr_extents = 0;
 		to_reserve = 0;
@@ -4047,7 +4041,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
 	to_free = calc_csum_metadata_size(inode, num_bytes);
 	if (nr_extents > 0)
-		to_free += calc_trans_metadata_size(root, nr_extents);
+		to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
 
 	btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
 				to_free);
fs/btrfs/inode.c +82 -31

248 lines not on this page · raw message

fs/btrfs/ioctl.c +1 -1
index 5fdb2ab..b200e07 100644
@@ -333,7 +333,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 	BUG_ON(ret);
 
 	ret = btrfs_insert_dir_item(trans, root,
-				    name, namelen, dir->i_ino, &key,
+				    name, namelen, dir, &key,
 				    BTRFS_FT_DIR, index);
 	if (ret)
 		goto fail;
fs/btrfs/super.c +9 -1
index db0a827..593ce8a 100644
@@ -40,6 +40,7 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 #include "compat.h"
+#include "delayed-inode.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -1163,10 +1164,14 @@ static int __init init_btrfs_fs(void)
 	if (err)
 		goto free_extent_io;
 
-	err = btrfs_interface_init();
+	err = btrfs_delayed_inode_init();
 	if (err)
 		goto free_extent_map;
 
+	err = btrfs_interface_init();
+	if (err)
+		goto free_delayed_inode;
+
 	err = register_filesystem(&btrfs_fs_type);
 	if (err)
 		goto unregister_ioctl;
@@ -1176,6 +1181,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
 	btrfs_interface_exit();
+free_delayed_inode:
+	btrfs_delayed_inode_exit();
 free_extent_map:
 	extent_map_exit();
 free_extent_io:
@@ -1192,6 +1199,7 @@ free_sysfs:
 static void __exit exit_btrfs_fs(void)
 {
 	btrfs_destroy_cachep();
+	btrfs_delayed_inode_exit();
 	extent_map_exit();
 	extent_io_exit();
 	btrfs_interface_exit();
fs/btrfs/transaction.c +39 -4

83 lines not on this page · raw message

fs/btrfs/transaction.h +2 -0
index 229a594..a4a441f 100644
@@ -115,6 +115,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 				   int wait_for_unblock);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 				   struct btrfs_root *root);
+int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+				struct btrfs_root *root);
 int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
fs/btrfs/tree-log.c +7 -0
index a4bbb85..e8a2e95 100644
@@ -2775,6 +2775,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 		max_key.type = (u8)-1;
 	max_key.offset = (u64)-1;
 
+	ret = btrfs_commit_inode_delayed_items(trans, root, inode);
+	if (ret) {
+		btrfs_free_path(path);
+		btrfs_free_path(dst_path);
+		return ret;
+	}
+
 	mutex_lock(&BTRFS_I(inode)->log_mutex);
 
 	/*
Signature · 1 line
1.7.3.1
#10 lore raw

Hi Miao,

Quoted 5 lines · On Tue, 22 Mar 2011 18:03:24 +0800 Miao Xie <[email protected]> wrote:

The V5 patch is attached, could you test it for me? I have run Chris stress test, dbench benchmark on my machine, it work well. I want to check if the above bug still exists or not.

Thanks
Miao

Here's the boot log (The V5 patch is on top of the btrfs-unstable next-rc branch):

BUG: unable to handle kernel NULL pointer dereference at 00000000000000c8
IP: [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
PGD 7074c067 PUD 75b6d067 PMD 0 
Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
last sysfs file: /sys/devices/virtual/bdi/btrfs-1/uevent
CPU 0 
Modules linked in: mptspi mptscsih mptbase scsi_transport_spi

Pid: 1, comm: init Not tainted 2.6.36-xie+ #120 440BX Desktop Reference Platform/VMware Virtual Platform

RIP: 0010:[<ffffffff81075c12>]  [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
RSP: 0018:ffff88007ceafb58  EFLAGS: 00010097
RAX: 0000000000000046 RBX: ffff88007ceb0050 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000c8
RBP: ffff88007ceafc18 R08: 0000000000000002 R09: 0000000000000000
R10: 0000000000000000 R11: ffff88007ceafd48 R12: ffff88007ceb0050
R13: 00000000000000c8 R14: 0000000000000002 R15: 0000000000000000
FS:  00007f1fe74e7720(0000) GS:ffff880004e00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 00000000000000c8 CR3: 0000000070486000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process init (pid: 1, threadinfo ffff88007ceae000, task ffff88007ceb0050)
Stack:
 0000000000000002 0000000000000001 ffff88007ceafb78 ffffffff810bdd5d
<0> ffff880000000000 ffffffff00000000 ffff88007ceafbc8 0000000000000046
<0> ffff88007ceafba8 ffff88007ceb0050 ffffffff81067dcd 0000000000000001
Call Trace:
 [<ffffffff810bdd5d>] ? time_hardirqs_off+0x2e/0x36
 [<ffffffff81067dcd>] ? local_clock+0x2a/0x3b
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff8110ba5f>] ? virt_to_head_page+0xe/0x31
 [<ffffffff8110dbbc>] ? cache_alloc_debugcheck_after+0x176/0x1cd
 [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
 [<ffffffff8121294b>] btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff811d7e01>] btrfs_real_readdir+0x170/0x52c
 [<ffffffff8112b739>] ? vfs_readdir+0x56/0xb6
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff810bdfc0>] ? trace_preempt_on+0x24/0x26
 [<ffffffff814cb4e8>] ? sub_preempt_count+0xa3/0xb6
 [<ffffffff814c6645>] ? __mutex_lock_common+0x3ee/0x444
 [<ffffffff8112b739>] ? vfs_readdir+0x56/0xb6
 [<ffffffff8111e435>] ? rcu_read_unlock+0x0/0x4b
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff8112b75c>] vfs_readdir+0x79/0xb6
 [<ffffffff8112b8e9>] sys_getdents+0x85/0xd8
 [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
Code: 58 e2 8b 01 00 be b3 0a 00 00 0f 85 c4 0c 00 00 e9 4d 0c 00 00 83 fe 07 76 11 e8 7e 55 1f 00 48 c7 c7 55 85 78 81 e9 78 0c 00 00 <49> 8 
RIP  [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
 RSP <ffff88007ceafb58>
CR2: 00000000000000c8
---[ end trace 87f215b3568d553d ]---
author
#11 lore raw

Hi, Kitayama-san

I'm sorry, I sent a intermediate version to you, The attached file is the correct one.

Thanks

Quoted 71 lines · Itaru Kitayama

Hi Miao,

Quoted 5 lines · On Tue, 22 Mar 2011 18:03:24 +0800 Miao Xie <[email protected]> wrote:

The V5 patch is attached, could you test it for me? I have run Chris stress test, dbench benchmark on my machine, it work well. I want to check if the above bug still exists or not.

Thanks
Miao

Here's the boot log (The V5 patch is on top of the btrfs-unstable next-rc branch):

BUG: unable to handle kernel NULL pointer dereference at 00000000000000c8
IP: [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
PGD 7074c067 PUD 75b6d067 PMD 0 
Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
last sysfs file: /sys/devices/virtual/bdi/btrfs-1/uevent
CPU 0 
Modules linked in: mptspi mptscsih mptbase scsi_transport_spi

Pid: 1, comm: init Not tainted 2.6.36-xie+ #120 440BX Desktop Reference Platform/VMware Virtual Platform

RIP: 0010:[<ffffffff81075c12>]  [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
RSP: 0018:ffff88007ceafb58  EFLAGS: 00010097
RAX: 0000000000000046 RBX: ffff88007ceb0050 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000000000c8
RBP: ffff88007ceafc18 R08: 0000000000000002 R09: 0000000000000000
R10: 0000000000000000 R11: ffff88007ceafd48 R12: ffff88007ceb0050
R13: 00000000000000c8 R14: 0000000000000002 R15: 0000000000000000
FS:  00007f1fe74e7720(0000) GS:ffff880004e00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 00000000000000c8 CR3: 0000000070486000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process init (pid: 1, threadinfo ffff88007ceae000, task ffff88007ceb0050)
Stack:
 0000000000000002 0000000000000001 ffff88007ceafb78 ffffffff810bdd5d
<0> ffff880000000000 ffffffff00000000 ffff88007ceafbc8 0000000000000046
<0> ffff88007ceafba8 ffff88007ceb0050 ffffffff81067dcd 0000000000000001
Call Trace:
 [<ffffffff810bdd5d>] ? time_hardirqs_off+0x2e/0x36
 [<ffffffff81067dcd>] ? local_clock+0x2a/0x3b
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
 [<ffffffff8121294b>] ? btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff8110ba5f>] ? virt_to_head_page+0xe/0x31
 [<ffffffff8110dbbc>] ? cache_alloc_debugcheck_after+0x176/0x1cd
 [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
 [<ffffffff8121294b>] btrfs_get_delayed_items+0x37/0xb6
 [<ffffffff811d7e01>] btrfs_real_readdir+0x170/0x52c
 [<ffffffff8112b739>] ? vfs_readdir+0x56/0xb6
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff810bdfc0>] ? trace_preempt_on+0x24/0x26
 [<ffffffff814cb4e8>] ? sub_preempt_count+0xa3/0xb6
 [<ffffffff814c6645>] ? __mutex_lock_common+0x3ee/0x444
 [<ffffffff8112b739>] ? vfs_readdir+0x56/0xb6
 [<ffffffff8111e435>] ? rcu_read_unlock+0x0/0x4b
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff8112b559>] ? filldir+0x0/0xd0
 [<ffffffff8112b75c>] vfs_readdir+0x79/0xb6
 [<ffffffff8112b8e9>] sys_getdents+0x85/0xd8
 [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
Code: 58 e2 8b 01 00 be b3 0a 00 00 0f 85 c4 0c 00 00 e9 4d 0c 00 00 83 fe 07 76 11 e8 7e 55 1f 00 48 c7 c7 55 85 78 81 e9 78 0c 00 00 <49> 8 
RIP  [<ffffffff81075c12>] __lock_acquire+0x98/0xda6
 RSP <ffff88007ceafb58>
CR2: 00000000000000c8
---[ end trace 87f215b3568d553d ]---
Quoted 7 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

From f97b0811b193914a90b6cc20d25492387a369464 Mon Sep 17 00:00:00 2001

From: Miao Xie <[email protected]>
Date: Tue, 15 Feb 2011 16:20:15 +0800
Subject: [PATCH] btrfs: implement delayed inode items operation - v5

Changelog V4 -> V5:
- Fix the race on adding the delayed node to the inode, which is reported by Chris Mason, and fix advice is also from him.
- Fix deadlock between readdir() and memory fault, which is reported by Itaru Kitayama.

Changelog V3 -> V4:
- Fix nested lock, which is reported by Itaru Kitayama, by updating space cache inode in time.

Changelog V2 -> V3:
- Fix the race between the delayed worker and the task which does delayed items balance, which is reported by Tsutomu Itoh.
- Modify the patch address David Sterba's comment.
- Fix the bug of the cpu recursion spinlock, reported by Chris Mason

Changelog V1 -> V2:
- break up the global rb-tree, use a list to manage the delayed nodes, which is created for every directory and file, and used to manage the delayed directory name index items and the delayed inode item.
- introduce a worker to deal with the delayed nodes.

Compare with Ext3/4, the performance of file creation and deletion on btrfs is very poor. the reason is that btrfs must do a lot of b+ tree insertions, such as inode item, directory name item, directory name index and so on.

If we can do some delayed b+ tree insertion or deletion, we can improve the performance, so we made this patch which implemented delayed directory name index insertion/deletion and delayed inode update.

Implementation:
- introduce a delayed root object into the filesystem, that use two lists to manage the delayed nodes which are created for every file/directory. One is used to manage all the delayed nodes that have delayed items. And the other is used to manage the delayed nodes which is waiting to be dealt with by the work thread.
- Every delayed node has two rb-tree, one is used to manage the directory name index which is going to be inserted into b+ tree, and the other is used to manage the directory name index which is going to be deleted from b+ tree.
- introduce a worker to deal with the delayed operation. This worker is used to deal with the works of the delayed directory name index items insertion and deletion and the delayed inode update.
When the delayed items is beyond the lower limit, we create works for some delayed nodes and insert them into the work queue of the worker, and then go back.
When the delayed items is beyond the upper bound, we create works for all the delayed nodes that haven't been dealt with, and insert them into the work queue of the worker, and then wait for that the untreated items is below some threshold value.
- When we want to insert a directory name index into b+ tree, we just add the information into the delayed inserting rb-tree.
And then we check the number of the delayed items and do delayed items balance. (The balance policy is above.)
- When we want to delete a directory name index from the b+ tree, we search it in the inserting rb-tree at first. If we look it up, just drop it. If not, add the key of it into the delayed deleting rb-tree.
Similar to the delayed inserting rb-tree, we also check the number of the delayed items and do delayed items balance.
(The same to inserting manipulation)
- When we want to update the metadata of some inode, we cached the data of the inode into the delayed node. the worker will flush it into the b+ tree after dealing with the delayed insertion and deletion.
- We will move the delayed node to the tail of the list after we access the delayed node, By this way, we can cache more delayed items and merge more inode updates.
- If we want to commit transaction, we will deal with all the delayed node.
- the delayed node will be freed when we free the btrfs inode.
- Before we log the inode items, we commit all the directory name index items and the delayed inode update.

I did a quick test by the benchmark tool[1] and found we can improve the performance of file creation by ~15%, and file deletion by ~20%.

Before applying this patch:
Create files:

	Total files: 50000
	Total time: 1.096108
	Average time: 0.000022
Delete files:
	Total files: 50000
	Total time: 1.510403
	Average time: 0.000030

After applying this patch:
Create files:

	Total files: 50000
	Total time: 0.932899
	Average time: 0.000019
Delete files:
	Total files: 50000
	Total time: 1.215732
	Average time: 0.000024

[1] http://marc.info/?l=linux-btrfs&m=128212635122920&q=p3

---
 fs/btrfs/Makefile        |    2 +-
 fs/btrfs/btrfs_inode.h   |    5 +
 fs/btrfs/ctree.c         |   14 +-
 fs/btrfs/ctree.h         |   24 +-
 fs/btrfs/delayed-inode.c | 1665 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/delayed-inode.h |  142 ++++
 fs/btrfs/dir-item.c      |   32 +-
 fs/btrfs/disk-io.c       |   49 ++-
 fs/btrfs/disk-io.h       |    1 +
 fs/btrfs/extent-tree.c   |   18 +-
 fs/btrfs/inode.c         |  113 +++-
 fs/btrfs/ioctl.c         |    2 +-
 fs/btrfs/super.c         |   10 +-
 fs/btrfs/transaction.c   |   43 ++-
 fs/btrfs/transaction.h   |    2 +
 fs/btrfs/tree-log.c      |    7 +
 16 files changed, 2040 insertions(+), 89 deletions(-)
 create mode 100644 fs/btrfs/delayed-inode.c
 create mode 100644 fs/btrfs/delayed-inode.h
fs/btrfs/Makefile +1 -1
index 31610ea..a8411c2 100644
@@ -7,4 +7,4 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
 	   extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
 	   extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
 	   export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
-	   compression.o delayed-ref.o relocation.o
+	   compression.o delayed-ref.o relocation.o delayed-inode.o
fs/btrfs/btrfs_inode.h +5 -0
index ccc991c..ef3baa8 100644
@@ -22,6 +22,7 @@
 #include "extent_map.h"
 #include "extent_io.h"
 #include "ordered-data.h"
+#include "delayed-inode.h"
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -159,9 +160,13 @@ struct btrfs_inode {
 	 */
 	unsigned force_compress:4;
 
+	struct btrfs_delayed_node *delayed_node;
+
 	struct inode vfs_inode;
 };
 
+extern unsigned char btrfs_filetype_table[];
+
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
 {
 	return container_of(inode, struct btrfs_inode, vfs_inode);
fs/btrfs/ctree.c +4 -10
index b5baff0..6e3e4c3 100644
@@ -38,11 +38,6 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
 			      struct extent_buffer *src_buf);
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   struct btrfs_path *path, int level, int slot);
-static int setup_items_for_insert(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root, struct btrfs_path *path,
-			struct btrfs_key *cpu_key, u32 *data_size,
-			u32 total_data, u32 total_size, int nr);
-
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
@@ -3688,11 +3683,10 @@ out:
  * to save stack depth by doing the bulk of the work in a function
  * that doesn't call btrfs_search_slot
  */
-static noinline_for_stack int
-setup_items_for_insert(struct btrfs_trans_handle *trans,
-		      struct btrfs_root *root, struct btrfs_path *path,
-		      struct btrfs_key *cpu_key, u32 *data_size,
-		      u32 total_data, u32 total_size, int nr)
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr)
 {
 	struct btrfs_item *item;
 	int i;
fs/btrfs/ctree.h +22 -2
index 28188a7..bafca2e 100644
@@ -859,6 +859,7 @@ struct btrfs_block_group_cache {
 struct reloc_control;
 struct btrfs_device;
 struct btrfs_fs_devices;
+struct btrfs_delayed_root;
 struct btrfs_fs_info {
 	u8 fsid[BTRFS_FSID_SIZE];
 	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
@@ -885,7 +886,10 @@ struct btrfs_fs_info {
 	/* logical->physical extent mapping */
 	struct btrfs_mapping_tree mapping_tree;
 
-	/* block reservation for extent, checksum and root tree */
+	/*
+	 * block reservation for extent, checksum, root tree and
+	 * delayed dir index item
+	 */
 	struct btrfs_block_rsv global_block_rsv;
 	/* block reservation for delay allocation */
 	struct btrfs_block_rsv delalloc_block_rsv;
@@ -1012,6 +1016,7 @@ struct btrfs_fs_info {
 	 * for the sys_munmap function call path
 	 */
 	struct btrfs_workers fixup_workers;
+	struct btrfs_workers delayed_workers;
 	struct task_struct *transaction_kthread;
 	struct task_struct *cleaner_kthread;
 	int thread_pool_size;
@@ -1069,6 +1074,8 @@ struct btrfs_fs_info {
 
 	/* filesystem state */
 	u64 fs_state;
+
+	struct btrfs_delayed_root *delayed_root;
 };
 
 /*
@@ -2086,6 +2093,13 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 }
 
 /* extent-tree.c */
+static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
+						 int num_items)
+{
+	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
+		3 * num_items;
+}
+
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 			   struct btrfs_root *root, unsigned long count);
@@ -2277,6 +2291,8 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
+void btrfs_clear_path_blocking(struct btrfs_path *p,
+			       struct extent_buffer *held);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2288,6 +2304,10 @@ static inline int btrfs_del_item(struct btrfs_trans_handle *trans,
 	return btrfs_del_items(trans, root, path, path->slots[0], 1);
 }
 
+int setup_items_for_insert(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct btrfs_path *path,
+			   struct btrfs_key *cpu_key, u32 *data_size,
+			   u32 total_data, u32 total_size, int nr);
 int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, void *data, u32 data_size);
 int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
@@ -2349,7 +2369,7 @@ int btrfs_set_root_node(struct btrfs_root_item *item,
 /* dir-item.c */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root, const char *name,
-			  int name_len, u64 dir,
+			  int name_len, struct inode *dir,
 			  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,
fs/btrfs/delayed-inode.c new file +1665 -0

1,665 lines not on this page · raw message

fs/btrfs/delayed-inode.h new file +142 -0

142 lines not on this page · raw message

fs/btrfs/dir-item.c +10 -22
index f0cad5a..696c793 100644
@@ -124,8 +124,9 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
  * to use for the second index (if one is created).
  */
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
-			  *root, const char *name, int name_len, u64 dir,
-			  struct btrfs_key *location, u8 type, u64 index)
+			  *root, const char *name, int name_len,
+			  struct inode *dir, struct btrfs_key *location,
+			  u8 type, u64 index)
 {
 	int ret = 0;
 	int ret2 = 0;
@@ -137,13 +138,17 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	struct btrfs_disk_key disk_key;
 	u32 data_size;
 
-	key.objectid = dir;
+	key.objectid = dir->i_ino;
 	btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
 	key.offset = btrfs_name_hash(name, name_len);
 
 	path = btrfs_alloc_path();
+	if (!path)
+		return -ENOMEM;
 	path->leave_spinning = 1;
 
+	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,
 					name, name_len);
@@ -155,7 +160,6 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
 	}
 
 	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
 	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
 	btrfs_set_dir_type(leaf, dir_item, type);
 	btrfs_set_dir_data_len(leaf, dir_item, 0);
@@ -174,24 +178,8 @@ second_insert:
 	}
 	btrfs_release_path(root, path);
 
-	btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
-	key.offset = index;
-	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
-					name, name_len);
-	if (IS_ERR(dir_item)) {
-		ret2 = PTR_ERR(dir_item);
-		goto out;
-	}
-	leaf = path->nodes[0];
-	btrfs_cpu_key_to_disk(&disk_key, location);
-	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
-	btrfs_set_dir_type(leaf, dir_item, type);
-	btrfs_set_dir_data_len(leaf, dir_item, 0);
-	btrfs_set_dir_name_len(leaf, dir_item, name_len);
-	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
-	name_ptr = (unsigned long)(dir_item + 1);
-	write_extent_buffer(leaf, name, name_ptr, name_len);
-	btrfs_mark_buffer_dirty(leaf);
+	ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir,
+					      &disk_key, type, index);
 out:
 	btrfs_free_path(path);
 	if (ret)
fs/btrfs/disk-io.c +44 -5

121 lines not on this page · raw message

fs/btrfs/disk-io.h +1 -0
index 07b20dc..aca35af 100644
@@ -71,6 +71,7 @@ int btrfs_insert_dev_radix(struct btrfs_root *root,
 			   u64 block_start,
 			   u64 num_blocks);
 void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
 int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 void btrfs_mark_buffer_dirty_nonblocking(struct extent_buffer *buf);
fs/btrfs/extent-tree.c +6 -12
index 100e409..aed763f 100644
@@ -3897,12 +3897,6 @@ static void release_global_block_rsv(struct btrfs_fs_info *fs_info)
 	WARN_ON(fs_info->chunk_block_rsv.reserved > 0);
 }
 
-static u64 calc_trans_metadata_size(struct btrfs_root *root, int num_items)
-{
-	return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
-		3 * num_items;
-}
-
 int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root,
 				 int num_items)
@@ -3913,7 +3907,7 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
 	if (num_items == 0 || root->fs_info->chunk_root == root)
 		return 0;
 
-	num_bytes = calc_trans_metadata_size(root, num_items);
+	num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
 	ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
 				  num_bytes);
 	if (!ret) {
@@ -3952,14 +3946,14 @@ int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * If all of the metadata space is used, we can commit
 	 * transaction and use space it freed.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
 void btrfs_orphan_release_metadata(struct inode *inode)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
-	u64 num_bytes = calc_trans_metadata_size(root, 4);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 4);
 	btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
 }
 
@@ -3973,7 +3967,7 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
 	 * two for root back/forward refs, two for directory entries
 	 * and one for root of the snapshot.
 	 */
-	u64 num_bytes = calc_trans_metadata_size(root, 5);
+	u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
 	dst_rsv->space_info = src_rsv->space_info;
 	return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
@@ -4000,7 +3994,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 	nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
 	if (nr_extents > BTRFS_I(inode)->reserved_extents) {
 		nr_extents -= BTRFS_I(inode)->reserved_extents;
-		to_reserve = calc_trans_metadata_size(root, nr_extents);
+		to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
 	} else {
 		nr_extents = 0;
 		to_reserve = 0;
@@ -4047,7 +4041,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
 	to_free = calc_csum_metadata_size(inode, num_bytes);
 	if (nr_extents > 0)
-		to_free += calc_trans_metadata_size(root, nr_extents);
+		to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
 
 	btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
 				to_free);
fs/btrfs/inode.c +82 -31

248 lines not on this page · raw message

fs/btrfs/ioctl.c +1 -1
index 5fdb2ab..b200e07 100644
@@ -333,7 +333,7 @@ static noinline int create_subvol(struct btrfs_root *root,
 	BUG_ON(ret);
 
 	ret = btrfs_insert_dir_item(trans, root,
-				    name, namelen, dir->i_ino, &key,
+				    name, namelen, dir, &key,
 				    BTRFS_FT_DIR, index);
 	if (ret)
 		goto fail;
fs/btrfs/super.c +9 -1
index db0a827..593ce8a 100644
@@ -40,6 +40,7 @@
 #include <linux/magic.h>
 #include <linux/slab.h>
 #include "compat.h"
+#include "delayed-inode.h"
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
@@ -1163,10 +1164,14 @@ static int __init init_btrfs_fs(void)
 	if (err)
 		goto free_extent_io;
 
-	err = btrfs_interface_init();
+	err = btrfs_delayed_inode_init();
 	if (err)
 		goto free_extent_map;
 
+	err = btrfs_interface_init();
+	if (err)
+		goto free_delayed_inode;
+
 	err = register_filesystem(&btrfs_fs_type);
 	if (err)
 		goto unregister_ioctl;
@@ -1176,6 +1181,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
 	btrfs_interface_exit();
+free_delayed_inode:
+	btrfs_delayed_inode_exit();
 free_extent_map:
 	extent_map_exit();
 free_extent_io:
@@ -1192,6 +1199,7 @@ free_sysfs:
 static void __exit exit_btrfs_fs(void)
 {
 	btrfs_destroy_cachep();
+	btrfs_delayed_inode_exit();
 	extent_map_exit();
 	extent_io_exit();
 	btrfs_interface_exit();
fs/btrfs/transaction.c +39 -4

83 lines not on this page · raw message

fs/btrfs/transaction.h +2 -0
index 229a594..a4a441f 100644
@@ -115,6 +115,8 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
 				   int wait_for_unblock);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
 				   struct btrfs_root *root);
+int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
+				struct btrfs_root *root);
 int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
 				 struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
fs/btrfs/tree-log.c +7 -0
index a4bbb85..e8a2e95 100644
@@ -2775,6 +2775,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 		max_key.type = (u8)-1;
 	max_key.offset = (u64)-1;
 
+	ret = btrfs_commit_inode_delayed_items(trans, root, inode);
+	if (ret) {
+		btrfs_free_path(path);
+		btrfs_free_path(dst_path);
+		return ret;
+	}
+
 	mutex_lock(&BTRFS_I(inode)->log_mutex);
 
 	/*
Signature · 1 line
1.7.3.1
#12 lore raw

Hi Miao,

The possible circular locking dependency message doesn't show up in the updated V5. However, I see a new possible irq lock inversion dependency message while running xfstests.

=========================================================
[ INFO: possible irq lock inversion dependency detected ] 2.6.36-xie+ #122
---------------------------------------------------------
kswapd0/49 just changed the state of lock:
(iprune_sem){++++.-}, at: [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
but this lock took another, RECLAIM_FS-unsafe lock in the past:
(&delayed_node->mutex){+.+.+.}

and interrupts could create inverse lock ordering between them.

other info that might help us debug this:
1 lock held by kswapd0/49:
#0: (shrinker_rwsem){++++..}, at: [<ffffffff810e242a>] shrink_slab+0x3d/0x164

the shortest dependencies between 2nd lock and 1st lock:

 -> (&delayed_node->mutex){+.+.+.} ops: 1703807 {
    HARDIRQ-ON-W at:
                          [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
                          [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                          [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                          [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                          [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                          [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                          [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                          [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                          [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                          [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                          [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                          [<ffffffff81127a77>] do_last+0x579/0x57e
                          [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                          [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                          [<ffffffff8111af8f>] sys_open+0x20/0x22
                          [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    SOFTIRQ-ON-W at:
                          [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                          [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                          [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                          [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                          [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                          [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                          [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                          [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                          [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                          [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                          [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                          [<ffffffff81127a77>] do_last+0x579/0x57e
                          [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                          [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                          [<ffffffff8111af8f>] sys_open+0x20/0x22
                          [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    RECLAIM_FS-ON-W at:
                             [<ffffffff81074292>] mark_held_locks+0x52/0x70
                             [<ffffffff81074354>] lockdep_trace_alloc+0xa4/0xc2
                             [<ffffffff8110f206>] __kmalloc+0x7f/0x154
                             [<ffffffff811c2c21>] kzalloc+0x14/0x16
                             [<ffffffff811c5e83>] cache_block_group+0x106/0x238
                             [<ffffffff811c7069>] find_free_extent+0x4e2/0xa86
                             [<ffffffff811c76c1>] btrfs_reserve_extent+0xb4/0x142
                             [<ffffffff811c78b6>] btrfs_alloc_free_block+0x167/0x2af
                             [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
                             [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
                             [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
                             [<ffffffff811cf5ab>] btrfs_lookup_inode+0x2f/0x8f
                             [<ffffffff81212405>] btrfs_update_delayed_inode+0x75/0x135
                             [<ffffffff8121340d>] btrfs_run_delayed_items+0xd6/0x131
                             [<ffffffff811d64d7>] btrfs_commit_transaction+0x28b/0x668
                             [<ffffffff811ba786>] btrfs_sync_fs+0x6b/0x70
                             [<ffffffff81140265>] __sync_filesystem+0x6b/0x83
                             [<ffffffff81140347>] sync_filesystem+0x4c/0x50
                             [<ffffffff8111fc56>] generic_shutdown_super+0x27/0xd7
                             [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                             [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                             [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                             [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                             [<ffffffff81136a87>] sys_umount+0x2c1/0x2ec
                             [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    INITIAL USE at:
                         [<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6
                         [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                         [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                         [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                         [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                         [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                         [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                         [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                         [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                         [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                         [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                         [<ffffffff81127a77>] do_last+0x579/0x57e
                         [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                         [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                         [<ffffffff8111af8f>] sys_open+0x20/0x22
                         [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
  }
  ... key      at: [<ffffffff82925450>] __key.31289+0x0/0x8
  ... acquired at:
   [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
   [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
   [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
   [<ffffffff81213217>] btrfs_remove_delayed_node+0x3e/0xd2
   [<ffffffff811d77ca>] btrfs_destroy_inode+0x2ae/0x2d4
   [<ffffffff81130dc1>] destroy_inode+0x2f/0x45
   [<ffffffff811312ca>] dispose_list+0xaa/0xdf
   [<ffffffff81131427>] invalidate_inodes+0x128/0x146
   [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
   [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
   [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
   [<ffffffff8111f495>] deactivate_super+0x45/0x4a
   [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
   [<ffffffff81136a87>] sys_umount+0x2c1/0x2ec
   [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

-> (iprune_sem){++++.-} ops: 69 {
HARDIRQ-ON-W at:

                        [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6a4a>] down_write+0x55/0x9b
                        [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                        [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                        [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                        [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                        [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                        [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                        [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                        [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                        [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                        [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                        [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                        [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                        [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                        [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                        [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                        [<ffffffff8113678c>] sys_mount+0x88/0xc2
                        [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
   HARDIRQ-ON-R at:
                        [<ffffffff81075e98>] __lock_acquire+0x31e/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6adc>] down_read+0x4c/0x91
                        [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                        [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                        [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                        [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                        [<ffffffff81061a60>] kthread+0x9d/0xa5
                        [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   SOFTIRQ-ON-W at:
                        [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6a4a>] down_write+0x55/0x9b
                        [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                        [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                        [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                        [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                        [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                        [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                        [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                        [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                        [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                        [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                        [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                        [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                        [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                        [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                        [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                        [<ffffffff8113678c>] sys_mount+0x88/0xc2
                        [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
   SOFTIRQ-ON-R at:
                        [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6adc>] down_read+0x4c/0x91
                        [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                        [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                        [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                        [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                        [<ffffffff81061a60>] kthread+0x9d/0xa5
                        [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   IN-RECLAIM_FS-R at:
                           [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
                           [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                           [<ffffffff814c6adc>] down_read+0x4c/0x91
                           [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                           [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                           [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                           [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                           [<ffffffff81061a60>] kthread+0x9d/0xa5
                           [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   INITIAL USE at:
                       [<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6
                       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                       [<ffffffff814c6a4a>] down_write+0x55/0x9b
                       [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                       [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                       [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                       [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                       [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                       [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                       [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                       [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                       [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                       [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                       [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                       [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                       [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                       [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                       [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                       [<ffffffff8113678c>] sys_mount+0x88/0xc2
                       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
 }
 ... key      at: [<ffffffff81a4d268>] iprune_sem+0x58/0xb0
 ... acquired at:
   [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
   [<ffffffff81074113>] mark_lock+0x13d/0x26a
   [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
   [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
   [<ffffffff814c6adc>] down_read+0x4c/0x91
   [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
   [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
   [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
   [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
   [<ffffffff81061a60>] kthread+0x9d/0xa5
   [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10


stack backtrace:
Pid: 49, comm: kswapd0 Not tainted 2.6.36-xie+ #122
Call Trace:
 [<ffffffff8107493d>] print_irq_inversion_bug+0x124/0x135
 [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
 [<ffffffff8107494e>] ? check_usage_forwards+0x0/0x7e
 [<ffffffff81074113>] mark_lock+0x13d/0x26a
 [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
 [<ffffffff81074003>] ? mark_lock+0x2d/0x26a
 [<ffffffff81076911>] ? __lock_acquire+0xd97/0xda6
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff810dcdfb>] ? global_dirty_limits+0x17/0xca
 [<ffffffff814c6adc>] down_read+0x4c/0x91
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
 [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
 [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
 [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
 [<ffffffff81062032>] ? autoremove_wake_function+0x0/0x39
 [<ffffffff810e483c>] ? kswapd+0x0/0x3c0
 [<ffffffff81061a60>] kthread+0x9d/0xa5
 [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
 [<ffffffff81038cd9>] ? finish_task_switch+0x70/0xb9
 [<ffffffff814c88c0>] ? restore_args+0x0/0x30
 [<ffffffff810619c3>] ? kthread+0x0/0xa5
 [<ffffffff81003c10>] ? kernel_thread_helper+0x0/0x10
author
#13 lore raw
Quoted 4 lines · Itaru Kitayama

Hi Miao,

The possible circular locking dependency message doesn't show up in the updated V5. However, I see a new possible irq lock inversion dependency message while running xfstests.

I is testing the new version, in which I fixed the slab shrinker problem reported by Chris. In the new version, the delayed node is removed before the relative inode is moved into the unused_inode list(the slab shrinker will reclaim inodes in this list). Maybe this method can also fix this bug. So could you tell me the reproduce step or the options of mkfs and mount? I will check if the new patch can fix this bug or not.

Thanks
Miao

Quoted 259 lines

=========================================================
[ INFO: possible irq lock inversion dependency detected ] 2.6.36-xie+ #122
---------------------------------------------------------
kswapd0/49 just changed the state of lock:
(iprune_sem){++++.-}, at: [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
but this lock took another, RECLAIM_FS-unsafe lock in the past:
(&delayed_node->mutex){+.+.+.}

and interrupts could create inverse lock ordering between them.

other info that might help us debug this:
1 lock held by kswapd0/49:
#0: (shrinker_rwsem){++++..}, at: [<ffffffff810e242a>] shrink_slab+0x3d/0x164

the shortest dependencies between 2nd lock and 1st lock:

 -> (&delayed_node->mutex){+.+.+.} ops: 1703807 {
    HARDIRQ-ON-W at:
                          [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
                          [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                          [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                          [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                          [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                          [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                          [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                          [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                          [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                          [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                          [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                          [<ffffffff81127a77>] do_last+0x579/0x57e
                          [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                          [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                          [<ffffffff8111af8f>] sys_open+0x20/0x22
                          [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    SOFTIRQ-ON-W at:
                          [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                          [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                          [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                          [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                          [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                          [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                          [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                          [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                          [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                          [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                          [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                          [<ffffffff81127a77>] do_last+0x579/0x57e
                          [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                          [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                          [<ffffffff8111af8f>] sys_open+0x20/0x22
                          [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    RECLAIM_FS-ON-W at:
                             [<ffffffff81074292>] mark_held_locks+0x52/0x70
                             [<ffffffff81074354>] lockdep_trace_alloc+0xa4/0xc2
                             [<ffffffff8110f206>] __kmalloc+0x7f/0x154
                             [<ffffffff811c2c21>] kzalloc+0x14/0x16
                             [<ffffffff811c5e83>] cache_block_group+0x106/0x238
                             [<ffffffff811c7069>] find_free_extent+0x4e2/0xa86
                             [<ffffffff811c76c1>] btrfs_reserve_extent+0xb4/0x142
                             [<ffffffff811c78b6>] btrfs_alloc_free_block+0x167/0x2af
                             [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
                             [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
                             [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
                             [<ffffffff811cf5ab>] btrfs_lookup_inode+0x2f/0x8f
                             [<ffffffff81212405>] btrfs_update_delayed_inode+0x75/0x135
                             [<ffffffff8121340d>] btrfs_run_delayed_items+0xd6/0x131
                             [<ffffffff811d64d7>] btrfs_commit_transaction+0x28b/0x668
                             [<ffffffff811ba786>] btrfs_sync_fs+0x6b/0x70
                             [<ffffffff81140265>] __sync_filesystem+0x6b/0x83
                             [<ffffffff81140347>] sync_filesystem+0x4c/0x50
                             [<ffffffff8111fc56>] generic_shutdown_super+0x27/0xd7
                             [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                             [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                             [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                             [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                             [<ffffffff81136a87>] sys_umount+0x2c1/0x2ec
                             [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
    INITIAL USE at:
                         [<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6
                         [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                         [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
                         [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
                         [<ffffffff81211fd4>] btrfs_delayed_update_inode+0x45/0x101
                         [<ffffffff811dc5c3>] btrfs_update_inode+0x2e/0x129
                         [<ffffffff811e0cba>] btrfs_truncate+0x43d/0x477
                         [<ffffffff810dfb22>] vmtruncate+0x44/0x52
                         [<ffffffff811e0ef6>] btrfs_setattr+0x202/0x253
                         [<ffffffff8113201e>] notify_change+0x1a2/0x29d
                         [<ffffffff8111bf08>] do_truncate+0x6c/0x89
                         [<ffffffff81127a77>] do_last+0x579/0x57e
                         [<ffffffff81129502>] do_filp_open+0x215/0x5ae
                         [<ffffffff8111aec0>] do_sys_open+0x60/0xfc
                         [<ffffffff8111af8f>] sys_open+0x20/0x22
                         [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
  }
  ... key      at: [<ffffffff82925450>] __key.31289+0x0/0x8
  ... acquired at:
   [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
   [<ffffffff814c62b1>] __mutex_lock_common+0x5a/0x444
   [<ffffffff814c6750>] mutex_lock_nested+0x39/0x3e
   [<ffffffff81213217>] btrfs_remove_delayed_node+0x3e/0xd2
   [<ffffffff811d77ca>] btrfs_destroy_inode+0x2ae/0x2d4
   [<ffffffff81130dc1>] destroy_inode+0x2f/0x45
   [<ffffffff811312ca>] dispose_list+0xaa/0xdf
   [<ffffffff81131427>] invalidate_inodes+0x128/0x146
   [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
   [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
   [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
   [<ffffffff8111f495>] deactivate_super+0x45/0x4a
   [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
   [<ffffffff81136a87>] sys_umount+0x2c1/0x2ec
   [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
-> (iprune_sem){++++.-} ops: 69 {
   HARDIRQ-ON-W at:
                        [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6a4a>] down_write+0x55/0x9b
                        [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                        [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                        [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                        [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                        [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                        [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                        [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                        [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                        [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                        [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                        [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                        [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                        [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                        [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                        [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                        [<ffffffff8113678c>] sys_mount+0x88/0xc2
                        [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
   HARDIRQ-ON-R at:
                        [<ffffffff81075e98>] __lock_acquire+0x31e/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6adc>] down_read+0x4c/0x91
                        [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                        [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                        [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                        [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                        [<ffffffff81061a60>] kthread+0x9d/0xa5
                        [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   SOFTIRQ-ON-W at:
                        [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6a4a>] down_write+0x55/0x9b
                        [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                        [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                        [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                        [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                        [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                        [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                        [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                        [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                        [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                        [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                        [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                        [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                        [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                        [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                        [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                        [<ffffffff8113678c>] sys_mount+0x88/0xc2
                        [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
   SOFTIRQ-ON-R at:
                        [<ffffffff81075ee1>] __lock_acquire+0x367/0xda6
                        [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                        [<ffffffff814c6adc>] down_read+0x4c/0x91
                        [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                        [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                        [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                        [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                        [<ffffffff81061a60>] kthread+0x9d/0xa5
                        [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   IN-RECLAIM_FS-R at:
                           [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
                           [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                           [<ffffffff814c6adc>] down_read+0x4c/0x91
                           [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
                           [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
                           [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
                           [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
                           [<ffffffff81061a60>] kthread+0x9d/0xa5
                           [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
   INITIAL USE at:
                       [<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6
                       [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
                       [<ffffffff814c6a4a>] down_write+0x55/0x9b
                       [<ffffffff8113133d>] invalidate_inodes+0x3e/0x146
                       [<ffffffff8111fc76>] generic_shutdown_super+0x47/0xd7
                       [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                       [<ffffffffa034d679>] nfs4_kill_super+0x44/0x77 [nfs]
                       [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                       [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                       [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                       [<ffffffff81135b40>] release_mounts+0x8e/0xa4
                       [<ffffffff81135bb7>] put_mnt_ns+0x61/0x72
                       [<ffffffffa034d3da>] nfs_follow_remote_path+0x207/0x302 [nfs]
                       [<ffffffffa034d5fb>] nfs4_try_mount+0x7a/0xb4 [nfs]
                       [<ffffffffa034e8a3>] nfs_get_sb+0x4cf/0x750 [nfs]
                       [<ffffffff8111f25e>] vfs_kern_mount+0xbd/0x1a7
                       [<ffffffff8111f3b0>] do_kern_mount+0x4d/0xed
                       [<ffffffff8113668d>] do_mount+0x74e/0x7c5
                       [<ffffffff8113678c>] sys_mount+0x88/0xc2
                       [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b
 }
 ... key      at: [<ffffffff81a4d268>] iprune_sem+0x58/0xb0
 ... acquired at:
   [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
   [<ffffffff81074113>] mark_lock+0x13d/0x26a
   [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
   [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
   [<ffffffff814c6adc>] down_read+0x4c/0x91
   [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
   [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
   [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
   [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
   [<ffffffff81061a60>] kthread+0x9d/0xa5
   [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10


stack backtrace:
Pid: 49, comm: kswapd0 Not tainted 2.6.36-xie+ #122
Call Trace:
 [<ffffffff8107493d>] print_irq_inversion_bug+0x124/0x135
 [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
 [<ffffffff8107494e>] ? check_usage_forwards+0x0/0x7e
 [<ffffffff81074113>] mark_lock+0x13d/0x26a
 [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
 [<ffffffff81074003>] ? mark_lock+0x2d/0x26a
 [<ffffffff81076911>] ? __lock_acquire+0xd97/0xda6
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff810dcdfb>] ? global_dirty_limits+0x17/0xca
 [<ffffffff814c6adc>] down_read+0x4c/0x91
 [<ffffffff811316d0>] ? shrink_icache_memory+0x4d/0x213
 [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
 [<ffffffff810e24cd>] shrink_slab+0xe0/0x164
 [<ffffffff810e4619>] balance_pgdat+0x2e8/0x50b
 [<ffffffff810e4bbc>] kswapd+0x380/0x3c0
 [<ffffffff81062032>] ? autoremove_wake_function+0x0/0x39
 [<ffffffff810e483c>] ? kswapd+0x0/0x3c0
 [<ffffffff81061a60>] kthread+0x9d/0xa5
 [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10
 [<ffffffff81038cd9>] ? finish_task_switch+0x70/0xb9
 [<ffffffff814c88c0>] ? restore_args+0x0/0x30
 [<ffffffff810619c3>] ? kthread+0x0/0xa5
 [<ffffffff81003c10>] ? kernel_thread_helper+0x0/0x10

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#14 lore raw
Quoted 5 lines · On Wed, 23 Mar 2011 12:00:38 +0800 Miao Xie <[email protected]> wrote:

I is testing the new version, in which I fixed the slab shrinker problem reported by Chris. In the new version, the delayed node is removed before the relative inode is moved into the unused_inode list(the slab shrinker will reclaim inodes in this list). Maybe this method can also fix this bug. So could you tell me the reproduce step or the options of mkfs and mount? I will check if the new patch can fix this bug or not.

I used the default mkfs options for $TEST_DEV and enabled the space_cache and the compress=lzo options upon mounting the partition.

itaru

author
#15 lore raw

Hi, Kitayama-san

Quoted 11 lines · Itaru Kitayama
Quoted 5 lines · On Wed, 23 Mar 2011 12:00:38 +0800 Miao Xie <[email protected]> wrote:

I is testing the new version, in which I fixed the slab shrinker problem reported by Chris. In the new version, the delayed node is removed before the relative inode is moved into the unused_inode list(the slab shrinker will reclaim inodes in this list). Maybe this method can also fix this bug. So could you tell me the reproduce step or the options of mkfs and mount? I will check if the new patch can fix this bug or not.

I used the default mkfs options for $TEST_DEV and enabled the space_cache and the compress=lzo options upon mounting the partition.

Unfortunately, I can trigger this warning, but by analyzing the following information,

Quoted 10 lines

=========================================================
[ INFO: possible irq lock inversion dependency detected ] 2.6.36-xie+ #122
---------------------------------------------------------
kswapd0/49 just changed the state of lock:
(iprune_sem){++++.-}, at: [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
but this lock took another, RECLAIM_FS-unsafe lock in the past:
(&delayed_node->mutex){+.+.+.}

and interrupts could create inverse lock ordering between them.

[SNIP]

Quoted 18 lines
    RECLAIM_FS-ON-W at:
                             [<ffffffff81074292>] mark_held_locks+0x52/0x70
                             [<ffffffff81074354>] lockdep_trace_alloc+0xa4/0xc2
                             [<ffffffff8110f206>] __kmalloc+0x7f/0x154
                             [<ffffffff811c2c21>] kzalloc+0x14/0x16
                             [<ffffffff811c5e83>] cache_block_group+0x106/0x238
                             [<ffffffff811c7069>] find_free_extent+0x4e2/0xa86
                             [<ffffffff811c76c1>] btrfs_reserve_extent+0xb4/0x142
                             [<ffffffff811c78b6>] btrfs_alloc_free_block+0x167/0x2af
                             [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
                             [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
                             [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
                             [<ffffffff811cf5ab>] btrfs_lookup_inode+0x2f/0x8f
                             [<ffffffff81212405>] btrfs_update_delayed_inode+0x75/0x135
                             [<ffffffff8121340d>] btrfs_run_delayed_items+0xd6/0x131
                             [<ffffffff811d64d7>] btrfs_commit_transaction+0x28b/0x668
                             [<ffffffff811ba786>] btrfs_sync_fs+0x6b/0x70
                             [<ffffffff81140265>] __sync_filesystem+0x6b/0x83
Quoted 8 lines
                             [<ffffffff81140347>] sync_filesystem+0x4c/0x50
                             [<ffffffff8111fc56>] generic_shutdown_super+0x27/0xd7
                             [<ffffffff8111fd5b>] kill_anon_super+0x16/0x54
                             [<ffffffff8111effd>] deactivate_locked_super+0x26/0x46
                             [<ffffffff8111f495>] deactivate_super+0x45/0x4a
                             [<ffffffff81135962>] mntput_no_expire+0xd6/0x104
                             [<ffffffff81136a87>] sys_umount+0x2c1/0x2ec
                             [<ffffffff81002ddb>] system_call_fastpath+0x16/0x1b

we found GFP_KERNEL was passed into kzalloc(), I think this flag trigger the above lockdep warning. the attached patch, which against the delayed items operation patch, may fix this problem, Could you test it for me?

Thanks
Miao

Quoted 1 line

From f84daee1d2060beae945a2774cda7af2ef7f3e61 Mon Sep 17 00:00:00 2001

From: Miao Xie <[email protected]>
Date: Wed, 23 Mar 2011 16:01:16 +0800
Subject: [PATCH] btrfs: use GFP_NOFS instead of GFP_KERNEL

In the filesystem context, we must allocate memory by GFP_NOFS, or we will start another filesystem operation and trigger lockdep warnning.

---
 fs/btrfs/extent-tree.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
fs/btrfs/extent-tree.c +1 -1
index f1db57d..fe50cff 100644
@@ -471,7 +471,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
 	if (load_cache_only)
 		return 0;
 
-	caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_KERNEL);
+	caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
 	BUG_ON(!caching_ctl);
 
 	INIT_LIST_HEAD(&caching_ctl->list);
Signature · 1 line
1.7.3.1
#16 lore raw
Quoted 3 lines · On Wed, 23 Mar 2011 17:47:01 +0800 Miao Xie <[email protected]> wrote:

we found GFP_KERNEL was passed into kzalloc(), I think this flag trigger the above lockdep warning. the attached patch, which against the delayed items operation patch, may fix this problem, Could you test it for me?

The possible irq lock inversion dependency warning seems to go away.

itaru