btrfs: implement delayed inode items operation
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
@@ -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
@@ -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
@@ -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 +21 -5
@@ -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
@@ -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
@@ -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 +45 -4
89 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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ; }
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.shscript:http://oss.oracle.com/~mason/stress.sh
I used:
stress.sh-n 50 -c <path to linux kernel git tree> /mntThe 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 thebtrfs_end_transactionvariants, which means that the FS writeback code waits forbalance_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@@ -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@@ -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@@ -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@@ -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@@ -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
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.shscript:http://oss.oracle.com/~mason/stress.sh
I used:
stress.sh-n 50 -c <path to linux kernel git tree> /mntThe 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 thebtrfs_end_transactionvariants, which means that the FS writeback code waits forbalance_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. ButOk, 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_mutexoriginally, so I didn't use any lock or other method to protectdelayed_nodeof the inodes.But I think we needn't use rcu lock to protect
delayed_nodewhen we want to get the delayed node, because we won't change it after it is created,cmpxchg()andACCESS_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
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 samestress.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
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 samestress.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_unusedlist, so if we free delayed nodes before moving the inode into theinode_unusedlist, we can avoid blocking the slab shrinker. Thus maybe we can fix the above problem by movingbtrfs_remove_delayed_node()frombtrfs_destroy_inode()tobtrfs_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
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/0x1bother 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.
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/0x101but task is already holding lock:
(&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>]sys_mmap_pgoff+0xd6/0x12ewhich 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/0x1bother info that might help us debug this:
1 lock held by vgs/1210:
#0: (&mm->mmap_sem){++++++}, at: [<ffffffff810f6512>]sys_mmap_pgoff+0xd6/0x12estack 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_readdirholdsi_mutex, I wonder if we can executebtrfs_readdir_delayed_dir_indexwithout 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
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
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
3be2da7ce535f87548e27721668a9dbdaf74dd46Mon 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 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 ]---
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
MiaoHere'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_spiPid: 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.htmlFrom
f97b0811b193914a90b6cc20d25492387a369464Mon 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 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/0x10Quoted 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/0x164the 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
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_inodelist(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
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_inodelist(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_cacheand 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/0x83Quoted 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/0x1bwe 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
f84daee1d2060beae945a2774cda7af2ef7f3e61Mon 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
@@ -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
Quoted 3 lines · On Wed, 23 Mar 2011 17:47:01 +0800 Miao Xie <[email protected]> wrote:
we found
GFP_KERNELwas passed intokzalloc(), 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