btrfs: implement delayed inode items operation
PATCH v5 2/2 btrfs: implement delayed inode items operation
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
Many thanks to Kitayama, Itoh, Sterba and Chris!
--- 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 | 114 +++- 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, 2041 insertions(+), 89 deletions(-) create mode 100644 fs/btrfs/delayed-inode.c create mode 100644 fs/btrfs/delayed-inode.h
fs/btrfs/Makefile +1 -1
@@ -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
@@ -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
@@ -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
@@ -868,6 +868,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 ];
@@ -894,7 +895,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;
@@ -1021,6 +1025,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;
@@ -1078,6 +1083,8 @@ struct btrfs_fs_info {/* filesystem state */ u64 fs_state; + +struct btrfs_delayed_root *delayed_root; };/*
@@ -2095,6 +2102,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);
@@ -2286,6 +2300,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,
@@ -2297,6 +2313,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,
@@ -2358,7 +2378,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
@@ -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_rootstruct 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
@@ -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
@@ -3905,12 +3905,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)
@@ -3921,7 +3915,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) {
@@ -3960,14 +3954,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); }
@@ -3981,7 +3975,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); }
@@ -4008,7 +4002,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 ;
@@ -4054,7 +4048,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 +83 -31
249 lines not on this page · raw message
fs/btrfs/ioctl.c +1 -1
@@ -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
@@ -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
@@ -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
@@ -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
Hi,
there's one thing I want to bring up. It's not related to delayed functionality itself but to git tree base of the patch.
There's a merge conflict when your patch is applied directly onto Linus' tree, and not when on Chris' one.
On Thu, Mar 24, 2011 at 07:41:31PM +0800, Miao Xie wrote:
...
fs/btrfs/inode.c void btrfs_destroy_inode(struct inode *inode) · line 6783
Quoted 12 lines
fs/btrfs/inode.c +3
-0@@ -6726,6 +6775,9 @@ void btrfs_destroy_inode(struct inode *inode)inode_tree_del (inode);btrfs_drop_extent_cache (inode,0 , (u64)-1 ,0 ); free: + ret =btrfs_remove_delayed_node (inode); +BUG_ON (ret); +kmem_cache_free (btrfs_inode_cachep,BTRFS_I (inode)); }
the call to kmem_cache_free has been replaced by
commit fa0d7e3de6d6fc5004ad9dea0dd6b286af8f03e9
Author: Nick Piggin <[email protected]> Date: Fri Jan 7 17:49:49 2011 +1100
fs: icache RCU free inodes
relevant hunk:
fs/btrfs/inode.c +8 -1
@@ -6495,6 +6495,13 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)return inode; } +static void btrfs_i_callback (struct rcu_head *head) +{ + struct inode *inode = container_of(head, struct inode, i_rcu); +INIT_LIST_HEAD (&inode->i_dentry); +kmem_cache_free (btrfs_inode_cachep,BTRFS_I (inode)); +} +void btrfs_destroy_inode (struct inode *inode) {struct btrfs_ordered_extent *ordered;
@@ -6564,7 +6571,7 @@ void btrfs_destroy_inode(struct inode *inode)inode_tree_del (inode);btrfs_drop_extent_cache (inode,0 , (u64)-1 ,0 ); free: -kmem_cache_free (btrfs_inode_cachep,BTRFS_I (inode)); +call_rcu (&inode->i_rcu, btrfs_i_callback); }
I don't think this disqualifies all the testing already done but maybe it's time to rebase btrfs-unstable.git to .38 .
Chris?
dave
Excerpts from Miao Xie's message of 2011-03-24 07:41:31 -0400:
Quoted 6 lines
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 betweenreaddir()and memory fault, which is reported by Itaru Kitayama.
This does do much better than v4, but I'm still hitting oom with stress.sh -n 50. I tried a bunch of variations but haven't been able to get it quite right. I think I need to hold off on this one and get the 2.6.39 pull request out.
I'll setup a .40 tree that has this in it and we can fix the ooms. This is a great base for the work, and I'd like to add more items to the delay, especially the initial inode insertions.
-chris
Hi Miao,
Chris' stress test, stress.sh -n 50 -c /mnt/linux-2.6 /mnt gave me another lockdep splat (see below). I applied your V5 patches on top of the next-rc branch.
I haven't triggered it in my actual testing, but do you think we can iterate a list of block groups in an lockless manner using rcu?
fs/btrfs/ctree.h +1 -0
@@ -740,6 +740,7 @@ struct btrfs_space_info {struct list_head block_groups[BTRFS_NR_RAID_TYPES ];spinlock_t lock;struct rw_semaphore groups_sem; +struct srcu_struct groups_srcu;atomic_t caching_threads; };
fs/btrfs/extent-tree.c +8 -6
@@ -3003,6 +3003,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,for (i =0 ; i <BTRFS_NR_RAID_TYPES ; i++)INIT_LIST_HEAD (&found->block_groups[i]);init_rwsem (&found->groups_sem); +init_srcu_struct (&found->groups_srcu);spin_lock_init (&found->lock); found->flags = flags & (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_SYSTEM |
@@ -4853,6 +4854,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, int data) {int ret =0 ; +int idx;struct btrfs_root *root = orig_root->fs_info->extent_root;struct btrfs_free_cluster *last_ptr =NULL ;struct btrfs_block_group_cache *block_group =NULL ;
@@ -4929,7 +4931,7 @@ ideal_cache:if (block_group &&block_group_bits (block_group, data) && (block_group->cached !=BTRFS_CACHE_NO || search_start == ideal_cache_offset)) { -down_read (&space_info->groups_sem); + idx =srcu_read_lock (&space_info->groups_srcu);if (list_empty (&block_group->list) || block_group->ro) {/*
@@ -4939,7 +4941,7 @@ ideal_cache:* valid */ btrfs_put_block_group (block_group); -up_read (&space_info->groups_sem); +srcu_read_unlock (&space_info->groups_srcu, idx); }else { index =get_block_group_index (block_group); goto have_block_group;
@@ -4949,8 +4951,8 @@ ideal_cache: } } search: -down_read (&space_info->groups_sem); -list_for_each_entry (block_group, &space_info->block_groups[index], + idx =srcu_read_lock (&space_info->groups_srcu); +list_for_each_entry_rcu (block_group, &space_info->block_groups[index], list) {u64 offset;int cached;
@@ -5197,8 +5199,8 @@ loop:BUG_ON (index !=get_block_group_index (block_group));btrfs_put_block_group (block_group); } -up_read (&space_info->groups_sem); - +srcu_read_unlock (&space_info->groups_srcu, idx); +if (!ins->objectid && ++index <BTRFS_NR_RAID_TYPES ) goto search;
=========================================================
[ INFO: possible irq lock inversion dependency detected ]
2.6.36-v5+ #2
---------------------------------------------------------
kswapd0/49 just changed the state of lock:
(&delayed_node->mutex){+.+.-.}, at: [<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2
but this lock took another, RECLAIM_FS-READ-unsafe lock in the past:
(&found->groups_sem){++++.+}
and interrupts could create inverse lock ordering between them.
other info that might help us debug this:
2 locks held by kswapd0/49:
#0: (shrinker_rwsem){++++..}, at: [<ffffffff810e242a>] shrink_slab+0x3d/0x164 #1: (iprune_sem){++++.-}, at: [<ffffffff811316d0>] shrink_icache_memory+0x4d/0x213
the shortest dependencies between 2nd lock and 1st lock:
-> (&found->groups_sem){++++.+} ops: 1334 {
HARDIRQ-ON-W at:
[<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6a2a>] down_write+0x55/0x9b
[<ffffffff811c352a>] __link_block_group+0x5a/0x83
[<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c
[<ffffffff811d4921>] open_ctree+0xf78/0x14ab
[<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467
[<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
[<ffffffff814c6abc>] down_read+0x4c/0x91
[<ffffffff811cb5b2>] find_free_extent+0x3ec/0xa86
[<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142
[<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2
[<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
[<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
[<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
[<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc
[<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75
[<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152
[<ffffffff811e0dd3>] btrfs_setattr+0xff/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
[<ffffffff814c6a2a>] down_write+0x55/0x9b
[<ffffffff811c352a>] __link_block_group+0x5a/0x83
[<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c
[<ffffffff811d4921>] open_ctree+0xf78/0x14ab
[<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467
[<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
[<ffffffff814c6abc>] down_read+0x4c/0x91
[<ffffffff811cb5b2>] find_free_extent+0x3ec/0xa86
[<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142
[<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2
[<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
[<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
[<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
[<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc
[<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75
[<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152
[<ffffffff811e0dd3>] btrfs_setattr+0xff/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-R at:
[<ffffffff81074292>] mark_held_locks+0x52/0x70
[<ffffffff81074354>] lockdep_trace_alloc+0xa4/0xc2
[<ffffffff810db873>] __alloc_pages_nodemask+0x96/0x841
[<ffffffff81105bcb>] alloc_pages_current+0xa7/0xca
[<ffffffff810d4d91>] __page_cache_alloc+0x85/0x8c
[<ffffffff810ddef6>] __do_page_cache_readahead+0xb5/0x19d
[<ffffffff810ddfff>] ra_submit+0x21/0x25
[<ffffffff810de3b9>] ondemand_readahead+0x1b6/0x1c9
[<ffffffff810de4b2>] page_cache_sync_readahead+0x3d/0x3f
[<ffffffff8120798d>] load_free_space_cache+0x262/0x671
[<ffffffff811c886f>] cache_block_group+0x97/0x233
[<ffffffff811cb63f>] find_free_extent+0x479/0xa86
[<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142
[<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2
[<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
[<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
[<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
[<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc
[<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75
[<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152
[<ffffffff811e0dd3>] btrfs_setattr+0xff/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
INITIAL USE at:
[<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6a2a>] down_write+0x55/0x9b
[<ffffffff811c352a>] __link_block_group+0x5a/0x83
[<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c
[<ffffffff811d4921>] open_ctree+0xf78/0x14ab
[<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467
[<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: [<ffffffff82924fb8>] __key.40112+0x0/0x8
... acquired at:
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6abc>] down_read+0x4c/0x91
[<ffffffff811cb48a>] find_free_extent+0x2c4/0xa86
[<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142
[<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2
[<ffffffff811be610>] __btrfs_cow_block+0x103/0x346
[<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110
[<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513
[<ffffffff811cf58b>] btrfs_lookup_inode+0x2f/0x8f
[<ffffffff812123e5>] btrfs_update_delayed_inode+0x75/0x135
[<ffffffff8121306e>] btrfs_async_run_delayed_node_done+0xd5/0x194
[<ffffffff811fb48e>] worker_loop+0x198/0x4dd
[<ffffffff81061a60>] kthread+0x9d/0xa5
[<ffffffff81003c14>] kernel_thread_helper+0x4/0x10-> (&delayed_node->mutex){+.+.-.} ops: 8932 {
HARDIRQ-ON-W at:
[<ffffffff81075ec0>] __lock_acquire+0x346/0xda6
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101
[<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129
[<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477
[<ffffffff810dfb22>] vmtruncate+0x44/0x52
[<ffffffff811e0ed6>] 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
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101
[<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129
[<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477
[<ffffffff810dfb22>] vmtruncate+0x44/0x52
[<ffffffff811e0ed6>] 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
IN-RECLAIM_FS-W at:
[<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4
[<ffffffff81130dc1>] destroy_inode+0x2f/0x45
[<ffffffff811312ca>] dispose_list+0xaa/0xdf
[<ffffffff81131866>] shrink_icache_memory+0x1e3/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
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101
[<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129
[<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477
[<ffffffff810dfb22>] vmtruncate+0x44/0x52
[<ffffffff811e0ed6>] 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:
[<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
[<ffffffff81074162>] mark_lock+0x18c/0x26a
[<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4
[<ffffffff81130dc1>] destroy_inode+0x2f/0x45
[<ffffffff811312ca>] dispose_list+0xaa/0xdf
[<ffffffff81131866>] shrink_icache_memory+0x1e3/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-v5+ #2
Call Trace:
[<ffffffff8107493d>] print_irq_inversion_bug+0x124/0x135
[<ffffffff810749bf>] check_usage_forwards+0x71/0x7e
[<ffffffff8107494e>] ? check_usage_forwards+0x0/0x7e
[<ffffffff81074162>] mark_lock+0x18c/0x26a
[<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6
[<ffffffff81076911>] ? __lock_acquire+0xd97/0xda6
[<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff81076a3d>] lock_acquire+0x11d/0x143
[<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444
[<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff81074604>] ? trace_hardirqs_on+0xd/0xf
[<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e
[<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2
[<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4
[<ffffffff81130dc1>] destroy_inode+0x2f/0x45
[<ffffffff811312ca>] dispose_list+0xaa/0xdf
[<ffffffff81131866>] shrink_icache_memory+0x1e3/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
[<ffffffff814c8880>] ? restore_args+0x0/0x30
[<ffffffff810619c3>] ? kthread+0x0/0xa5
[<ffffffff81003c10>] ? kernel_thread_helper+0x0/0x10Quoted 2 lines · Itaru Kitayama
Chris' stress test,
stress.sh-n 50 -c/mnt/linux-2.6/mnt gave me another lockdep splat (see below). I applied your V5 patches on top of the next-rc branch.
I got it. It is because the allocation flag of the metadata's page cache, which is stored in the btree inode's i_mapping, was set to be GFP_HIGHUSER_MOVABLE. So if we allocate pages for btree's page cache, this lockdep warning will be triggered.
I think even without my patch, this lockdep warning can also be triggered, btrfs_evict_inode() do the similar operations like what I do in the btrfs_destroy_inode().
Task1 Kswap0 task
open()
...
btrfs_search_slot()
...
btrfs_cow_block()
...
alloc_page()
wait for reclaiming
shrink_slab()
...
shrink_icache_memory()
...
btrfs_evict_inode()
...
btrfs_search_slot()If the path is locked by task1, the deadlock happens.
So the btree's page cache is different with the file's page cache, it can not allocate pages by GFP_HIGHUSER_MOVABLE flag.
I will make a separate patch to fix it.
Quoted 2 lines
I haven't triggered it in my actual testing, but do you think we can iterate a list of block groups in an lockless manner using rcu?
May be we can use it, but AFAIK, the write-side of the sleepable RCU is quite slow. Though the operations of the block group list are few, I think we should do some test to check the performance regression.
Thanks
Miao
Quoted 348 lines
fs/btrfs/ctree.h +1
-0@@ -740,6 +740,7 @@ struct btrfs_space_info {struct list_head block_groups[BTRFS_NR_RAID_TYPES ];spinlock_t lock;struct rw_semaphore groups_sem; +struct srcu_struct groups_srcu;atomic_t caching_threads; };fs/btrfs/extent-tree.c +8
-6@@ -3003,6 +3003,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,for (i =0 ; i <BTRFS_NR_RAID_TYPES ; i++)INIT_LIST_HEAD (&found->block_groups[i]);init_rwsem (&found->groups_sem); +init_srcu_struct (&found->groups_srcu);spin_lock_init (&found->lock); found->flags = flags & (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_SYSTEM |@@ -4853,6 +4854,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, int data) {int ret =0 ; +int idx;struct btrfs_root *root = orig_root->fs_info->extent_root;struct btrfs_free_cluster *last_ptr =NULL ;struct btrfs_block_group_cache *block_group =NULL ;@@ -4929,7 +4931,7 @@ ideal_cache:if (block_group &&block_group_bits (block_group, data) && (block_group->cached !=BTRFS_CACHE_NO || search_start == ideal_cache_offset)) { -down_read (&space_info->groups_sem); + idx =srcu_read_lock (&space_info->groups_srcu);if (list_empty (&block_group->list) || block_group->ro) {/* @@ -4939,7 +4941,7 @@ ideal_cache:* valid */ btrfs_put_block_group (block_group); -up_read (&space_info->groups_sem); +srcu_read_unlock (&space_info->groups_srcu, idx); }else { index =get_block_group_index (block_group); goto have_block_group;@@ -4949,8 +4951,8 @@ ideal_cache: } } search: -down_read (&space_info->groups_sem); -list_for_each_entry (block_group, &space_info->block_groups[index], + idx =srcu_read_lock (&space_info->groups_srcu); +list_for_each_entry_rcu (block_group, &space_info->block_groups[index], list) {u64 offset;int cached;@@ -5197,8 +5199,8 @@ loop:BUG_ON (index !=get_block_group_index (block_group));btrfs_put_block_group (block_group); } -up_read (&space_info->groups_sem); - +srcu_read_unlock (&space_info->groups_srcu, idx); +if (!ins->objectid && ++index <BTRFS_NR_RAID_TYPES ) goto search;=========================================================
[ INFO: possible irq lock inversion dependency detected ]
2.6.36-v5+ #2
---------------------------------------------------------
kswapd0/49 just changed the state of lock:
(&delayed_node->mutex){+.+.-.}, at: [<ffffffff812131f7>]btrfs_remove_delayed_node+0x3e/0xd2
but this lock took another, RECLAIM_FS-READ-unsafe lock in the past:
(&found->groups_sem){++++.+}and interrupts could create inverse lock ordering between them.
other info that might help us debug this:
2 locks held by kswapd0/49:
#0: (shrinker_rwsem){++++..}, at: [<ffffffff810e242a>]shrink_slab+0x3d/0x164#1: (iprune_sem){++++.-}, at: [<ffffffff811316d0>]shrink_icache_memory+0x4d/0x213the shortest dependencies between 2nd lock and 1st lock:
-> (&found->groups_sem){++++.+} ops: 1334 { HARDIRQ-ON-W at: [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6a2a>] down_write+0x55/0x9b [<ffffffff811c352a>] __link_block_group+0x5a/0x83 [<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c [<ffffffff811d4921>] open_ctree+0xf78/0x14ab [<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467 [<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 [<ffffffff814c6abc>] down_read+0x4c/0x91 [<ffffffff811cb5b2>] find_free_extent+0x3ec/0xa86 [<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142 [<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2 [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346 [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110 [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513 [<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc [<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75 [<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152 [<ffffffff811e0dd3>] btrfs_setattr+0xff/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 [<ffffffff814c6a2a>] down_write+0x55/0x9b [<ffffffff811c352a>] __link_block_group+0x5a/0x83 [<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c [<ffffffff811d4921>] open_ctree+0xf78/0x14ab [<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467 [<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 [<ffffffff814c6abc>] down_read+0x4c/0x91 [<ffffffff811cb5b2>] find_free_extent+0x3ec/0xa86 [<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142 [<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2 [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346 [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110 [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513 [<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc [<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75 [<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152 [<ffffffff811e0dd3>] btrfs_setattr+0xff/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-R at: [<ffffffff81074292>] mark_held_locks+0x52/0x70 [<ffffffff81074354>] lockdep_trace_alloc+0xa4/0xc2 [<ffffffff810db873>] __alloc_pages_nodemask+0x96/0x841 [<ffffffff81105bcb>] alloc_pages_current+0xa7/0xca [<ffffffff810d4d91>] __page_cache_alloc+0x85/0x8c [<ffffffff810ddef6>] __do_page_cache_readahead+0xb5/0x19d [<ffffffff810ddfff>] ra_submit+0x21/0x25 [<ffffffff810de3b9>] ondemand_readahead+0x1b6/0x1c9 [<ffffffff810de4b2>] page_cache_sync_readahead+0x3d/0x3f [<ffffffff8120798d>] load_free_space_cache+0x262/0x671 [<ffffffff811c886f>] cache_block_group+0x97/0x233 [<ffffffff811cb63f>] find_free_extent+0x479/0xa86 [<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142 [<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2 [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346 [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110 [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513 [<ffffffff811c1495>] btrfs_insert_empty_items+0x6a/0xbc [<ffffffff811ffb68>] btrfs_insert_orphan_item+0x5d/0x75 [<ffffffff811df1a1>] btrfs_orphan_add+0x139/0x152 [<ffffffff811e0dd3>] btrfs_setattr+0xff/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 INITIAL USE at: [<ffffffff81075f37>] __lock_acquire+0x3bd/0xda6 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6a2a>] down_write+0x55/0x9b [<ffffffff811c352a>] __link_block_group+0x5a/0x83 [<ffffffff811ca562>] btrfs_read_block_groups+0x2fb/0x56c [<ffffffff811d4921>] open_ctree+0xf78/0x14ab [<ffffffff811bafdf>] btrfs_get_sb+0x236/0x467 [<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: [<ffffffff82924fb8>] __key.40112+0x0/0x8 ... acquired at: [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6abc>] down_read+0x4c/0x91 [<ffffffff811cb48a>] find_free_extent+0x2c4/0xa86 [<ffffffff811cbd00>] btrfs_reserve_extent+0xb4/0x142 [<ffffffff811cbef5>] btrfs_alloc_free_block+0x167/0x2b2 [<ffffffff811be610>] __btrfs_cow_block+0x103/0x346 [<ffffffff811bedb8>] btrfs_cow_block+0x101/0x110 [<ffffffff811c05d8>] btrfs_search_slot+0x143/0x513 [<ffffffff811cf58b>] btrfs_lookup_inode+0x2f/0x8f [<ffffffff812123e5>] btrfs_update_delayed_inode+0x75/0x135 [<ffffffff8121306e>] btrfs_async_run_delayed_node_done+0xd5/0x194 [<ffffffff811fb48e>] worker_loop+0x198/0x4dd [<ffffffff81061a60>] kthread+0x9d/0xa5 [<ffffffff81003c14>] kernel_thread_helper+0x4/0x10-> (&delayed_node->mutex){+.+.-.} ops: 8932 { HARDIRQ-ON-W at: [<ffffffff81075ec0>] __lock_acquire+0x346/0xda6 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101 [<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129 [<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477 [<ffffffff810dfb22>] vmtruncate+0x44/0x52 [<ffffffff811e0ed6>] 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 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101 [<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129 [<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477 [<ffffffff810dfb22>] vmtruncate+0x44/0x52 [<ffffffff811e0ed6>] 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 IN-RECLAIM_FS-W at: [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4 [<ffffffff81130dc1>] destroy_inode+0x2f/0x45 [<ffffffff811312ca>] dispose_list+0xaa/0xdf [<ffffffff81131866>] shrink_icache_memory+0x1e3/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 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff81211fb4>] btrfs_delayed_update_inode+0x45/0x101 [<ffffffff811dc5a3>] btrfs_update_inode+0x2e/0x129 [<ffffffff811e0c9a>] btrfs_truncate+0x43d/0x477 [<ffffffff810dfb22>] vmtruncate+0x44/0x52 [<ffffffff811e0ed6>] 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: [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e [<ffffffff81074162>] mark_lock+0x18c/0x26a [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4 [<ffffffff81130dc1>] destroy_inode+0x2f/0x45 [<ffffffff811312ca>] dispose_list+0xaa/0xdf [<ffffffff81131866>] shrink_icache_memory+0x1e3/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-v5+ #2 Call Trace: [<ffffffff8107493d>] print_irq_inversion_bug+0x124/0x135 [<ffffffff810749bf>] check_usage_forwards+0x71/0x7e [<ffffffff8107494e>] ? check_usage_forwards+0x0/0x7e [<ffffffff81074162>] mark_lock+0x18c/0x26a [<ffffffff81075f1f>] __lock_acquire+0x3a5/0xda6 [<ffffffff81076911>] ? __lock_acquire+0xd97/0xda6 [<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff81076a3d>] lock_acquire+0x11d/0x143 [<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff814c6291>] __mutex_lock_common+0x5a/0x444 [<ffffffff812131f7>] ? btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff81074604>] ? trace_hardirqs_on+0xd/0xf [<ffffffff814c6730>] mutex_lock_nested+0x39/0x3e [<ffffffff812131f7>] btrfs_remove_delayed_node+0x3e/0xd2 [<ffffffff811d77aa>] btrfs_destroy_inode+0x2ae/0x2d4 [<ffffffff81130dc1>] destroy_inode+0x2f/0x45 [<ffffffff811312ca>] dispose_list+0xaa/0xdf [<ffffffff81131866>] shrink_icache_memory+0x1e3/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 [<ffffffff814c8880>] ? 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
Hi Miao,
Quoted 23 lines · On Sun, 27 Mar 2011 15:00:00 +0800 Miao Xie <[email protected]> wrote:
I got it. It is because the allocation flag of the metadata's page cache, which is stored in the btree inode's
i_mapping, was set to beGFP_HIGHUSER_MOVABLE. So if we allocate pages for btree's page cache, this lockdep warning will be triggered.I think even without my patch, this lockdep warning can also be triggered,
btrfs_evict_inode()do the similar operations like what I do in thebtrfs_destroy_inode().
Task1 Kswap0 task
open()... btrfs_search_slot() ... btrfs_cow_block() ... alloc_page() wait for reclaiming shrink_slab() ... shrink_icache_memory() ... btrfs_evict_inode() ... btrfs_search_slot()
Quoted 1 line
If the path is locked by task1, the deadlock happens.
Ok. balance_pgdat() calls shrink_slab() with GFP_KERNEL so it's still possible for the kswapd0 to call prune_icache(), no? I still see the lockdep warning even with your patch that clears __GFP_FS in open_ctree().
itaru
Quoted 28 lines · Itaru Kitayama
Hi Miao,
Quoted 23 lines · On Sun, 27 Mar 2011 15:00:00 +0800 Miao Xie <[email protected]> wrote:
I got it. It is because the allocation flag of the metadata's page cache, which is stored in the btree inode's
i_mapping, was set to beGFP_HIGHUSER_MOVABLE. So if we allocate pages for btree's page cache, this lockdep warning will be triggered.I think even without my patch, this lockdep warning can also be triggered,
btrfs_evict_inode()do the similar operations like what I do in thebtrfs_destroy_inode().
Task1 Kswap0 task
open()... btrfs_search_slot() ... btrfs_cow_block() ... alloc_page() wait for reclaiming shrink_slab() ... shrink_icache_memory() ... btrfs_evict_inode() ... btrfs_search_slot()
Quoted 5 lines
Quoted 1 line
If the path is locked by task1, the deadlock happens.
Ok.
balance_pgdat()callsshrink_slab()withGFP_KERNELso it's still possible for the kswapd0 to callprune_icache(), no? I still see the lockdep warning even with your patch that clears__GFP_FSinopen_ctree().
sorry for my mistake. The above explanation is wrong, it has no business with kswap thread. The correct explanation is
Task1
open()
...
btrfs_search_slot()
...
btrfs_cow_block() ...
alloc_page()
do_try_to_free_pages()
shrink_slab()
...
shrink_icache_memory()
...
btrfs_evict_inode()
...
btrfs_search_slot()
If the path is locked by task1, the deadlock happens.
So balance_pgdat() is impossible to trigger the lockdep. (My clearing __GFP_FS patch's changelog is also wrong.)
I see, except btree's page cache, free space cache's page cache is also special, can not use __GFP_FS flag.
Thanks
Miao
Quoted 7 lines
itaru
--
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
Excerpts from Miao Xie's message of 2011-03-27 07:44:06 -0400:
Quoted 55 lines · Itaru Kitayama
Quoted 28 lines
Hi Miao,
Quoted 23 lines · On Sun, 27 Mar 2011 15:00:00 +0800 Miao Xie <[email protected]> wrote:
I got it. It is because the allocation flag of the metadata's page cache, which is stored in the btree inode's
i_mapping, was set to beGFP_HIGHUSER_MOVABLE. So if we allocate pages for btree's page cache, this lockdep warning will be triggered.I think even without my patch, this lockdep warning can also be triggered,
btrfs_evict_inode()do the similar operations like what I do in thebtrfs_destroy_inode().
Task1 Kswap0 task
open()... btrfs_search_slot() ... btrfs_cow_block() ... alloc_page() wait for reclaiming shrink_slab() ... shrink_icache_memory() ... btrfs_evict_inode() ... btrfs_search_slot()Quoted 5 lines
Quoted 1 line
If the path is locked by task1, the deadlock happens.
Ok.
balance_pgdat()callsshrink_slab()withGFP_KERNELso it's still possible for the kswapd0 to callprune_icache(), no? I still see the lockdep warning even with your patch that clears__GFP_FSinopen_ctree().sorry for my mistake. The above explanation is wrong, it has no business with kswap thread. The correct explanation is
Task1 open() ... btrfs_search_slot() ... btrfs_cow_block() ... alloc_page() do_try_to_free_pages() shrink_slab() ... shrink_icache_memory() ... btrfs_evict_inode() ... btrfs_search_slot()
Quoted 7 lines
If the path is locked by task1, the deadlock happens.
So
balance_pgdat()is impossible to trigger the lockdep. (My clearing__GFP_FSpatch's changelog is also wrong.)I see, except btree's page cache, free space cache's page cache is also special, can not use
__GFP_FSflag.
Ok, I've got your first patch already, I'll add a hunk for the free space cache too. Most of the allocations we're doing are explicitly with GFP_NOFS, so it is just supporting allocations and readahead that should be causing trouble.
Thanks!
-chris